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..0112319 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,10 @@ import { Button } from '@imphnen-frontend-service/ui/atoms'; -import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules'; +import { 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'; +import { UseFormReturn } from 'react-hook-form'; +import { TRegisterRequest } from '@imphnen-frontend-service/service'; interface IModalFormRegisterProps { isOpen: boolean; @@ -8,6 +12,8 @@ interface IModalFormRegisterProps { } const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { + const { form, onSubmit } = useRegister(); + const { step: currentStep, nextStep, @@ -37,45 +43,56 @@ const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { {currentStep === 1 ? 'Info Akun' : 'Informasi Pengiriman Hadiah'} - - {currentStep === 1 && } - {currentStep === 2 && ( - - )} + +
+ {currentStep === 1 && ( + + )} + {currentStep === 2 && } +
); }; interface IStepOneProps { + form: UseFormReturn; nextStep: () => void; onClose: () => void; } -const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( +const StepOne = ({ form, nextStep, onClose }: IStepOneProps) => ( <> - - - - ( ); interface IStepTwoProps { - nextStep: () => void; + form: UseFormReturn; prevStep: () => void; } -const StepTwo = ({ nextStep, prevStep }: IStepTwoProps) => ( +const StepTwo = ({ form, 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 = { diff --git a/libs/ui/src/molecules/input-field/input-field.tsx b/libs/ui/src/molecules/input-field/input-field.tsx index 72c6910..d7b4901 100644 --- a/libs/ui/src/molecules/input-field/input-field.tsx +++ b/libs/ui/src/molecules/input-field/input-field.tsx @@ -75,7 +75,7 @@ export const InputField: FC = ({ {...rest} /> {error ? ( -

{error}

+

{error}

) : ( helperText && (