fix:create user, create role form

This commit is contained in:
Rama Priyanto 2024-12-04 09:35:29 +07:00
parent 24d27df67e
commit 0d04ea0b14
3 changed files with 381 additions and 176 deletions

View File

@ -1,10 +1,10 @@
import FormMasterUserRole from '@/components/form/form-master-user-role' import FormMasterUserRole from "@/components/form/form-master-user-role";
import { Card } from '@nextui-org/react' import { Card } from "@nextui-org/react";
export default function CreateMasterUserRolePage() { export default function CreateMasterUserRolePage() {
return ( return (
<Card className="h-[96vh] rounded-md my- ml-3 border bg-transparent"> <Card className="h-[96vh] rounded-md border bg-transparent">
<FormMasterUserRole /> <FormMasterUserRole />
</Card> </Card>
) );
} }

View File

@ -1,164 +1,308 @@
'use client' "use client";
import { error } from '@/config/swal'; import { error } from "@/config/swal";
import { createMasterUser } from '@/service/master-user'; import { createMasterUser } from "@/service/master-user";
import { createMasterUserRole } from '@/service/master-user-role'; import { createMasterUserRole } from "@/service/master-user-role";
import { MasterUser } from '@/types/globals'; import { MasterUser } from "@/types/globals";
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from "@hookform/resolvers/zod";
import { Button, Card, Input, Radio, RadioGroup, Select, SelectItem, Selection, Textarea } from '@nextui-org/react' import {
import Link from 'next/link'; Button,
import { useRouter } from 'next/navigation'; Card,
import React, { useState } from 'react' Checkbox,
import { useForm } from 'react-hook-form'; Input,
import Swal from 'sweetalert2'; Radio,
import withReactContent from 'sweetalert2-react-content'; RadioGroup,
import { z } from 'zod'; Select,
SelectItem,
Selection,
Textarea,
} from "@nextui-org/react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { z } from "zod";
const masterUserSchema = z.object({ const masterUserSchema = z.object({
code: z.string().min(1, { message: "Required" }), code: z.string().min(1, { message: "Required" }),
description: z.string().min(1, { message: "Required" }), description: z.string().min(1, { message: "Required" }),
levelNumber: z.string().min(1, { message: "Required" }), name: z.string().min(1, { message: "Required" }),
name: z.string().min(1, { message: "Required" }), userLevelId: z.string().min(1, { message: "Required" }),
userRoleAccess: z.array(
z.object({
isAdminEnabled: z.boolean(),
isApprovalEnabled: z.boolean(),
isDeleteEnabled: z.boolean(),
isInsertEnabled: z.boolean(),
isUpdateEnabled: z.boolean(),
isViewEnabled: z.boolean(),
menuId: z.number(),
menuTitle: z.string(),
})
),
}); });
const menus = [{ id: 1, title: "Menu 1" }];
export default function FormMasterUserRole() { export default function FormMasterUserRole() {
const router = useRouter(); const router = useRouter();
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
const [code, setCode] = useState<string>();
const [description, setDescription] = useState<string>();
const [levelNumber, setLevelNumber] = useState<any>(1);
const [name, setName] = useState<string>();
const formOptions = { resolver: zodResolver(masterUserSchema) }; const formOptions = {
type MicroIssueSchema = z.infer<typeof masterUserSchema>; resolver: zodResolver(masterUserSchema),
const { };
register, type MicroIssueSchema = z.infer<typeof masterUserSchema>;
control, const {
handleSubmit, register,
setValue, control,
formState: { errors }, handleSubmit,
} = useForm<MicroIssueSchema>(formOptions); setValue,
getValues,
formState: { errors },
} = useForm<MicroIssueSchema>(formOptions);
const { fields, append, remove } = useFieldArray({
control,
name: "userRoleAccess",
});
useEffect(() => {
const data: any = [];
menus.map((menu) => {
data.push({
menuId: menu.id,
isAdminEnabled: false,
isApprovalEnabled: false,
isDeleteEnabled: false,
isInsertEnabled: false,
isUpdateEnabled: false,
isViewEnabled: false,
menuTitle: menu.title,
});
});
setValue("userRoleAccess", data);
}, []);
async function save(data: any) { async function save(data: z.infer<typeof masterUserSchema>) {
const formData = { const formData = {
code: code, code: data.code,
description: description, description: data.description,
level_number: levelNumber, statusId: 1,
name: name, userLevelIds: [Number(data.userLevelId)],
name: data.name,
userRoleAccess: data.userRoleAccess.map((roleAccess) => {
return {
isAdminEnabled: roleAccess.isAdminEnabled,
isApprovalEnabled: roleAccess.isApprovalEnabled,
isDeleteEnabled: roleAccess.isDeleteEnabled,
isInsertEnabled: roleAccess.isInsertEnabled,
isUpdateEnabled: roleAccess.isUpdateEnabled,
isViewEnabled: roleAccess.isViewEnabled,
menuId: roleAccess.menuId,
}; };
}),
console.log("Form MasterUser:", formData);
const response = await createMasterUserRole(formData);
if (response?.error) {
error(response.message);
return false;
}
successSubmit("/admin/master-role");
}; };
function successSubmit(redirect: any) { console.log("Form MasterUser:", formData);
MySwal.fire({ const response = await createMasterUserRole(formData);
title: "Sukses",
icon: "success", if (response?.error) {
confirmButtonColor: "#3085d6", error(response.message);
confirmButtonText: "OK", return false;
}).then((result) => {
if (result.isConfirmed) {
router.push(redirect);
}
});
} }
async function onSubmit(data: any) { successSubmit("/admin/master-role");
MySwal.fire({ }
title: "Simpan Data",
text: "",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#d33",
confirmButtonColor: "#3085d6",
confirmButtonText: "Simpan",
}).then((result) => {
if (result.isConfirmed) {
save(data);
}
});
}
return ( function successSubmit(redirect: any) {
<div className='mx-5 my-5 overflow-y-auto'> MySwal.fire({
<form method="POST" onSubmit={handleSubmit(onSubmit)}> title: "Sukses",
<Card className='rounded-md p-5 space-y-5'> icon: "success",
<div> confirmButtonColor: "#3085d6",
<Input confirmButtonText: "OK",
type="text" }).then((result) => {
{...register("code")} if (result.isConfirmed) {
label="Code" router.push(redirect);
variant='bordered' }
placeholder="Enter Text" });
labelPlacement='outside' }
value={code}
onChange={(e) => setCode(e.target.value)} async function onSubmit(data: z.infer<typeof masterUserSchema>) {
/> MySwal.fire({
{errors.code?.message} title: "Simpan Data",
</div> text: "",
<div> icon: "warning",
<Input showCancelButton: true,
type="text" cancelButtonColor: "#d33",
{...register("name")} confirmButtonColor: "#3085d6",
label="Role" confirmButtonText: "Simpan",
variant='bordered' }).then((result) => {
placeholder="Enter Text" if (result.isConfirmed) {
labelPlacement='outside' save(data);
value={name} }
onChange={(e) => setName(e.target.value)} });
/> }
{errors.name?.message}
</div> return (
<div> <div className="mx-5 my-5 overflow-y-auto">
<Textarea <form method="POST" onSubmit={handleSubmit(onSubmit)}>
label="Description" <Card className="rounded-md flex flex-col gap-3 p-5">
{...register("description")} <Controller
labelPlacement="outside" control={control}
placeholder="Enter Text" name="code"
value={description} render={({ field: { onChange, value } }) => (
onValueChange={setDescription} <Input
/> type="text"
</div> id="code"
<div> placeholder="Code..."
<Input label="Code"
type="text" value={value}
{...register("levelNumber")} onChange={onChange}
label="Level Number" labelPlacement="outside"
variant='bordered' className="w-full"
placeholder="Enter Text" variant="bordered"
labelPlacement='outside' />
value={levelNumber} )}
/> />
{errors.code?.message} {errors.code?.message && (
</div> <p className="text-red-400 text-sm">{errors.code?.message}</p>
<div className='flex justify-end gap-3'> )}
<Link href={`/admin/master-role`}> <Controller
<Button control={control}
color='danger' name="name"
variant="ghost" render={({ field: { onChange, value } }) => (
> <Input
Cancel type="text"
</Button> id="name"
</Link> placeholder="Name..."
<Button label="Name"
type="submit" value={value}
color='primary' onChange={onChange}
variant="solid" labelPlacement="outside"
> className="w-full"
Save variant="bordered"
</Button> />
</div> )}
</Card> />
</form> {errors.name?.message && (
</div > <p className="text-red-400 text-sm">{errors.name?.message}</p>
) )}
<Controller
control={control}
name="description"
render={({ field: { onChange, value } }) => (
<Textarea
label="Description"
labelPlacement="outside"
placeholder="Enter Text"
value={value}
onValueChange={onChange}
/>
)}
/>
{errors.description?.message && (
<p className="text-red-400 text-sm">
{errors.description?.message}
</p>
)}
<Controller
control={control}
name="userLevelId"
render={({ field: { onChange, value } }) => (
<Input
type="number"
id="userLevelId"
placeholder="User Level..."
label="User Level"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
/>
)}
/>
{errors.userLevelId?.message && (
<p className="text-red-400 text-sm">
{errors.userLevelId?.message}
</p>
)}
<p>Menus</p>
{fields.map((field, index) => (
<div key={field.menuId} className="flex flex-row gap-10">
<p>{field.menuTitle}</p>
<div className="grid grid-cols-6 gap-3">
{/* <Checkbox>Option</Checkbox> */}
<Controller
control={control}
name={`userRoleAccess.${index}.isAdminEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isAdminEnabled
</Checkbox>
)}
/>
<Controller
control={control}
name={`userRoleAccess.${index}.isApprovalEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isApprovalEnabled
</Checkbox>
)}
/>
<Controller
control={control}
name={`userRoleAccess.${index}.isDeleteEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isDeleteEnabled
</Checkbox>
)}
/>
<Controller
control={control}
name={`userRoleAccess.${index}.isInsertEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isInsertEnabled
</Checkbox>
)}
/>
<Controller
control={control}
name={`userRoleAccess.${index}.isUpdateEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isUpdateEnabled
</Checkbox>
)}
/>
<Controller
control={control}
name={`userRoleAccess.${index}.isViewEnabled`}
render={({ field: { onChange, value } }) => (
<Checkbox isSelected={value} onValueChange={onChange}>
isViewEnabled
</Checkbox>
)}
/>
</div>
</div>
))}
<div className="flex justify-end gap-3">
<Link href={`/admin/master-role`}>
<Button color="danger" variant="ghost">
Cancel
</Button>
</Link>
<Button type="submit" color="primary" variant="solid">
Save
</Button>
</div>
</Card>
</form>
</div>
);
} }

View File

@ -27,7 +27,20 @@ import { EyeFilledIcon, EyeSlashFilledIcon } from "../icons";
const masterUserSchema = z.object({ const masterUserSchema = z.object({
fullname: z.string().min(1, { message: "Required" }), fullname: z.string().min(1, { message: "Required" }),
username: z.string().min(1, { message: "Required" }), username: z.string().min(1, { message: "Required" }),
password: z.string().min(1, { message: "Required" }), password: z
.string()
.min(8, "Password harus memiliki minimal 8 karakter.")
.refine((password) => /[A-Z]/.test(password), {
message: "Password harus memiliki minimal satu huruf kapital.",
})
.refine((password) => /[0-9]/.test(password), {
message: "Password harus memiliki minimal satu angka.",
})
.refine((password) => /[!@#$%^&*(),.?":{}|<>]/.test(password), {
message: "Password harus memiliki minimal satu simbol.",
}),
passwordValidate: z.string().min(1, { message: "Required" }),
email: z.string().min(1, { message: "Required" }), email: z.string().min(1, { message: "Required" }),
identityType: z.string().min(1, { message: "Required" }), identityType: z.string().min(1, { message: "Required" }),
identityNumber: z.string().min(1, { message: "Required" }), identityNumber: z.string().min(1, { message: "Required" }),
@ -114,8 +127,12 @@ const educationGrade = [
export default function FormMasterUser() { export default function FormMasterUser() {
const router = useRouter(); const router = useRouter();
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
const [isVisible, setIsVisible] = useState(false); const [isVisible, setIsVisible] = useState([false, false]);
const toggleVisibility = () => setIsVisible(!isVisible); const toggleVisibility = (type: number) => {
setIsVisible(
type === 0 ? [!isVisible[0], isVisible[1]] : [isVisible[0], !isVisible[1]]
);
};
const formOptions = { const formOptions = {
resolver: zodResolver(masterUserSchema), resolver: zodResolver(masterUserSchema),
@ -129,6 +146,7 @@ export default function FormMasterUser() {
control, control,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
setError,
} = useForm<MicroIssueSchema>(formOptions); } = useForm<MicroIssueSchema>(formOptions);
async function save(data: z.infer<typeof masterUserSchema>) { async function save(data: z.infer<typeof masterUserSchema>) {
@ -173,19 +191,26 @@ export default function FormMasterUser() {
} }
async function onSubmit(data: z.infer<typeof masterUserSchema>) { async function onSubmit(data: z.infer<typeof masterUserSchema>) {
MySwal.fire({ if (data.password === data.passwordValidate) {
title: "Simpan Data", MySwal.fire({
text: "", title: "Simpan Data",
icon: "warning", text: "",
showCancelButton: true, icon: "warning",
cancelButtonColor: "#d33", showCancelButton: true,
confirmButtonColor: "#3085d6", cancelButtonColor: "#d33",
confirmButtonText: "Simpan", confirmButtonColor: "#3085d6",
}).then((result) => { confirmButtonText: "Simpan",
if (result.isConfirmed) { }).then((result) => {
save(data); if (result.isConfirmed) {
} save(data);
}); }
});
} else {
setError("passwordValidate", {
type: "manual",
message: "Password harus sama.",
});
}
} }
return ( return (
@ -237,7 +262,7 @@ export default function FormMasterUser() {
name="password" name="password"
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<Input <Input
type={isVisible ? "text" : "password"} type={isVisible[0] ? "text" : "password"}
id="password" id="password"
placeholder="Password..." placeholder="Password..."
label="Password" label="Password"
@ -250,9 +275,9 @@ export default function FormMasterUser() {
<button <button
className="focus:outline-none" className="focus:outline-none"
type="button" type="button"
onClick={toggleVisibility} onClick={() => toggleVisibility(0)}
> >
{isVisible ? ( {isVisible[0] ? (
<EyeSlashFilledIcon className="text-2xl text-default-400 pointer-events-none" /> <EyeSlashFilledIcon className="text-2xl text-default-400 pointer-events-none" />
) : ( ) : (
<EyeFilledIcon className="text-2xl text-default-400 pointer-events-none" /> <EyeFilledIcon className="text-2xl text-default-400 pointer-events-none" />
@ -265,6 +290,42 @@ export default function FormMasterUser() {
{errors.password?.message && ( {errors.password?.message && (
<p className="text-red-400 text-sm">{errors.password?.message}</p> <p className="text-red-400 text-sm">{errors.password?.message}</p>
)} )}
<Controller
control={control}
name="passwordValidate"
render={({ field: { onChange, value } }) => (
<Input
type={isVisible[1] ? "text" : "password"}
id="passwordValidate"
placeholder="Confirm Password..."
label="Confirm Password"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
endContent={
<button
className="focus:outline-none"
type="button"
onClick={() => toggleVisibility(1)}
>
{isVisible[1] ? (
<EyeSlashFilledIcon className="text-2xl text-default-400 pointer-events-none" />
) : (
<EyeFilledIcon className="text-2xl text-default-400 pointer-events-none" />
)}
</button>
}
/>
)}
/>
{errors.passwordValidate?.message && (
<p className="text-red-400 text-sm">
{errors.passwordValidate?.message}
</p>
)}
<Controller <Controller
control={control} control={control}
name="email" name="email"
@ -343,8 +404,8 @@ export default function FormMasterUser() {
value={value} value={value}
onValueChange={onChange} onValueChange={onChange}
> >
<Radio value="male">Laki-laki</Radio> <Radio value="Male">Laki-laki</Radio>
<Radio value="female">Perempuan</Radio> <Radio value="Female">Perempuan</Radio>
</RadioGroup> </RadioGroup>
)} )}
/> />