Change into action-service pattern
This commit is contained in:
parent
443dcdaa36
commit
e33a7b5e9c
|
|
@ -1,6 +1,6 @@
|
||||||
import { Card, Stack, Title } from "@mantine/core";
|
import { Card, Stack, Title } from "@mantine/core";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import getUsers from "@/modules/userManagement/actions/getAllUsers";
|
import getUsers from "@/modules/userManagement/services/getAllUsers";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import UsersTable from "@/modules/userManagement/tables/UsersTable/UsersTable";
|
import UsersTable from "@/modules/userManagement/tables/UsersTable/UsersTable";
|
||||||
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
|
import checkMultiplePermissions from "@/modules/auth/utils/checkMultiplePermissions";
|
||||||
|
|
@ -25,7 +25,7 @@ export default async function UsersPage() {
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={1}>Users</Title>
|
<Title order={1}>Users</Title>
|
||||||
<Card>
|
<Card>
|
||||||
<UsersTable permissions={permissions} userData={users} />
|
<UsersTable permissions={permissions} data={users} />
|
||||||
</Card>
|
</Card>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ interface DashboardErrorOptions {
|
||||||
message?: string;
|
message?: string;
|
||||||
errorCode: (typeof DashboardErrorCodes)[number] | (string & {});
|
errorCode: (typeof DashboardErrorCodes)[number] | (string & {});
|
||||||
formErrors?: Record<string, string>
|
formErrors?: Record<string, string>
|
||||||
|
statusCode?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class DashboardError extends BaseError {
|
export default class DashboardError extends BaseError {
|
||||||
|
|
@ -24,6 +25,7 @@ export default class DashboardError extends BaseError {
|
||||||
super({
|
super({
|
||||||
errorCode: options.errorCode,
|
errorCode: options.errorCode,
|
||||||
message: options.message,
|
message: options.message,
|
||||||
|
statusCode: options.statusCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.errorCode = options.errorCode;
|
this.errorCode = options.errorCode;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
import DashboardError from "../errors/DashboardError";
|
import BaseError from "@/core/error/BaseError";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throws a 'NOT_FOUND' DashboardError with a custom or default message.
|
* Throws a 'NOT_FOUND' DashboardError with a custom or default message.
|
||||||
* @param message Optional custom message for the error.
|
* @param message Optional custom message for the error.
|
||||||
*/
|
*/
|
||||||
const notFound = ({ message }: { message?: string }) => {
|
const notFound = ({ message }: { message?: string }) => {
|
||||||
throw new DashboardError({
|
throw new BaseError({
|
||||||
errorCode: "NOT_FOUND",
|
errorCode: "NOT_FOUND",
|
||||||
message:
|
message:
|
||||||
message ??
|
message ??
|
||||||
"The requested data could not be located. It may have been deleted or relocated. Please verify the information or try a different request.",
|
"The requested data could not be located. It may have been deleted or relocated. Please verify the information or try a different request.",
|
||||||
|
statusCode: 404
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
"use server";
|
|
||||||
|
|
||||||
import prisma from "@/db";
|
|
||||||
import getCurrentUser from "@/modules/auth/utils/getCurrentUser";
|
|
||||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
|
||||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
|
||||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
|
||||||
import notFound from "@/modules/dashboard/utils/notFound";
|
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
|
||||||
import { revalidatePath } from "next/cache";
|
|
||||||
import UserManagementError from "../errors/UserManagementError";
|
|
||||||
import db from "@/core/db";
|
|
||||||
|
|
||||||
export default async function deleteUser(
|
|
||||||
id: string
|
|
||||||
): Promise<ServerResponseAction> {
|
|
||||||
try {
|
|
||||||
const currentUser = await getCurrentUser();
|
|
||||||
|
|
||||||
if (!(await checkPermission("users.delete")) || !currentUser)
|
|
||||||
return unauthorized();
|
|
||||||
|
|
||||||
//prevents self delete
|
|
||||||
if (currentUser.id === id) {
|
|
||||||
throw new UserManagementError({
|
|
||||||
errorCode: "CANNOT_DELETE_SELF",
|
|
||||||
message: "You cannot delete yourself",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await db.user.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) notFound({ message: "The user does not exists" });
|
|
||||||
|
|
||||||
revalidatePath(".");
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: "The user has been deleted successfully",
|
|
||||||
};
|
|
||||||
} catch (e: unknown) {
|
|
||||||
return handleCatch(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/modules/userManagement/actions/deleteUserAction.ts
Normal file
29
src/modules/userManagement/actions/deleteUserAction.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
|
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||||
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import deleteUser from "../services/deleteUser";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
|
||||||
|
export default async function deleteUserAction(
|
||||||
|
id: string
|
||||||
|
): Promise<ServerResponseAction> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!(await checkPermission("users.delete")))
|
||||||
|
return unauthorized();
|
||||||
|
|
||||||
|
await deleteUser(id);
|
||||||
|
|
||||||
|
revalidatePath(".");
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "The user has been deleted successfully",
|
||||||
|
};
|
||||||
|
} catch (e: unknown) {
|
||||||
|
return handleCatch(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
import db from "@/core/db";
|
|
||||||
import prisma from "@/db";
|
|
||||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
|
||||||
import "server-only";
|
|
||||||
|
|
||||||
const getAllUsers = async () => {
|
|
||||||
if (!(await checkPermission("users.readAll"))) unauthorized();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const users = await db.user.findMany({
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
photoProfile: true,
|
|
||||||
name: true,
|
|
||||||
roles: {
|
|
||||||
select: {
|
|
||||||
name: true,
|
|
||||||
code: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = users.map((user) => ({
|
|
||||||
...user,
|
|
||||||
photoUrl: user.photoProfile ?? null,
|
|
||||||
photoProfile: undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getAllUsers;
|
|
||||||
24
src/modules/userManagement/actions/getAllUsersAction.ts
Normal file
24
src/modules/userManagement/actions/getAllUsersAction.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
|
import getAllUsers from "../services/getAllUsers";
|
||||||
|
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
|
|
||||||
|
export default async function getAllUsersAction(): Promise<
|
||||||
|
ServerResponseAction<Awaited<ReturnType<typeof getAllUsers>>>
|
||||||
|
> {
|
||||||
|
try {
|
||||||
|
if (!(await checkPermission("users.readAll"))) unauthorized();
|
||||||
|
|
||||||
|
const users = await getAllUsers();
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: users,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return handleCatch(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
"use server";
|
"use server";
|
||||||
import "server-only";
|
|
||||||
import prisma from "@/db";
|
|
||||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
import db from "@/core/db";
|
import getUserById from "../services/getUserById";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
|
||||||
type UserData = {
|
type UserData = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -23,35 +21,14 @@ type UserData = {
|
||||||
* @param id The unique identifier of the user.
|
* @param id The unique identifier of the user.
|
||||||
* @returns The user's detailed information or an error response.
|
* @returns The user's detailed information or an error response.
|
||||||
*/
|
*/
|
||||||
export default async function getUserDetailById(
|
export default async function getUserDetailByIdAction(
|
||||||
id: string
|
id: string
|
||||||
): Promise<ServerResponseAction<UserData>> {
|
): Promise<ServerResponseAction<UserData>> {
|
||||||
// Check user permission
|
// Check user permission
|
||||||
if (!checkPermission("users.read")) return unauthorized();
|
if (!checkPermission("users.read")) return unauthorized();
|
||||||
|
|
||||||
// Retrieve user data from the database
|
// Retrieve user data from the database
|
||||||
const user = await db.user.findFirst({
|
const user = await getUserById(id)
|
||||||
where: { id },
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
name: true,
|
|
||||||
photoProfile: true,
|
|
||||||
roles: {
|
|
||||||
select: {
|
|
||||||
code: true,
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if user exists
|
|
||||||
if (!user)
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "User not found",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// Format user data
|
// Format user data
|
||||||
const formattedUser = {
|
const formattedUser = {
|
||||||
|
|
@ -64,7 +41,6 @@ export default async function getUserDetailById(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Permission fetched successfully",
|
|
||||||
data: formattedUser,
|
data: formattedUser,
|
||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
"use server";
|
|
||||||
|
|
||||||
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
|
||||||
import prisma from "@/db";
|
|
||||||
import { revalidatePath } from "next/cache";
|
|
||||||
import userFormDataSchema, {
|
|
||||||
UserFormData,
|
|
||||||
} from "../formSchemas/userFormSchema";
|
|
||||||
import checkPermission from "@/modules/dashboard/services/checkPermission";
|
|
||||||
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
|
||||||
import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
|
||||||
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
|
||||||
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
|
||||||
import hashPassword from "@/modules/auth/utils/hashPassword";
|
|
||||||
import db from "@/core/db";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upserts a user based on the provided UserFormData.
|
|
||||||
* If the user already exists (determined by `id`), it updates the user; otherwise, it creates a new user.
|
|
||||||
* Authorization checks are performed based on whether it's a create or update operation.
|
|
||||||
*
|
|
||||||
* @param data - The data for creating or updating the user.
|
|
||||||
* @returns An object containing the success status, message, and any errors.
|
|
||||||
*/
|
|
||||||
export default async function upsertUser(
|
|
||||||
data: UserFormData
|
|
||||||
): Promise<ServerResponseAction> {
|
|
||||||
try {
|
|
||||||
const isInsert = !data.id;
|
|
||||||
|
|
||||||
// Authorization check
|
|
||||||
const permissionType = isInsert ? "users.create" : "users.update";
|
|
||||||
if (!(await checkPermission(permissionType))) {
|
|
||||||
return unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate form data
|
|
||||||
const validatedFields = userFormDataSchema.safeParse(data);
|
|
||||||
if (!validatedFields.success) {
|
|
||||||
throw new DashboardError({
|
|
||||||
errorCode: "INVALID_FORM_DATA",
|
|
||||||
formErrors: mapObjectToFirstValue(
|
|
||||||
validatedFields.error.flatten().fieldErrors
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const userData = {
|
|
||||||
id: validatedFields.data.id ? validatedFields.data.id : undefined,
|
|
||||||
name: validatedFields.data.name,
|
|
||||||
photoProfile: validatedFields.data.photoProfileUrl ?? "",
|
|
||||||
email: validatedFields.data.email,
|
|
||||||
};
|
|
||||||
|
|
||||||
const passwordHash = await hashPassword(validatedFields.data.password!);
|
|
||||||
|
|
||||||
const roles = await db.role.findMany({
|
|
||||||
where: {
|
|
||||||
code: {
|
|
||||||
in: validatedFields.data.roles,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true, // Only select the id field
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Database operation
|
|
||||||
if (isInsert) {
|
|
||||||
if (
|
|
||||||
await db.user.findFirst({
|
|
||||||
where: {
|
|
||||||
email: userData.email,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
throw new DashboardError({
|
|
||||||
errorCode: "INVALID_FORM_DATA",
|
|
||||||
formErrors: {
|
|
||||||
email: "The user is already exists",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await db.user.create({
|
|
||||||
data: {
|
|
||||||
...userData,
|
|
||||||
passwordHash,
|
|
||||||
roles: {
|
|
||||||
connect: roles.map((role) => ({ id: role.id })),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await db.user.update({
|
|
||||||
where: { id: validatedFields.data.id! },
|
|
||||||
data: {
|
|
||||||
...userData,
|
|
||||||
roles: {
|
|
||||||
set: roles.map((role) => ({ id: role.id })),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revalidate the cache
|
|
||||||
revalidatePath(".");
|
|
||||||
|
|
||||||
// Return success message
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: `User ${validatedFields.data.name} has been successfully ${
|
|
||||||
isInsert ? "created" : "updated"
|
|
||||||
}.`,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
return handleCatch(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
src/modules/userManagement/actions/upsertUserAction.ts
Normal file
46
src/modules/userManagement/actions/upsertUserAction.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { UserFormData } from "../formSchemas/userFormSchema";
|
||||||
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
|
import handleCatch from "@/modules/dashboard/utils/handleCatch";
|
||||||
|
import ServerResponseAction from "@/modules/dashboard/types/ServerResponseAction";
|
||||||
|
import checkPermission from "@/modules/auth/utils/checkPermission";
|
||||||
|
import upsertUser from "../services/upsertUser";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upserts a user based on the provided UserFormData.
|
||||||
|
* If the user already exists (determined by `id`), it updates the user; otherwise, it creates a new user.
|
||||||
|
* Authorization checks are performed based on whether it's a create or update operation.
|
||||||
|
*
|
||||||
|
* @param data - The data for creating or updating the user.
|
||||||
|
* @returns An object containing the success status, message, and any errors.
|
||||||
|
*/
|
||||||
|
export default async function upsertUserAction(
|
||||||
|
data: UserFormData
|
||||||
|
): Promise<ServerResponseAction> {
|
||||||
|
try {
|
||||||
|
const isInsert = !data.id;
|
||||||
|
|
||||||
|
// Authorization check
|
||||||
|
const permissionType = isInsert ? "users.create" : "users.update";
|
||||||
|
if (!(await checkPermission(permissionType))) {
|
||||||
|
return unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await upsertUser(data);
|
||||||
|
|
||||||
|
// Revalidate the cache
|
||||||
|
revalidatePath(".");
|
||||||
|
|
||||||
|
// Return success message
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `User ${user.name} has been successfully ${
|
||||||
|
isInsert ? "created" : "updated"
|
||||||
|
}.`,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return handleCatch(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ interface UserManagementErrorOptions {
|
||||||
message?: string;
|
message?: string;
|
||||||
errorCode: (typeof UserManagementErrorCodes)[number] | (string & {});
|
errorCode: (typeof UserManagementErrorCodes)[number] | (string & {});
|
||||||
formErrors?: Record<string, string>
|
formErrors?: Record<string, string>
|
||||||
|
statusCode?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UserManagementError extends DashboardError {
|
export default class UserManagementError extends DashboardError {
|
||||||
|
|
@ -18,6 +19,7 @@ export default class UserManagementError extends DashboardError {
|
||||||
super({
|
super({
|
||||||
errorCode: options.errorCode,
|
errorCode: options.errorCode,
|
||||||
message: options.message,
|
message: options.message,
|
||||||
|
statusCode: options.statusCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.errorCode = options.errorCode;
|
this.errorCode = options.errorCode;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { showNotification } from "@/utils/notifications";
|
import { showNotification } from "@/utils/notifications";
|
||||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||||
import deleteUser from "../actions/deleteUser";
|
import deleteUserAction from "../actions/deleteUserAction";
|
||||||
import ClientError from "@/core/error/ClientError";
|
import ClientError from "@/core/error/ClientError";
|
||||||
|
|
||||||
export interface DeleteModalProps {
|
export interface DeleteModalProps {
|
||||||
|
|
@ -38,7 +38,7 @@ export default function UserDeleteModal(props: DeleteModalProps) {
|
||||||
if (!props.data?.id) return;
|
if (!props.data?.id) return;
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
withServerAction(() => deleteUser(props.data!.id))
|
withServerAction(deleteUserAction, props.data!.id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
showNotification(
|
showNotification(
|
||||||
response.message ?? "User deleted successfully"
|
response.message ?? "User deleted successfully"
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ import { TbDeviceFloppy } from "react-icons/tb";
|
||||||
import userFormDataSchema, {
|
import userFormDataSchema, {
|
||||||
UserFormData,
|
UserFormData,
|
||||||
} from "../formSchemas/userFormSchema";
|
} from "../formSchemas/userFormSchema";
|
||||||
import getUserDetailById from "../actions/getUserDetailById";
|
import getUserDetailById from "../actions/getUserDetailByIdAction";
|
||||||
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
import withServerAction from "@/modules/dashboard/utils/withServerAction";
|
||||||
import upsertUser from "../actions/upsertUser";
|
import upsertUserAction from "../actions/upsertUserAction";
|
||||||
import ClientError from "@/core/error/ClientError";
|
import ClientError from "@/core/error/ClientError";
|
||||||
import stringToColorHex from "@/core/utils/stringToColorHex";
|
import stringToColorHex from "@/core/utils/stringToColorHex";
|
||||||
import getAllRoles from "@/modules/role/actions/getAllRoles";
|
import getAllRoles from "@/modules/role/actions/getAllRoles";
|
||||||
|
|
@ -112,7 +112,7 @@ export default function UserFormModal(props: ModalProps) {
|
||||||
|
|
||||||
const handleSubmit = (values: UserFormData) => {
|
const handleSubmit = (values: UserFormData) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
withServerAction(upsertUser, values)
|
withServerAction(upsertUserAction, values)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
showNotification(response.message!, "success");
|
showNotification(response.message!, "success");
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
|
||||||
26
src/modules/userManagement/services/deleteUser.ts
Normal file
26
src/modules/userManagement/services/deleteUser.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import getCurrentUser from "@/modules/auth/services/getCurrentUser"
|
||||||
|
import unauthorized from "@/modules/dashboard/utils/unauthorized";
|
||||||
|
import "server-only"
|
||||||
|
import UserManagementError from "../errors/UserManagementError";
|
||||||
|
import db from "@/core/db";
|
||||||
|
import notFound from "@/modules/dashboard/utils/notFound";
|
||||||
|
|
||||||
|
export default async function deleteUser(id: string){
|
||||||
|
const currentUser = await getCurrentUser();
|
||||||
|
|
||||||
|
if (!currentUser) return unauthorized();
|
||||||
|
|
||||||
|
if (currentUser.id !== id) throw new UserManagementError({
|
||||||
|
errorCode: "CANNOT_DELETE_SELF",
|
||||||
|
message: "You cannot delete yourself",
|
||||||
|
statusCode: 403,
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = await db.user.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) return notFound({message: "The user does not exists"})
|
||||||
|
|
||||||
|
return true as const;
|
||||||
|
}
|
||||||
29
src/modules/userManagement/services/getAllUsers.ts
Normal file
29
src/modules/userManagement/services/getAllUsers.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import db from "@/core/db";
|
||||||
|
import "server-only";
|
||||||
|
|
||||||
|
const getAllUsers = async () => {
|
||||||
|
const users = await db.user.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
photoProfile: true,
|
||||||
|
name: true,
|
||||||
|
roles: {
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
code: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = users.map((user) => ({
|
||||||
|
...user,
|
||||||
|
photoUrl: user.photoProfile ?? null,
|
||||||
|
photoProfile: undefined,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getAllUsers;
|
||||||
24
src/modules/userManagement/services/getUserById.ts
Normal file
24
src/modules/userManagement/services/getUserById.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import db from "@/core/db";
|
||||||
|
import notFound from "@/modules/dashboard/utils/notFound";
|
||||||
|
|
||||||
|
export default async function getUserById(id: string) {
|
||||||
|
const user = await db.user.findFirst({
|
||||||
|
where: { id },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
photoProfile: true,
|
||||||
|
roles: {
|
||||||
|
select: {
|
||||||
|
code: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) return notFound({message: "The user does not exists"})
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
80
src/modules/userManagement/services/upsertUser.ts
Normal file
80
src/modules/userManagement/services/upsertUser.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
import DashboardError from "@/modules/dashboard/errors/DashboardError";
|
||||||
|
import userFormDataSchema, {
|
||||||
|
UserFormData,
|
||||||
|
} from "../formSchemas/userFormSchema";
|
||||||
|
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
|
||||||
|
import hashPassword from "@/modules/auth/utils/hashPassword";
|
||||||
|
import db from "@/core/db";
|
||||||
|
import "server-only"
|
||||||
|
|
||||||
|
export default async function upsertUser(data: UserFormData) {
|
||||||
|
const isInsert = !data.id;
|
||||||
|
|
||||||
|
// Validate form data
|
||||||
|
const validatedFields = userFormDataSchema.safeParse(data);
|
||||||
|
if (!validatedFields.success) {
|
||||||
|
throw new DashboardError({
|
||||||
|
errorCode: "INVALID_FORM_DATA",
|
||||||
|
formErrors: mapObjectToFirstValue(
|
||||||
|
validatedFields.error.flatten().fieldErrors
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const userData = {
|
||||||
|
id: validatedFields.data.id ? validatedFields.data.id : undefined,
|
||||||
|
name: validatedFields.data.name,
|
||||||
|
photoProfile: validatedFields.data.photoProfileUrl ?? "",
|
||||||
|
email: validatedFields.data.email,
|
||||||
|
};
|
||||||
|
|
||||||
|
const passwordHash = await hashPassword(validatedFields.data.password!);
|
||||||
|
|
||||||
|
const roles = await db.role.findMany({
|
||||||
|
where: {
|
||||||
|
code: {
|
||||||
|
in: validatedFields.data.roles,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true, // Only select the id field
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Database operation
|
||||||
|
if (isInsert) {
|
||||||
|
if (
|
||||||
|
await db.user.findFirst({
|
||||||
|
where: {
|
||||||
|
email: userData.email,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
throw new DashboardError({
|
||||||
|
errorCode: "INVALID_FORM_DATA",
|
||||||
|
formErrors: {
|
||||||
|
email: "The user is already exists",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return await db.user.create({
|
||||||
|
data: {
|
||||||
|
...userData,
|
||||||
|
passwordHash,
|
||||||
|
roles: {
|
||||||
|
connect: roles.map((role) => ({ id: role.id })),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return await db.user.update({
|
||||||
|
where: { id: validatedFields.data.id! },
|
||||||
|
data: {
|
||||||
|
...userData,
|
||||||
|
roles: {
|
||||||
|
set: roles.map((role) => ({ id: role.id })),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,12 +9,12 @@ import UserDeleteModal, {
|
||||||
DeleteModalProps,
|
DeleteModalProps,
|
||||||
} from "../../modals/UserDeleteModal";
|
} from "../../modals/UserDeleteModal";
|
||||||
import createColumns from "./columns";
|
import createColumns from "./columns";
|
||||||
import getAllUsers from "../../actions/getAllUsers";
|
import getAllUsers from "../../services/getAllUsers";
|
||||||
import DashboardTable from "@/modules/dashboard/components/DashboardTable";
|
import DashboardTable from "@/modules/dashboard/components/DashboardTable";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
permissions: Partial<CrudPermissions>;
|
permissions: Partial<CrudPermissions>;
|
||||||
userData: Awaited<ReturnType<typeof getAllUsers>>;
|
data: Awaited<ReturnType<typeof getAllUsers>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function UsersTable(props: Props) {
|
export default function UsersTable(props: Props) {
|
||||||
|
|
@ -32,11 +32,11 @@ export default function UsersTable(props: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const userData = useMemo(
|
const userData = useMemo(
|
||||||
() => props.userData.map((data) => ({
|
() => props.data.map((data) => ({
|
||||||
...data,
|
...data,
|
||||||
roles: data.roles.map((x) => x.name),
|
roles: data.roles.map((x) => x.name),
|
||||||
})),
|
})),
|
||||||
[props.userData]
|
[props.data]
|
||||||
);
|
);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user