feat: integeration register modal

This commit is contained in:
egagofur
2025-04-03 23:32:44 +07:00
parent 585ad482f2
commit 9aff9e2dc8
5 changed files with 151 additions and 17 deletions
@@ -1,6 +1,8 @@
import { Button } from '@imphnen-frontend-service/ui/atoms'; import { Button } from '@imphnen-frontend-service/ui/atoms';
import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules'; import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules';
import { useQueryState } from '@imphnen-frontend-service/utils'; import { useQueryState } from '@imphnen-frontend-service/utils';
import { useRegister } from '../../_hooks/use-register';
import { ControlledInputField } from '@imphnen-frontend-service/ui/organisms';
interface IModalFormRegisterProps { interface IModalFormRegisterProps {
isOpen: boolean; isOpen: boolean;
@@ -8,6 +10,8 @@ interface IModalFormRegisterProps {
} }
const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => { const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => {
const { form, onSubmit } = useRegister();
const { const {
step: currentStep, step: currentStep,
nextStep, nextStep,
@@ -37,45 +41,58 @@ const ModalFormRegister = ({ isOpen, onClose }: IModalFormRegisterProps) => {
{currentStep === 1 ? 'Info Akun' : 'Informasi Pengiriman Hadiah'} {currentStep === 1 ? 'Info Akun' : 'Informasi Pengiriman Hadiah'}
</h2> </h2>
</Modal.Header> </Modal.Header>
<Modal.Content className="space-y-6"> <Modal.Content>
{currentStep === 1 && <StepOne nextStep={nextStep} onClose={onClose} />} <form onSubmit={onSubmit} className="space-y-6">
{currentStep === 2 && ( {currentStep === 1 && (
<StepTwo nextStep={nextStep} prevStep={prevStep} /> <StepOne form={form} nextStep={nextStep} onClose={onClose} />
)} )}
{currentStep === 2 && (
<StepTwo form={form} nextStep={nextStep} prevStep={prevStep} />
)}
</form>
</Modal.Content> </Modal.Content>
</Modal> </Modal>
); );
}; };
interface IStepOneProps { interface IStepOneProps {
form: any;
nextStep: () => void; nextStep: () => void;
onClose: () => void; onClose: () => void;
} }
const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( const StepOne = ({ form, nextStep, onClose }: IStepOneProps) => (
<> <>
<InputField <ControlledInputField
control={form.control}
name="fullname"
label="Nama Lengkap" label="Nama Lengkap"
placeholder="Masukkan Nama Lengkap" placeholder="Masukkan Nama Lengkap"
type="text" type="text"
size="lg" size="lg"
className="w-full" className="w-full"
/> />
<InputField <ControlledInputField
control={form.control}
label="Email" label="Email"
placeholder="Masukkan Email Anda" placeholder="Masukkan Email Anda"
type="email" type="email"
name="email"
size="lg" size="lg"
className="w-full" className="w-full"
/> />
<InputField <ControlledInputField
control={form.control}
name="password"
label="Password" label="Password"
placeholder="Masukkan Password" placeholder="Masukkan Password"
type="password" type="password"
size="lg" size="lg"
className="w-full" className="w-full"
/> />
<InputField <ControlledInputField
control={form.control}
name="confirm_password"
label="Ulangi Password" label="Ulangi Password"
placeholder="Masukkan Ulang Password" placeholder="Masukkan Ulang Password"
type="password" type="password"
@@ -89,22 +106,45 @@ const StepOne = ({ nextStep, onClose }: IStepOneProps) => (
); );
interface IStepTwoProps { interface IStepTwoProps {
form: any;
nextStep: () => void; nextStep: () => void;
prevStep: () => void; prevStep: () => void;
} }
const StepTwo = ({ nextStep, prevStep }: IStepTwoProps) => ( const StepTwo = ({ form, nextStep, prevStep }: IStepTwoProps) => (
<> <>
<InputField <ControlledInputField
control={form.control}
name="phone_number"
label="Nomor Telepon" label="Nomor Telepon"
placeholder="Masukkan Nomor Telepon Aktif" placeholder="Masukkan Nomor Telepon Aktif"
type="text" type="text"
size="lg" size="lg"
className="w-full" className="w-full"
/> />
<InputField <ControlledInputField
label="Alamat Pengiriman" control={form.control}
placeholder="Masukkan Alamat Pengiriman" name="referral_code"
label="Kode Referral"
placeholder="Masukkan Kode Referral"
type="text"
size="lg"
className="w-full"
/>
<ControlledInputField
control={form.control}
name="referred_by"
label="Referral By"
placeholder="Masukkan Referral By"
type="text"
size="lg"
className="w-full"
/>
<ControlledInputField
control={form.control}
name="student_type"
label="Tipe Pelajar"
placeholder="Masukkan Tipe Pelajar"
type="text" type="text"
size="lg" size="lg"
className="w-full" className="w-full"
@@ -113,7 +153,7 @@ const StepTwo = ({ nextStep, prevStep }: IStepTwoProps) => (
<Button size="md" variant="text" className="w-[40%]" onClick={prevStep}> <Button size="md" variant="text" className="w-[40%]" onClick={prevStep}>
Kembali Kembali
</Button> </Button>
<Button size="md" className="w-full" onClick={nextStep}> <Button size="md" className="w-full" type='submit'>
Gacha Sekarang Gacha Sekarang
</Button> </Button>
</div> </div>
+28
View File
@@ -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<TRegisterRequest>({
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,
};
};
+2
View File
@@ -8,6 +8,7 @@ import {
convertPagesToRoute, convertPagesToRoute,
QueryProvider, QueryProvider,
} from '@imphnen-frontend-service/utils'; } from '@imphnen-frontend-service/utils';
import { Toaster } from 'sonner';
import './index.css'; import './index.css';
const files = import.meta.glob('./app/**/*(page|layout).tsx'); 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( createRoot(rootElement).render(
<StrictMode> <StrictMode>
<QueryProvider> <QueryProvider>
<Toaster />
<RouterProvider router={router} /> <RouterProvider router={router} />
</QueryProvider> </QueryProvider>
</StrictMode> </StrictMode>
+59
View File
@@ -15,3 +15,62 @@ export const authLoginSchema = z.object({
}) })
.min(1, 'Password tidak boleh kosong'), .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.`,
});
}
});
+6 -1
View File
@@ -16,9 +16,14 @@ export type TLoginResponse = {
}; };
export type TRegisterRequest = { export type TRegisterRequest = {
fullname: string;
email: string; email: string;
fullname: string;
password: string; password: string;
phone_number: string;
referral_code?: string;
referred_by?: string;
student_type: string;
confirm_password: string;
}; };
export type TVerifyEmailRequest = { export type TVerifyEmailRequest = {