amati/apps/frontend/src/modules/usersManagement/modals/UserFormModal.tsx

313 lines
7.1 KiB
TypeScript

import stringToColorHex from "@/utils/stringToColorHex";
import {
Avatar,
Button,
Center,
Flex,
Modal,
ScrollArea,
Stack,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { getRouteApi } from "@tanstack/react-router";
import { createUser, updateUser } from "../queries/userQueries";
import { TbDeviceFloppy } from "react-icons/tb";
import client from "../../../honoClient";
import { getUserByIdQueryOptions } from "../queries/userQueries";
import { useEffect } from "react";
import { notifications } from "@mantine/notifications";
import FormResponseError from "@/errors/FormResponseError";
import createInputComponents from "@/utils/createInputComponents";
/**
* Change this
*/
const routeApi = getRouteApi("/_dashboardLayout/users/");
export default function UserFormModal() {
/**
* DON'T CHANGE FOLLOWING:
*/
const queryClient = useQueryClient();
const navigate = routeApi.useNavigate();
const searchParams = routeApi.useSearch();
const dataId = searchParams.detail || searchParams.edit;
const isModalOpen = Boolean(dataId || searchParams.create);
const detailId = searchParams.detail;
const editId = searchParams.edit;
const formType = detailId ? "detail" : editId ? "ubah" : "tambah";
/**
* CHANGE FOLLOWING:
*/
const userQuery = useQuery(getUserByIdQueryOptions(dataId));
const modalTitle =
formType.charAt(0).toUpperCase() + formType.slice(1) + " Pengguna";
const form = useForm({
initialValues: {
id: "",
email: "",
name: "",
username: "",
photoProfileUrl: "",
password: "",
roles: [] as string[],
companyName: "",
position: "",
workExperience: "",
address: "",
phoneNumber: "",
},
});
useEffect(() => {
const data = userQuery.data;
if (!data) {
form.reset();
return;
}
form.setValues({
id: data.id,
email: data.email ?? "",
name: data.name,
photoProfileUrl: "",
username: data.username,
password: "",
roles: data.roles.map((v) => v.id), //only extract the id
companyName: data.companyName ?? "",
position: data.position ?? "",
workExperience: data.workExperience ?? "",
address: data.address ?? "",
phoneNumber: data.phoneNumber ?? "",
});
form.setErrors({});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userQuery.data]);
const mutation = useMutation({
mutationKey: ["usersMutation"],
mutationFn: async (
options:
| { action: "ubah"; data: Parameters<typeof updateUser>[0] }
| { action: "tambah"; data: Parameters<typeof createUser>[0] }
) => {
console.log("called");
return options.action === "ubah"
? await updateUser(options.data)
: await createUser(options.data);
},
onError: (error: unknown) => {
console.log(error);
if (error instanceof FormResponseError) {
form.setErrors(error.formErrors);
return;
}
if (error instanceof Error) {
notifications.show({
message: error.message,
color: "red",
});
}
},
});
const handleSubmit = async (values: typeof form.values) => {
if (formType === "detail") return;
//TODO: OPtimize this code
if (formType === "tambah") {
await mutation.mutateAsync({
action: formType,
data: {
email: values.email,
name: values.name,
password: values.password,
roles: values.roles,
isEnabled: "true",
username: values.username,
companyName: values.email,
position: values.position,
workExperience: values.workExperience,
address: values.address,
phoneNumber: values.phoneNumber,
},
});
} else {
await mutation.mutateAsync({
action: formType,
data: {
id: values.id,
email: values.email,
name: values.name,
password: values.password,
roles: values.roles,
isEnabled: "true",
username: values.username,
companyName: values.companyName,
position: values.position,
workExperience: values.workExperience,
address: values.address,
phoneNumber: values.phoneNumber,
},
});
}
queryClient.invalidateQueries({ queryKey: ["users"] });
notifications.show({
message: `The ser is ${formType === "tambah" ? "created" : "edited"}`,
});
navigate({ search: {} });
};
/**
* YOU MIGHT NOT NEED FOLLOWING:
*/
const rolesQuery = useQuery({
queryKey: ["roles"],
queryFn: async () => {
const res = await client.roles.$get();
if (res.ok) {
return await res.json();
}
throw new Error(await res.text());
},
});
return (
<Modal
opened={isModalOpen}
onClose={() => navigate({ search: {} })}
title={modalTitle} //Uppercase first letter
scrollAreaComponent={ScrollArea.Autosize}
size="md"
>
<form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
<Stack mt="sm" gap="lg" px="lg">
{/* Avatar */}
<Center>
<Avatar
color={stringToColorHex(form.values.id ?? "")}
src={form.values.photoProfileUrl}
size={120}
>
{form.values.name?.[0]?.toUpperCase()}
</Avatar>
</Center>
</Stack>
{createInputComponents({
disableAll: mutation.isPending,
readonlyAll: formType === "detail",
inputs: [
{
type: "text",
label: "Id Pengguna",
readOnly: true,
variant: "filled",
...form.getInputProps("id"),
hidden: !form.values.id,
},
{
type: "text",
label: "Nama",
...form.getInputProps("name"),
},
{
type: "text",
label: "Jabatan",
...form.getInputProps("position"),
},
{
type: "text",
label: "Pengalaman Kerja",
...form.getInputProps("workExperience"),
},
{
type: "text",
label: "Email",
...form.getInputProps("email"),
},
{
type: "text",
label: "Instansi/Perusahaan",
...form.getInputProps("companyName"),
},
{
type: "text",
label: "Alamat",
...form.getInputProps("address"),
},
{
type: "text",
label: "Nomor Telepon",
...form.getInputProps("phoneNumber"),
},
{
type: "multi-select",
label: "Roles",
value: form.values.roles,
onChange: (values) =>
form.setFieldValue("roles", values),
data: rolesQuery.data?.map((role) => ({
value: role.id,
label: role.name,
})),
error: form.errors.roles,
},
{
type: "text",
label: "Username",
...form.getInputProps("username"),
},
{
type: "password",
label: "Password",
hidden: formType !== "tambah",
...form.getInputProps("password"),
},
],
})}
{/* Buttons */}
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
<Button
variant="outline"
onClick={() => navigate({ search: {} })}
disabled={mutation.isPending}
>
Close
</Button>
{formType !== "detail" && (
<Button
variant="filled"
leftSection={<TbDeviceFloppy size={20} />}
type="submit"
loading={mutation.isPending}
>
Save
</Button>
)}
</Flex>
</form>
</Modal>
);
}