Skip to content

Commit 7fa3547

Browse files
committed
chore: refactor admin for ValidationErrorSummary
1 parent c9b833b commit 7fa3547

25 files changed

Lines changed: 970 additions & 382 deletions

File tree

bciers/apps/administration/app/components/buttons/CancelAccessRequest.tsx

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,39 @@ import { UUID } from "crypto";
66
import SimpleModal from "@bciers/components/modal/SimpleModal";
77
import cancelAccessRequest from "@/administration/app/components/userOperators/cancelAccessRequest";
88
import {
9-
ValidationItem,
109
useValidationErrors,
10+
handleApiResponse,
1111
} from "@bciers/components/validationErrors";
1212

1313
interface CancelAccessRequestProps {
1414
userOperatorId: UUID;
1515
}
1616

17-
const createErrorItem = (message: string): ValidationItem => ({
18-
key: "generic_error",
19-
error: {
20-
message,
21-
severity: "Error",
22-
},
23-
});
24-
2517
export default function CancelAccessRequest({
2618
userOperatorId,
2719
}: Readonly<CancelAccessRequestProps>) {
2820
const router = useRouter();
29-
const { setErrors, renderedErrors } =
30-
useValidationErrors<ValidationMessageKey>({
31-
config: validationUIConfig,
32-
});
3321
const [modalOpen, setModalOpen] = useState(false);
3422
const [isSubmitting, setIsSubmitting] = useState(false);
3523

24+
const { setErrors, renderedErrors } = useValidationErrors({
25+
config: {},
26+
});
27+
3628
const handleCancelAccessRequest = async () => {
3729
setIsSubmitting(true);
30+
setErrors(undefined);
3831

39-
try {
40-
const response = await cancelAccessRequest(userOperatorId);
32+
const response = await cancelAccessRequest(userOperatorId);
33+
setIsSubmitting(false);
4134

42-
if (typeof response !== "boolean" && response?.error) {
43-
setErrors([createErrorItem(response.error)]);
44-
} else {
45-
router.push("/select-operator");
46-
}
47-
} catch (err: any) {
48-
setErrors([
49-
createErrorItem(
50-
err?.message || "An unexpected error occurred. Please try again.",
51-
),
52-
]);
53-
} finally {
35+
const isSuccess = handleApiResponse(response, setErrors);
36+
if (!isSuccess) {
5437
setModalOpen(false);
55-
setIsSubmitting(false);
38+
return;
5639
}
40+
41+
router.push("/select-operator");
5742
};
5843

5944
return (
@@ -69,6 +54,7 @@ export default function CancelAccessRequest({
6954
>
7055
Are you sure you want to cancel this request?
7156
</SimpleModal>
57+
7258
<button
7359
className="button-link mt-8 text-[#D8292F]"
7460
aria-label="Cancel Access Request"

bciers/apps/administration/app/components/buttons/RequestAccessButton.tsx

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,31 @@ import { useState } from "react";
44
import Button from "@mui/material/Button";
55
import { actionHandler } from "@bciers/actions";
66
import { useRouter } from "next/navigation";
7-
import { ghgRegulatorEmail } from "@bciers/utils/src/urls";
87
import {
9-
ValidationItem,
108
useValidationErrors,
9+
handleApiResponse,
1110
} from "@bciers/components/validationErrors";
11+
import { validationUIConfig } from "@/administration/app/components/validationErrors/config";
12+
import type { ValidationKey } from "@/administration/app/components/validationErrors/types";
13+
1214
interface RequestAccessButtonProps {
1315
operatorId: number;
1416
operatorName: string;
1517
isAdminRequest?: boolean;
1618
}
1719

18-
const createErrorItem = (
19-
message: string,
20-
operatorId?: number,
21-
): ValidationItem => {
22-
const isBceidError = message.includes(
23-
"Your business BCeID does not have access to this operator.",
24-
);
25-
26-
return {
27-
key: "generic_error",
28-
error: {
29-
message,
30-
severity: "Error",
31-
context: isBceidError
32-
? {
33-
email: ghgRegulatorEmail,
34-
report_version_id: operatorId,
35-
}
36-
: undefined,
37-
},
38-
};
39-
};
40-
4120
export default function RequestAccessButton({
4221
operatorId,
4322
operatorName,
4423
isAdminRequest = false,
4524
}: Readonly<RequestAccessButtonProps>) {
4625
const router = useRouter();
47-
const { setErrors, renderedErrors } =
48-
useValidationErrors<ValidationMessageKey>({
49-
config: validationUIConfig,
50-
});
5126
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
5227

28+
const { setErrors, renderedErrors } = useValidationErrors<ValidationKey>({
29+
config: validationUIConfig,
30+
});
31+
5332
const label = isAdminRequest
5433
? "Request administrator access"
5534
: "Request access";
@@ -60,35 +39,27 @@ export default function RequestAccessButton({
6039

6140
const handleRequestAccess = async () => {
6241
setIsSubmitting(true);
42+
setErrors(undefined);
43+
44+
const response = await actionHandler(endpointUrl, "POST", "");
45+
setIsSubmitting(false);
6346

64-
try {
65-
const response = await actionHandler(endpointUrl, "POST", "");
47+
const isSuccess = handleApiResponse(response, setErrors);
48+
if (!isSuccess) return;
6649

67-
if (response?.error) {
68-
setErrors([createErrorItem(response.error, operatorId)]);
69-
} else {
70-
router.push(
71-
`/select-operator/received/request-access/${operatorId}?title=${operatorName}`,
72-
);
73-
}
74-
} catch (err: any) {
75-
setErrors([
76-
createErrorItem(
77-
err?.message || "An unexpected error occurred. Please try again.",
78-
operatorId,
79-
),
80-
]);
81-
} finally {
82-
setIsSubmitting(false);
83-
}
50+
router.push(
51+
`/select-operator/received/request-access/${operatorId}?title=${encodeURIComponent(
52+
operatorName,
53+
)}`,
54+
);
8455
};
8556

8657
return (
8758
<>
8859
<div className="min-h-6 flex justify-center w-full">{renderedErrors}</div>
8960
<Button
9061
className="my-10"
91-
sx={{ textTransform: "none" }} // to remove uppercase text
62+
sx={{ textTransform: "none" }}
9263
aria-label={label ?? "Request Access"}
9364
color="primary"
9465
variant="contained"

bciers/apps/administration/app/components/contacts/ContactForm.tsx

Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -39,38 +39,77 @@ export default function ContactForm({
3939
allowEdit,
4040
}: Readonly<Props>) {
4141
const router = useRouter();
42-
const { setErrors, renderedErrors } =
43-
useValidationErrors<ValidationMessageKey>({
44-
config: validationUIConfig,
45-
});
46-
const [formState, setFormState] = useState<ContactFormData>(formData ?? {});
47-
const [isCreatingState, setIsCreatingState] = useState(isCreating);
48-
const [key, resetKey] = useKey();
42+
const params = useParams();
4943
const role = useSessionRole();
44+
const [key, resetKey] = useKey();
45+
46+
const [formState, setFormState] = useState<ContactFormData>(
47+
formData ?? ({} as ContactFormData),
48+
);
49+
const [isCreatingState, setIsCreatingState] = useState(Boolean(isCreating));
5050
const [modalOpen, setModalOpen] = useState(false);
5151
const [isSubmitting, setIsSubmitting] = useState(false);
52-
const params = useParams();
5352

54-
const handleClickDelete = () => {
55-
setModalOpen(true);
56-
};
53+
const { setErrors, renderedErrors } = useValidationErrors({
54+
config: {},
55+
});
56+
57+
const hasPlacesAssigned = Boolean(
58+
formData.places_assigned && formData.places_assigned.length > 0,
59+
);
5760

5861
const handleArchiveContact = async () => {
5962
setIsSubmitting(true);
6063
setErrors(undefined);
64+
6165
const response = await archiveContact(params.contactId as string);
62-
if (response?.error) {
63-
handleApiResponse(response, setErrors);
66+
setIsSubmitting(false);
67+
68+
const isSuccess = handleApiResponse(response, setErrors);
69+
if (!isSuccess) {
6470
setModalOpen(false);
65-
setIsSubmitting(false);
6671
return;
6772
}
73+
6874
router.push("/contacts?from_deletion=true");
69-
return;
7075
};
7176

72-
const hasPlacesAssigned =
73-
formData.places_assigned && formData.places_assigned.length > 0;
77+
const handleSubmit = async (data: { formData?: any }) => {
78+
setErrors(undefined);
79+
const updatedFormData = { ...formState, ...data.formData };
80+
setFormState(updatedFormData);
81+
82+
const method = isCreatingState ? "POST" : "PUT";
83+
const contactId = formState.id ?? params.contactId;
84+
const endpoint = isCreatingState
85+
? "registration/contacts"
86+
: `registration/contacts/${contactId}`;
87+
const pathToRevalidate = isCreatingState
88+
? "/contacts"
89+
: `/contacts/${contactId}`;
90+
91+
const response = await actionHandler(endpoint, method, pathToRevalidate, {
92+
body: JSON.stringify(data.formData),
93+
});
94+
95+
const isSuccess = handleApiResponse(response, setErrors);
96+
if (!isSuccess) {
97+
return { error: response.error };
98+
}
99+
100+
const activeId = response.id ?? contactId;
101+
102+
if (isCreatingState) {
103+
setIsCreatingState(false);
104+
setFormState((prev) => ({ ...prev, id: activeId }));
105+
} else {
106+
resetKey();
107+
}
108+
109+
const titleQuery =
110+
`${response.first_name ?? ""} ${response.last_name ?? ""}`.trim();
111+
router.replace(`/contacts/${activeId}?contacts_title=${titleQuery}`);
112+
};
74113

75114
return (
76115
<>
@@ -88,6 +127,7 @@ export default function ContactForm({
88127
? "Before you can delete this contact, please remove them from the places they are assigned. If they are the only one assigned, you must replace them with another contact in the assigned place."
89128
: "Please confirm that you would like to delete this contact."}
90129
</SimpleModal>
130+
91131
<SingleStepTaskListForm
92132
key={key}
93133
errors={renderedErrors}
@@ -103,52 +143,9 @@ export default function ContactForm({
103143
showDeleteButton={
104144
!isCreatingState && role === FrontEndRoles.INDUSTRY_USER_ADMIN
105145
}
106-
handleDelete={handleClickDelete}
146+
handleDelete={() => setModalOpen(true)}
107147
deleteButtonText="Delete Contact"
108-
onSubmit={async (data: { formData?: any }) => {
109-
setErrors(undefined);
110-
const updatedFormData = { ...formState, ...data.formData };
111-
setFormState(updatedFormData);
112-
113-
const method = isCreatingState ? "POST" : "PUT";
114-
const endpoint = isCreatingState
115-
? "registration/contacts"
116-
: `registration/contacts/${formState.id}`;
117-
const pathToRevalidate = isCreatingState
118-
? "/contacts"
119-
: `/contacts/${formState.id}`;
120-
const body = {
121-
...data.formData,
122-
};
123-
124-
const response = await actionHandler(
125-
endpoint,
126-
method,
127-
pathToRevalidate,
128-
{
129-
body: JSON.stringify(body),
130-
},
131-
);
132-
133-
const hasErrors = handleApiResponse(response, setErrors);
134-
if (hasErrors || response.error) {
135-
return { error: response.error || "Validation error" };
136-
}
137-
138-
if (isCreatingState) {
139-
setIsCreatingState(false);
140-
setFormState((prevState) => ({
141-
...prevState,
142-
id: response.id,
143-
}));
144-
} else {
145-
resetKey();
146-
}
147-
const replaceUrl = `/contacts/${
148-
method === "POST" ? response.id : formState.id
149-
}?contacts_title=${response.first_name} ${response.last_name}`;
150-
router.replace(replaceUrl);
151-
}}
148+
onSubmit={handleSubmit}
152149
onCancel={() => router.replace("/contacts")}
153150
/>
154151
</>

0 commit comments

Comments
 (0)