Add error handling to upsert role

This commit is contained in:
Sianida26 2024-01-28 05:14:42 +07:00
parent 2e04483343
commit bae8a2aa3e
4 changed files with 108 additions and 84 deletions

View File

@ -1,9 +1,11 @@
/* eslint-disable react-hooks/exhaustive-deps */
import DashboardError from "@/features/dashboard/errors/DashboardError";
import getRoleById from "@/features/dashboard/roles/actions/getRoleById";
import upsertRole from "@/features/dashboard/roles/actions/upsertRole";
import roleFormDataSchema, {
RoleFormData,
} from "@/features/dashboard/roles/formSchemas/RoleFormData";
import withErrorHandling from "@/features/dashboard/utils/withServerAction";
import { showNotification } from "@/utils/notifications";
import {
Flex,
@ -17,6 +19,7 @@ import {
Checkbox,
Skeleton,
Fieldset,
Alert,
} from "@mantine/core";
import { useForm, zodResolver } from "@mantine/form";
import { useRouter } from "next/navigation";
@ -41,6 +44,7 @@ export default function FormModal(props: ModalProps) {
const router = useRouter();
const [isSubmitting, setSubmitting] = useState(false);
const [isFetching, setFetching] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const form = useForm<RoleFormData>({
initialValues: {
@ -93,21 +97,29 @@ export default function FormModal(props: ModalProps) {
};
const handleSubmit = (values: RoleFormData) => {
upsertRole(values)
setSubmitting(true);
withErrorHandling(() => upsertRole(values))
.then((response) => {
if (response.success) {
showNotification(response.message, "success");
return closeModal();
} else {
form.setErrors(response.errors ?? {});
if (!response.errors) {
showNotification(response.message, "error");
}
}
showNotification(response.message!, "success");
closeModal();
})
.catch((e) => {
//TODO: Handle Error
console.log(e);
if (e instanceof DashboardError) {
if (e.errorCode === "INVALID_FORM_DATA") {
form.setErrors(e.formErrors ?? {});
} else {
setErrorMessage(`ERROR: ${e.message} (${e.errorCode})`);
}
} else if (e instanceof Error) {
setErrorMessage(`ERROR: ${e.message}`);
} else {
setErrorMessage(
`Unkown error is occured. Please contact administrator`
);
}
})
.finally(() => {
setSubmitting(false);
});
};
@ -121,6 +133,7 @@ export default function FormModal(props: ModalProps) {
>
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack mt="sm" gap="lg" px="lg">
{errorMessage && <Alert color="red">{errorMessage}</Alert>}
{/* ID */}
{form.values.id ? (
<TextInput

View File

@ -4,7 +4,7 @@ export const DashboardErrorCodes = [
"UNAUTHORIZED",
"NOT_FOUND",
"UNKNOWN_ERROR",
"INVALID_FORM_DATA"
"INVALID_FORM_DATA",
] as const;
interface ErrorOptions {
@ -14,7 +14,7 @@ interface ErrorOptions {
}
export default class DashboardError extends Error {
public readonly errorCode: string;
public readonly errorCode: typeof DashboardErrorCodes[number] | string & {};
public readonly formErrors?: {[k: string]: string}
// public readonly data: object;

View File

@ -2,39 +2,40 @@
import checkPermission from "@/features/auth/tools/checkPermission";
import roleFormDataSchema, { RoleFormData } from "../formSchemas/RoleFormData";
import { unauthorized } from "@/BaseError";
import mapObjectToFirstValue from "@/utils/mapObjectToFirstValue";
import prisma from "@/db";
import { revalidatePath } from "next/cache";
import ServerResponse from "@/types/Action";
import DashboardError, { handleCatch, unauthorized } from "../../errors/DashboardError";
/**
* Upserts a role based on the provided RoleFormData.
* If the role already exists (determined by `id`), it updates the role; otherwise, it creates a new role.
* Authorization checks are performed based on whether it's a create or update operation.
*
* @param {RoleFormData} data - The data for creating or updating the role.
* @returns {Promise<object>} An object containing the success status, message, and any errors.
* @param data - The data for creating or updating the role.
* @returns An object containing the success status, message, and any errors.
*/
export default async function upsertRole(data: RoleFormData) {
export default async function upsertRole(
data: RoleFormData
): Promise<ServerResponse> {
try {
const isInsert = !data.id;
// Authorization check
const permissionType = isInsert ? "role.create" : "role.update";
if (!await checkPermission(permissionType)) {
if (!(await checkPermission(permissionType))) {
return unauthorized();
}
// Validate form data
const validatedFields = roleFormDataSchema.safeParse(data);
if (!validatedFields.success) {
return {
success: false,
message: "Invalid Form Data",
errors: mapObjectToFirstValue(validatedFields.error.flatten().fieldErrors),
};
throw new DashboardError({
errorCode: "INVALID_FORM_DATA",
formErrors: mapObjectToFirstValue(validatedFields.error.flatten().fieldErrors)
})
}
try {
const roleData = {
code: validatedFields.data.code,
description: validatedFields.data.description,
@ -44,6 +45,18 @@ export default async function upsertRole(data: RoleFormData) {
// Database operation
if (isInsert) {
if (await prisma.role.findFirst({
where: {
code: roleData.code
}
})){
throw new DashboardError({
errorCode: "INVALID_FORM_DATA",
formErrors: {
code: "The code is already exists"
}
})
}
await prisma.role.create({ data: roleData });
} else {
await prisma.role.update({
@ -58,13 +71,11 @@ export default async function upsertRole(data: RoleFormData) {
// Return success message
return {
success: true,
message: `Role ${validatedFields.data.name} has been successfully ${isInsert ? "created" : "updated"}.`,
message: `Role ${validatedFields.data.name} has been successfully ${
isInsert ? "created" : "updated"
}.`,
};
} catch (error) {
console.error('Error updating role data', error);
return {
success: false,
message: "Error updating role data.",
};
return handleCatch(error)
}
}

View File

@ -10,8 +10,8 @@ export interface RoleFormData {
const roleFormDataSchema = z.object({
id: z.string().nullable(),
name: z.string(),
code: z.string(),
name: z.string().min(1),
code: z.string().min(1),
description: z.string(),
isActive: z.boolean(),
})