From d61cb4a21578dce8ca9ad5ee3b729e272a7bc359 Mon Sep 17 00:00:00 2001 From: egagofur Date: Fri, 4 Apr 2025 16:38:21 +0700 Subject: [PATCH] fix: split zod validation register modal --- .../_components/form/modal-form-register.tsx | 103 ++++++++++-------- apps/gacha/src/app/_hooks/use-register.ts | 30 +++++ libs/service/src/schemas/auth/index.ts | 56 +++++----- 3 files changed, 116 insertions(+), 73 deletions(-) diff --git a/apps/gacha/src/app/_components/form/modal-form-register.tsx b/apps/gacha/src/app/_components/form/modal-form-register.tsx index 0112319..8f50e04 100644 --- a/apps/gacha/src/app/_components/form/modal-form-register.tsx +++ b/apps/gacha/src/app/_components/form/modal-form-register.tsx @@ -12,7 +12,7 @@ interface IModalFormRegisterProps { } const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { - const { form, onSubmit } = useRegister(); + const { form, onSubmit, isStepOneValid } = useRegister(); const { step: currentStep, @@ -46,7 +46,11 @@ const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => {
{currentStep === 1 && ( - + )} {currentStep === 2 && } @@ -58,52 +62,59 @@ const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { interface IStepOneProps { form: UseFormReturn; nextStep: () => void; - onClose: () => void; + isStepOneValid: boolean; } -const StepOne = ({ form, nextStep, onClose }: IStepOneProps) => ( - <> - - - - - - -); +const StepOne = ({ form, nextStep, isStepOneValid }: IStepOneProps) => { + return ( + <> + + + + + + + ); +}; interface IStepTwoProps { form: UseFormReturn; diff --git a/apps/gacha/src/app/_hooks/use-register.ts b/apps/gacha/src/app/_hooks/use-register.ts index c5d7fb6..5817c30 100644 --- a/apps/gacha/src/app/_hooks/use-register.ts +++ b/apps/gacha/src/app/_hooks/use-register.ts @@ -1,19 +1,48 @@ import { useForm } from 'react-hook-form'; import { authRegisterSchema, + stepOneRegisterSchema, TRegisterRequest, usePostRegister, } from '@imphnen-frontend-service/service'; +import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; import { toast } from 'sonner'; +import { useEffect, useState } from 'react'; export const useRegister = () => { const postRegister = usePostRegister(); const form = useForm({ resolver: zodResolver(authRegisterSchema), mode: 'all', + defaultValues: { + fullname: '', + email: '', + password: '', + confirm_password: '', + phone_number: '', + referral_code: '', + referred_by: '', + student_type: '', + }, }); + const [stepValid, setStepValid] = useState(false); + + useEffect(() => { + const subscription = form.watch(() => { + const { fullname, email, password, confirm_password } = form.getValues(); + const valid = stepOneRegisterSchema.safeParse({ + fullname, + email, + password, + confirm_password, + }).success; + setStepValid(valid); + }); + return () => subscription.unsubscribe(); + }, [form]); + const onSubmit = form.handleSubmit((data) => { postRegister.mutate(data, { onSuccess: (data) => toast.success(data.message), @@ -24,5 +53,6 @@ export const useRegister = () => { return { form, onSubmit, + isStepOneValid: stepValid, }; }; diff --git a/libs/service/src/schemas/auth/index.ts b/libs/service/src/schemas/auth/index.ts index bb8e849..d406f97 100644 --- a/libs/service/src/schemas/auth/index.ts +++ b/libs/service/src/schemas/auth/index.ts @@ -16,7 +16,7 @@ export const authLoginSchema = z.object({ .min(1, 'Password tidak boleh kosong'), }); -export const authRegisterSchema = z +export const stepOneRegisterSchema = z .object({ email: z .string({ @@ -40,24 +40,6 @@ export const authRegisterSchema = z .min(1, 'Password tidak boleh kosong') .min(8, 'Password harus lebih dari 8 karakter') .max(50, 'Password tidak boleh lebih dari 50 karakter'), - phone_number: z - .string({ - required_error: 'Nomor telepon tidak boleh kosong', - invalid_type_error: 'Nomor telepon harus berupa string', - }) - .min(1, 'Nomor telepon tidak boleh kosong') - .max(15, 'Nomor telepon tidak boleh lebih dari 15 karakter'), - referral_code: z - .string() - .min(1, 'Kode referral tidak boleh kosong') - .max(4, 'Kode referral tidak boleh lebih dari 4 karakter') - .optional(), - referred_by: z - .string() - .min(1, 'Kode referral tidak boleh kosong') - .max(50, 'Kode referral tidak boleh lebih dari 50 karakter') - .optional(), - student_type: z.string(), confirm_password: z .string({ required_error: 'Konfirmasi password tidak boleh kosong', @@ -65,12 +47,32 @@ export const authRegisterSchema = z .min(1, 'Konfirmasi password tidak boleh kosong') .max(50, 'Konfirmasi password tidak boleh lebih dari 50 karakter'), }) - .superRefine((val, ctx) => { - if (val.password !== val.confirm_password) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ['confirm_password'], - message: `No duplicates allowed.`, - }); - } + .refine((data) => data.password === data.confirm_password, { + message: 'Password dan Konfirmasi Password harus sama', + path: ['confirm_password'], }); + +const stepTwoRegisterSchema = z.object({ + phone_number: z + .string({ + required_error: 'Nomor telepon tidak boleh kosong', + invalid_type_error: 'Nomor telepon harus berupa string', + }) + .min(1, 'Nomor telepon tidak boleh kosong') + .max(15, 'Nomor telepon tidak boleh lebih dari 15 karakter'), + referral_code: z + .string() + .min(1, 'Kode referral tidak boleh kosong') + .max(4, 'Kode referral tidak boleh lebih dari 4 karakter') + .optional(), + referred_by: z + .string() + .min(1, 'Kode referral tidak boleh kosong') + .max(50, 'Kode referral tidak boleh lebih dari 50 karakter') + .optional(), + student_type: z.string(), +}); + +export const authRegisterSchema = stepOneRegisterSchema.and( + stepTwoRegisterSchema +);