Merge pull request #18 from IMPHNEN/feat/register-integeration
feat: integeration register modal
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
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 { 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';
|
||||||
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
|
import { TRegisterRequest } from '@imphnen-frontend-service/service';
|
||||||
|
|
||||||
interface IModalFormRegisterProps {
|
interface IModalFormRegisterProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -8,6 +12,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 +43,56 @@ 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} prevStep={prevStep} />}
|
||||||
|
</form>
|
||||||
</Modal.Content>
|
</Modal.Content>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IStepOneProps {
|
interface IStepOneProps {
|
||||||
|
form: UseFormReturn<TRegisterRequest, any, TRegisterRequest>;
|
||||||
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,44 @@ const StepOne = ({ nextStep, onClose }: IStepOneProps) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
interface IStepTwoProps {
|
interface IStepTwoProps {
|
||||||
nextStep: () => void;
|
form: UseFormReturn<TRegisterRequest, any, TRegisterRequest>;
|
||||||
prevStep: () => void;
|
prevStep: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StepTwo = ({ nextStep, prevStep }: IStepTwoProps) => (
|
const StepTwo = ({ form, 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 +152,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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export const InputField: FC<TInputFieldProps> = ({
|
|||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
{error ? (
|
{error ? (
|
||||||
<p className="text-danger-500 text-label2 text-left">{error}</p>
|
<p className="text-danger-500 text-label1 text-left">{error}</p>
|
||||||
) : (
|
) : (
|
||||||
helperText && (
|
helperText && (
|
||||||
<p
|
<p
|
||||||
|
|||||||
Reference in New Issue
Block a user