Update : Shadcn migration except Modal and Scrollarea in user management
This commit is contained in:
parent
4f3e9f50a8
commit
d3da289363
|
|
@ -16,17 +16,17 @@ import { respondents } from "../../drizzle/schema/respondents";
|
|||
import { forbidden, notFound } from "../../errors/DashboardError";
|
||||
|
||||
export const userFormSchema = z.object({
|
||||
name: z.string().min(1, "Name is required").max(255),
|
||||
username: z.string().min(1, "Username is required").max(255),
|
||||
email: z.string().min(1, "Email is required").max(255),
|
||||
password: z.string().min(6, "Password is required"),
|
||||
companyName: z.string().min(1, "Company name is required").max(255),
|
||||
position: z.string().min(1, "Position is required").max(255),
|
||||
workExperience: z.string().min(1, "Work experience is required").max(255),
|
||||
address: z.string().min(1, "Address is required"),
|
||||
phoneNumber: z.string().min(1, "Phone number is required").max(13),
|
||||
name: z.string().min(1, "Nama wajib diisi").max(255),
|
||||
username: z.string().min(1, "Username wajib diisi").max(255),
|
||||
email: z.string().min(1, "Email wajib diisi").max(255),
|
||||
password: z.string().min(6, "Password wajib diisi"),
|
||||
companyName: z.string().min(1, "Nama Perusahaan wajib diisi").max(255),
|
||||
position: z.string().min(1, "Jabatan wajib diisi").max(255),
|
||||
workExperience: z.string().min(1, "Pengalaman Kerja wajib diisi").max(255),
|
||||
address: z.string().min(1, "Alamat wajib diisi"),
|
||||
phoneNumber: z.string().min(1, "Nomor Telepon wajib diisi").max(13),
|
||||
isEnabled: z.string().default("false"),
|
||||
roles: z.array(z.string().min(1, "Role is required")),
|
||||
roles: z.array(z.string().min(1, "Role wajib diisi")),
|
||||
});
|
||||
|
||||
export const userUpdateSchema = userFormSchema.extend({
|
||||
|
|
@ -342,7 +342,7 @@ const usersRoute = new Hono<HonoEnv>()
|
|||
.values({
|
||||
companyName: userData.companyName,
|
||||
position: userData.position,
|
||||
workExperience: userData.workExperience,
|
||||
workExperience: userData.workExperience + " Tahun",
|
||||
address: userData.address,
|
||||
phoneNumber: userData.phoneNumber,
|
||||
userId: newUser.id,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
import client from "@/honoClient";
|
||||
import { Button, Flex, Modal, Text } from "@mantine/core";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/shadcn/components/ui/alert-dialog";
|
||||
import { Button } from "@/shadcn/components/ui/button";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { getRouteApi, useSearch } from "@tanstack/react-router";
|
||||
import { deleteUser } from "../queries/userQueries";
|
||||
|
|
@ -60,40 +69,34 @@ export default function UserDeleteModal() {
|
|||
const isModalOpen = Boolean(searchParams.delete && userQuery.data);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
opened={isModalOpen}
|
||||
onClose={() => navigate({ search: {} })}
|
||||
title={`Konfirmasi Hapus`}
|
||||
>
|
||||
<Text size="sm">
|
||||
Apakah Anda yakin ingin menghapus pengguna{" "}
|
||||
<Text span fw={700}>
|
||||
{userQuery.data?.name}
|
||||
</Text>
|
||||
? Tindakan ini tidak dapat diubah.
|
||||
</Text>
|
||||
|
||||
{/* {errorMessage && <Alert color="red">{errorMessage}</Alert>} */}
|
||||
{/* Buttons */}
|
||||
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate({ search: {} })}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button
|
||||
variant="subtle"
|
||||
// leftSection={<TbDeviceFloppy size={20} />}
|
||||
type="submit"
|
||||
color="red"
|
||||
loading={mutation.isPending}
|
||||
onClick={() => mutation.mutate({ id: userId })}
|
||||
>
|
||||
Hapus Pengguna
|
||||
</Button>
|
||||
</Flex>
|
||||
</Modal>
|
||||
<AlertDialog open={isModalOpen} onOpenChange={() => navigate({ search: {} })}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Konfirmasi Hapus</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Apakah Anda yakin ingin menghapus pengguna{" "}
|
||||
<strong>{userQuery.data?.name}</strong>?
|
||||
<br />
|
||||
Tindakan ini tidak dapat diubah.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel
|
||||
onClick={() => navigate({ search: {} })}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
Batal
|
||||
</AlertDialogCancel>
|
||||
<Button
|
||||
variant="default"
|
||||
color="red"
|
||||
onClick={() => mutation.mutate({ id: userId })}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
{mutation.isPending ? "Hapus..." : "Hapus Pengguna"}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
import client from "../../../honoClient";
|
||||
import stringToColorHex from "@/utils/stringToColorHex";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
Modal,
|
||||
ScrollArea,
|
||||
Stack,
|
||||
} from "@mantine/core";
|
||||
AvatarFallback,
|
||||
AvatarImage
|
||||
} from "@/shadcn/components/ui/avatar";
|
||||
import { Modal, ScrollArea } from "@mantine/core";
|
||||
import { Button } from "@/shadcn/components/ui/button";
|
||||
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";
|
||||
|
|
@ -191,114 +188,113 @@ export default function UserFormModal() {
|
|||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<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>
|
||||
>
|
||||
<form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
|
||||
<div className="flex items-center justify-center my-2">
|
||||
<div className="h-120 w-120 rounded-full overflow-hidden">
|
||||
<Avatar className="h-[120px] w-[120px] rounded-full overflow-hidden">
|
||||
<AvatarImage src={form.values.photoProfileUrl} alt={form.values.name} />
|
||||
<AvatarFallback style={{ backgroundColor: stringToColorHex(form.values.id ?? ""), fontSize: "60px", color: "white", fontWeight: "bold" }}>
|
||||
{form.values.name?.[0]?.toUpperCase() ?? "?"}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{createInputComponents({
|
||||
disableAll: mutation.isPending,
|
||||
readonlyAll: formType === "detail",
|
||||
inputs: [
|
||||
{
|
||||
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"),
|
||||
},
|
||||
],
|
||||
})}
|
||||
<ScrollArea className="h-72 pr-4">
|
||||
{createInputComponents({
|
||||
disableAll: mutation.isPending,
|
||||
readonlyAll: formType === "detail",
|
||||
inputs: [
|
||||
{
|
||||
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"),
|
||||
},
|
||||
],
|
||||
})}
|
||||
</ScrollArea>
|
||||
|
||||
{/* Buttons */}
|
||||
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate({ search: {} })}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
Tutup
|
||||
</Button>
|
||||
{formType !== "detail" && (
|
||||
<Button
|
||||
variant="filled"
|
||||
leftSection={<TbDeviceFloppy size={20} />}
|
||||
type="submit"
|
||||
loading={mutation.isPending}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</form>
|
||||
{/* Buttons */}
|
||||
<div className="flex justify-end align-center gap-1 mt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate({ search: {} })}
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
Tutup
|
||||
</Button>
|
||||
{formType !== "detail" && (
|
||||
<Button
|
||||
variant="default"
|
||||
type="submit"
|
||||
disabled={mutation.isPending}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { createLazyFileRoute } from "@tanstack/react-router";
|
|||
import UserFormModal from "@/modules/usersManagement/modals/UserFormModal";
|
||||
import ExtractQueryDataType from "@/types/ExtractQueryDataType";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { Badge, Flex } from "@mantine/core";
|
||||
import createActionButtons from "@/utils/createActionButton";
|
||||
import { TbEye, TbPencil, TbTrash } from "react-icons/tb";
|
||||
import UserDeleteModal from "@/modules/usersManagement/modals/UserDeleteModal";
|
||||
|
|
@ -61,7 +60,7 @@ export default function UsersPage() {
|
|||
columnHelper.display({
|
||||
header: "Aksi",
|
||||
cell: (props) => (
|
||||
<Flex gap="xs">
|
||||
<div className="flex gap-x-2">
|
||||
{createActionButtons([
|
||||
{
|
||||
label: "Detail",
|
||||
|
|
@ -85,7 +84,7 @@ export default function UsersPage() {
|
|||
icon: <TbTrash />,
|
||||
},
|
||||
])}
|
||||
</Flex>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
]}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user