fix:form create user

This commit is contained in:
Rama Priyanto 2025-02-10 17:09:06 +07:00
parent f1589b5316
commit 573fc57991
3 changed files with 308 additions and 215 deletions

View File

@ -23,6 +23,7 @@ import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { z } from "zod";
import { EyeFilledIcon, EyeSlashFilledIcon } from "../icons";
import ReactPasswordChecklist from "react-password-checklist";
const masterUserSchema = z.object({
fullname: z.string().min(1, { message: "Required" }),
@ -42,17 +43,17 @@ const masterUserSchema = z.object({
passwordValidate: 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" }),
lastEducation: z.string().min(1, { message: "Required" }),
// lastEducation: z.string().min(1, { message: "Required" }),
genderType: z.string().min(1, { message: "Required" }),
phoneNumber: z.string().min(1, { message: "Required" }),
workType: z.string().min(1, { message: "Required" }),
// workType: z.string().min(1, { message: "Required" }),
address: z.string().min(1, { message: "Required" }),
birthDate: z.object({
startDate: z.string().min(1, { message: "Required" }),
endDate: z.string().min(1, { message: "Required" }),
}),
// birthDate: z.object({
// startDate: z.string().min(1, { message: "Required" }),
// endDate: z.string().min(1, { message: "Required" }),
// }),
});
const typeIdentity = [
@ -128,6 +129,8 @@ export default function FormMasterUser() {
const router = useRouter();
const MySwal = withReactContent(Swal);
const [isVisible, setIsVisible] = useState([false, false]);
const [isValidPassword, setIsValidPassword] = useState(false);
const toggleVisibility = (type: number) => {
setIsVisible(
type === 0 ? [!isVisible[0], isVisible[1]] : [isVisible[0], !isVisible[1]]
@ -136,10 +139,7 @@ export default function FormMasterUser() {
const formOptions = {
resolver: zodResolver(masterUserSchema),
defaultValues: {
identityType: "KTP",
birthDate: { stardDate: "", endDate: "" },
},
defaultValues: { password: "", passwordValidate: "" },
};
type MicroIssueSchema = z.infer<typeof masterUserSchema>;
const {
@ -147,24 +147,25 @@ export default function FormMasterUser() {
handleSubmit,
formState: { errors },
setError,
watch,
setValue,
} = useForm<MicroIssueSchema>(formOptions);
const passwordVal = watch("password");
const passwordConfVal = watch("passwordValidate");
async function save(data: z.infer<typeof masterUserSchema>) {
const formData = {
address: data.address,
dateOfBirt: data.birthDate,
password: data.password,
email: data.email,
fullname: data.fullname,
genderType: data.genderType,
identityNumber: data.identityNumber,
identityType: data.identityType,
lastEducation: data.lastEducation,
phoneNumber: data.phoneNumber,
userLevelId: 2,
userRoleId: 2,
username: data.username,
workType: data.workType,
};
const response = await createMasterUser(formData);
@ -174,7 +175,7 @@ export default function FormMasterUser() {
return false;
}
successSubmit("/admin/article");
successSubmit("/admin/master-user");
}
function successSubmit(redirect: any) {
@ -213,6 +214,40 @@ export default function FormMasterUser() {
}
}
const generatePassword = () => {
const length = Math.floor(Math.random() * 9) + 8;
const upperCaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const lowerCaseChars = "abcdefghijklmnopqrstuvwxyz";
const numberChars = "0123456789";
const specialChars = "!@#$%^&*";
const allChars =
upperCaseChars + lowerCaseChars + numberChars + specialChars;
let generatedPassword = "";
generatedPassword +=
upperCaseChars[Math.floor(Math.random() * upperCaseChars.length)];
generatedPassword +=
specialChars[Math.floor(Math.random() * specialChars.length)];
generatedPassword +=
numberChars[Math.floor(Math.random() * numberChars.length)];
generatedPassword +=
lowerCaseChars[Math.floor(Math.random() * lowerCaseChars.length)];
for (let i = generatedPassword.length; i < length; i++) {
generatedPassword +=
allChars[Math.floor(Math.random() * allChars.length)];
}
generatedPassword = generatedPassword
.split("")
.sort(() => 0.5 - Math.random())
.join("");
setValue("password", generatedPassword);
};
return (
<div className="mx-5 my-5 overflow-y-auto">
<form method="POST" onSubmit={handleSubmit(onSubmit)}>
@ -224,12 +259,18 @@ export default function FormMasterUser() {
<Input
type="text"
id="title"
placeholder="Fullname..."
label="Fullname"
placeholder="Nama Lengkap..."
label="Nama Lengkap"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
)}
@ -250,6 +291,12 @@ export default function FormMasterUser() {
onChange={onChange}
labelPlacement="outside"
className="w-full"
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
)}
@ -257,6 +304,220 @@ export default function FormMasterUser() {
{errors.username?.message && (
<p className="text-red-400 text-sm">{errors.username?.message}</p>
)}
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<Input
type="email"
id="email"
placeholder="Email..."
label="Email"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
)}
/>
{errors.email?.message && (
<p className="text-red-400 text-sm">{errors.email?.message}</p>
)}
{/* <Controller
control={control}
name="identityType"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Identity Type"
placeholder="Select"
className="max-w-xs"
selectedKeys={[value]}
onChange={onChange}
>
{typeIdentity.map((type) => (
<SelectItem key={type.value}>{type.value}</SelectItem>
))}
</Select>
)}
/>
{errors.identityType?.message && (
<p className="text-red-400 text-sm">
{errors.identityType?.message}
</p>
)} */}
<Controller
control={control}
name="identityNumber"
render={({ field: { onChange, value } }) => (
<Input
type="number"
id="identityNumber"
placeholder="NRP..."
label="NRP"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
)}
/>
{errors.identityNumber?.message && (
<p className="text-red-400 text-sm">
{errors.identityNumber?.message}
</p>
)}
<Controller
control={control}
name="address"
render={({ field: { onChange, value } }) => (
<Textarea
label="Alamat"
labelPlacement="outside"
placeholder="Alamat..."
variant="bordered"
value={value}
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
onValueChange={onChange}
/>
)}
/>
{errors.address?.message && (
<p className="text-red-400 text-sm">{errors.address?.message}</p>
)}
<Controller
control={control}
name="genderType"
render={({ field: { onChange, value } }) => (
<RadioGroup
orientation="horizontal"
label="Gender"
value={value}
onValueChange={onChange}
>
<Radio value="Male">Laki-laki</Radio>
<Radio value="Female">Perempuan</Radio>
</RadioGroup>
)}
/>
{errors.genderType?.message && (
<p className="text-red-400 text-sm">{errors.genderType?.message}</p>
)}
{/* <Controller
control={control}
name="birthDate"
render={({ field: { onChange, value } }) => (
<Datepicker
useRange={false}
asSingle={true}
value={value}
displayFormat="DD/MM/YYYY"
onChange={onChange}
popoverDirection="down"
inputClassName="w-full bg-transparent border-1 border-gray-200 px-2 py-[6px] rounded-xl "
/>
)}
/>
{errors.birthDate?.startDate?.message && (
<p className="text-red-400 text-sm">
{errors.birthDate?.startDate?.message}
</p>
)} */}
{/* <Controller
control={control}
name="lastEducation"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Last Education"
selectedKeys={[value]}
onChange={onChange}
placeholder="Select"
className="max-w-xs"
>
{educationGrade.map((grade) => (
<SelectItem key={grade.value}>{grade.value}</SelectItem>
))}
</Select>
)}
/>
{errors.lastEducation?.message && (
<p className="text-red-400 text-sm">
{errors.lastEducation?.message}
</p>
)} */}
<Controller
control={control}
name="phoneNumber"
render={({ field: { onChange, value } }) => (
<Input
type="number"
id="identityNumber"
placeholder="08*********"
label="No. Handphone"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
/>
)}
/>
{errors.phoneNumber?.message && (
<p className="text-red-400 text-sm">
{errors.phoneNumber?.message}
</p>
)}
{/* <Controller
control={control}
name="workType"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Working Type"
placeholder="Select"
className="max-w-xs"
selectedKeys={[value]}
onChange={onChange}
>
{workingBackground.map((type) => (
<SelectItem key={type.id} value={type.id}>
{type.value}
</SelectItem>
))}
</Select>
)}
/>
{errors.workType?.message && (
<p className="text-red-400 text-sm">{errors.workType?.message}</p>
)} */}
<Controller
control={control}
name="password"
@ -297,8 +558,8 @@ export default function FormMasterUser() {
<Input
type={isVisible[1] ? "text" : "password"}
id="passwordValidate"
placeholder="Confirm Password..."
label="Confirm Password"
placeholder="Konfirmasi Password..."
label="Konfirmasi Password"
value={value}
onChange={onChange}
labelPlacement="outside"
@ -326,198 +587,29 @@ export default function FormMasterUser() {
</p>
)}
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<Input
type="email"
id="email"
placeholder="Email..."
label="Email"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
/>
)}
<a
className="cursor-pointer text-[#DD8306]"
onClick={generatePassword}
>
Generate Password
</a>
<ReactPasswordChecklist
rules={["minLength", "specialChar", "number", "capital", "match"]}
minLength={8}
value={passwordVal}
valueAgain={passwordConfVal}
onChange={(isValid) => {
setIsValidPassword(isValid);
}}
className="text-black dark:text-white text-sm my-3"
messages={{
minLength: "Password must be more than 8 characters",
specialChar: "Password must include a special character",
number: "Password must include a number",
capital: "Password must include an uppercase letter",
match: "Passwords match",
}}
/>
{errors.email?.message && (
<p className="text-red-400 text-sm">{errors.email?.message}</p>
)}
<Controller
control={control}
name="identityType"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Identity Type"
placeholder="Select"
className="max-w-xs"
selectedKeys={[value]}
onChange={onChange}
>
{typeIdentity.map((type) => (
<SelectItem key={type.value}>{type.value}</SelectItem>
))}
</Select>
)}
/>
{errors.identityType?.message && (
<p className="text-red-400 text-sm">
{errors.identityType?.message}
</p>
)}
<Controller
control={control}
name="identityNumber"
render={({ field: { onChange, value } }) => (
<Input
type="number"
id="identityNumber"
placeholder="Identity Number..."
label="Identity Number"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
/>
)}
/>
{errors.identityNumber?.message && (
<p className="text-red-400 text-sm">
{errors.identityNumber?.message}
</p>
)}
<Controller
control={control}
name="genderType"
render={({ field: { onChange, value } }) => (
<RadioGroup
orientation="horizontal"
label="Gender"
value={value}
onValueChange={onChange}
>
<Radio value="Male">Laki-laki</Radio>
<Radio value="Female">Perempuan</Radio>
</RadioGroup>
)}
/>
{errors.genderType?.message && (
<p className="text-red-400 text-sm">{errors.genderType?.message}</p>
)}
<Controller
control={control}
name="birthDate"
render={({ field: { onChange, value } }) => (
<Datepicker
useRange={false}
asSingle={true}
value={value}
displayFormat="DD/MM/YYYY"
onChange={onChange}
popoverDirection="down"
inputClassName="w-full bg-transparent border-1 border-gray-200 px-2 py-[6px] rounded-xl "
/>
)}
/>
{errors.birthDate?.startDate?.message && (
<p className="text-red-400 text-sm">
{errors.birthDate?.startDate?.message}
</p>
)}
<Controller
control={control}
name="lastEducation"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Last Education"
selectedKeys={[value]}
onChange={onChange}
placeholder="Select"
className="max-w-xs"
>
{educationGrade.map((grade) => (
<SelectItem key={grade.value}>{grade.value}</SelectItem>
))}
</Select>
)}
/>
{errors.lastEducation?.message && (
<p className="text-red-400 text-sm">
{errors.lastEducation?.message}
</p>
)}
<Controller
control={control}
name="phoneNumber"
render={({ field: { onChange, value } }) => (
<Input
type="number"
id="identityNumber"
placeholder="08*********"
label="No. Handphone"
value={value}
onChange={onChange}
labelPlacement="outside"
className="w-full"
variant="bordered"
/>
)}
/>
{errors.phoneNumber?.message && (
<p className="text-red-400 text-sm">
{errors.phoneNumber?.message}
</p>
)}
<Controller
control={control}
name="workType"
render={({ field: { onChange, value } }) => (
<Select
variant="bordered"
labelPlacement="outside"
label="Working Type"
placeholder="Select"
className="max-w-xs"
selectedKeys={[value]}
onChange={onChange}
>
{workingBackground.map((type) => (
<SelectItem key={type.id} value={type.id}>
{type.value}
</SelectItem>
))}
</Select>
)}
/>
{errors.workType?.message && (
<p className="text-red-400 text-sm">{errors.workType?.message}</p>
)}
<Controller
control={control}
name="address"
render={({ field: { onChange, value } }) => (
<Textarea
label="Address"
labelPlacement="outside"
placeholder="Enter Text"
value={value}
onValueChange={onChange}
/>
)}
/>
{errors.address?.message && (
<p className="text-red-400 text-sm">{errors.address?.message}</p>
)}
<div className="flex justify-end gap-3">
<Link href={`/admin/master-user`}>
<Button color="danger" variant="ghost">

View File

@ -622,8 +622,9 @@ export const TwIcon = ({
>
<rect width="30" height="30" rx="8" fill="white" />
<path
d="M22.1497 11.3338C22.1612 11.4936 22.1612 11.6536 22.1612 11.8135C22.1612 16.6903 18.4493 22.3096 11.665 22.3096C9.57486 22.3096 7.63325 21.7043 6 20.6536C6.29696 20.6878 6.58247 20.6992 6.89086 20.6992C8.61545 20.6992 10.203 20.1168 11.4708 19.1231C9.84898 19.0888 8.48984 18.0267 8.02155 16.5647C8.25 16.599 8.47841 16.6218 8.71828 16.6218C9.04949 16.6218 9.38073 16.5761 9.68909 16.4962C7.99874 16.1535 6.73093 14.6688 6.73093 12.8756V12.83C7.22203 13.1041 7.79314 13.2754 8.39843 13.2982C7.40477 12.6358 6.75379 11.5051 6.75379 10.2259C6.75379 9.54061 6.93649 8.91244 7.25631 8.36421C9.0723 10.6028 11.802 12.0647 14.8629 12.2246C14.8058 11.9505 14.7715 11.665 14.7715 11.3795C14.7715 9.34644 16.4162 7.69037 18.4606 7.69037C19.5228 7.69037 20.4822 8.1358 21.156 8.85534C21.9898 8.69545 22.7893 8.38706 23.4974 7.96448C23.2233 8.8211 22.6408 9.54064 21.8756 9.99746C22.618 9.91755 23.3375 9.71192 23.9999 9.42642C23.4975 10.1574 22.8693 10.8083 22.1497 11.3338Z"
fill="#1DA1F2"
fill="black"
d="M10.488 14.651L15.25 21h7l-7.858-10.478L20.93 3h-2.65l-5.117 5.886L8.75 3h-7l7.51 10.015L2.32 21h2.65zM16.25 19L5.75 5h2l10.5 14z"
transform="translate(2 2)"
/>
</svg>
);

View File

@ -214,12 +214,12 @@ export default function MasterRoleTable() {
Detail
</Link>
</DropdownItem>
<DropdownItem>
{/* <DropdownItem>
<Link href={`/admin/master-role/edit/${role.id}`}>
<CreateIconIon className="inline mr-2 mb-1" />
Edit
</Link>
</DropdownItem>
</DropdownItem> */}
<DropdownItem onClick={() => handleDelete(role.id)}>
<DeleteIcon
color="red"