From 9aff9e2dc88d09b5ecb5d67d087785b2c87a36a4 Mon Sep 17 00:00:00 2001 From: egagofur Date: Thu, 3 Apr 2025 23:32:44 +0700 Subject: [PATCH] feat: integeration register modal --- .../_components/form/modal-form-register.tsx | 72 ++++++++++++++----- apps/gacha/src/app/_hooks/use-register.ts | 28 ++++++++ apps/gacha/src/main.tsx | 2 + libs/service/src/schemas/auth/index.ts | 59 +++++++++++++++ libs/service/src/types/auth/index.ts | 7 +- 5 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 apps/gacha/src/app/_hooks/use-register.ts 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 2a9c385..37269ac 100644 --- a/apps/gacha/src/app/_components/form/modal-form-register.tsx +++ b/apps/gacha/src/app/_components/form/modal-form-register.tsx @@ -1,6 +1,8 @@ import { Button } from '@imphnen-frontend-service/ui/atoms'; import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules'; import { useQueryState } from '@imphnen-frontend-service/utils'; +import { useRegister } from '../../_hooks/use-register'; +import { ControlledInputField } from '@imphnen-frontend-service/ui/organisms'; interface IModalFormRegisterProps { isOpen: boolean; @@ -8,6 +10,8 @@ interface IModalFormRegisterProps { } const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { + const { form, onSubmit } = useRegister(); + const { step: currentStep, nextStep, @@ -37,45 +41,58 @@ const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { {currentStep === 1 ? 'Info Akun' : 'Informasi Pengiriman Hadiah'} - - {currentStep === 1 && } - {currentStep === 2 && ( - - )} + +
+ {currentStep === 1 && ( + + )} + {currentStep === 2 && ( + + )} +
); }; interface IStepOneProps { + form: any; nextStep: () => void; onClose: () => void; } -const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( +const StepOne = ({ form, nextStep, onClose }: IStepOneProps) => ( <> - - - - ( ); interface IStepTwoProps { + form: any; nextStep: () => void; prevStep: () => void; } -const StepTwo = ({ nextStep, prevStep }: IStepTwoProps) => ( +const StepTwo = ({ form, nextStep, prevStep }: IStepTwoProps) => ( <> - - + + ( - diff --git a/apps/gacha/src/app/_hooks/use-register.ts b/apps/gacha/src/app/_hooks/use-register.ts new file mode 100644 index 0000000..c5d7fb6 --- /dev/null +++ b/apps/gacha/src/app/_hooks/use-register.ts @@ -0,0 +1,28 @@ +import { useForm } from 'react-hook-form'; +import { + authRegisterSchema, + TRegisterRequest, + usePostRegister, +} from '@imphnen-frontend-service/service'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { toast } from 'sonner'; + +export const useRegister = () => { + const postRegister = usePostRegister(); + const form = useForm({ + resolver: zodResolver(authRegisterSchema), + mode: 'all', + }); + + const onSubmit = form.handleSubmit((data) => { + postRegister.mutate(data, { + onSuccess: (data) => toast.success(data.message), + onError: (error) => toast.error(error.message), + }); + }); + + return { + form, + onSubmit, + }; +}; diff --git a/apps/gacha/src/main.tsx b/apps/gacha/src/main.tsx index 7201952..919d102 100644 --- a/apps/gacha/src/main.tsx +++ b/apps/gacha/src/main.tsx @@ -8,6 +8,7 @@ import { convertPagesToRoute, QueryProvider, } from '@imphnen-frontend-service/utils'; +import { Toaster } from 'sonner'; import './index.css'; const files = import.meta.glob('./app/**/*(page|layout).tsx'); @@ -34,6 +35,7 @@ if (!rootElement) throw new Error('Failed to find the root element'); createRoot(rootElement).render( + diff --git a/libs/service/src/schemas/auth/index.ts b/libs/service/src/schemas/auth/index.ts index 9a61758..bb8e849 100644 --- a/libs/service/src/schemas/auth/index.ts +++ b/libs/service/src/schemas/auth/index.ts @@ -15,3 +15,62 @@ export const authLoginSchema = z.object({ }) .min(1, 'Password tidak boleh kosong'), }); + +export const authRegisterSchema = z + .object({ + email: z + .string({ + required_error: 'Email tidak boleh kosong', + invalid_type_error: 'Email harus berupa string', + }) + .min(1, 'Email tidak boleh kosong') + .email('Email harus valid'), + fullname: z + .string({ + required_error: 'Nama tidak boleh kosong', + invalid_type_error: 'Nama harus berupa string', + }) + .min(1, 'Nama tidak boleh kosong') + .max(50, 'Nama tidak boleh lebih dari 50 karakter'), + password: z + .string({ + required_error: 'Password tidak boleh kosong', + invalid_type_error: 'Password harus berupa string', + }) + .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', + }) + .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.`, + }); + } + }); diff --git a/libs/service/src/types/auth/index.ts b/libs/service/src/types/auth/index.ts index 031773c..8bd2d8d 100644 --- a/libs/service/src/types/auth/index.ts +++ b/libs/service/src/types/auth/index.ts @@ -16,9 +16,14 @@ export type TLoginResponse = { }; export type TRegisterRequest = { - fullname: string; email: string; + fullname: string; password: string; + phone_number: string; + referral_code?: string; + referred_by?: string; + student_type: string; + confirm_password: string; }; export type TVerifyEmailRequest = {