feat: OTP Resend

This commit is contained in:
boboiazumi
2025-05-30 14:19:36 +07:00
parent 935d23887c
commit a7cf85dd66
8 changed files with 103 additions and 4 deletions
@@ -0,0 +1,10 @@
import { useSendOTP } from '@imphnen-frontend-service/utils';
export const useResendOtpHook = () => {
const { resendOTP, isLoading } = useSendOTP();
return {
resendOTP
};
};
@@ -1,12 +1,38 @@
import { FC, ReactElement } from 'react';
import { FC, ReactElement, useEffect, useState } from 'react';
import { ControlledInputField, RegisterResetBanner } from "@imphnen-frontend-service/ui/organisms";
import { useOtpHook } from '../../../_hooks/use-otp';
import { Button } from '@imphnen-frontend-service/ui/atoms';
import { useSearchParams } from 'react-router-dom';
import { useResendOtpHook } from '../../../_hooks/use-resend-otp';
export const Components: FC = (): ReactElement => {
const { form, onSubmit, isLoading } = useOtpHook()
const [ searchParams ] = useSearchParams()
const [ disabled, setDisabled] = useState(true);
const [ timeLeft, setTimeLeft ] = useState(5 * 60);
const { resendOTP } = useResendOtpHook()
useEffect(() => {
if (disabled) {
const interval = setInterval(() => {
setTimeLeft(prev => {
if (prev <= 1) {
clearInterval(interval);
setDisabled(false);
return 0;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}
}, [disabled]);
const formatTime = (seconds: number) => {
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return `${m}:${s.toString().padStart(2, '0')}`;
};
return (
<div className='flex flex-col justify-center items-center min-h-screen py-[60px] px-[80px]'>
@@ -26,6 +52,13 @@ export const Components: FC = (): ReactElement => {
maxLength={6}
control={form.control}
/>
<Button type="button" className="mt-2" disabled={disabled} onClick={
() => {
resendOTP({email: searchParams.get("email") || ""})
setDisabled(true)
setTimeLeft(5 * 60)
}
}>Kirim ulang otp {disabled? `(${formatTime(timeLeft)})`: ""}</Button>
<Button className="xl:w-full mt-2" disabled={(!form.formState.isValid || isLoading)}>Linked Start !!!</Button>
</form>
</div>
+1 -1
View File
@@ -10,7 +10,7 @@ const mappingPublicRoutes = [
'/auth/login',
'/auth/forgot',
'/auth/forgot/otp',
'/auth/register',
'/auth/register',
'/auth/register/otp',
'/auth/register/success',
'/auth/new-password',
+12
View File
@@ -3,6 +3,7 @@ import {
TLoginRequest,
TLoginResponse,
TRegisterRequest,
TSendOTPRequest,
TVerifyEmailRequest,
} from '../../types/auth';
import { TResponseMessage } from '../../types/common';
@@ -39,3 +40,14 @@ export const postVerifyEmail = async (
});
return data;
};
export const postSendOtp = async (
payload: TSendOTPRequest
): Promise<TResponseMessage> => {
const { data } = await api({
method: 'POST',
url: '/auth/send-otp',
data: payload,
});
return data;
};
+15 -1
View File
@@ -1,9 +1,10 @@
import { useMutation, UseMutationResult } from '@tanstack/react-query';
import { postLogin, postRegister, postVerifyEmail } from '../../api/auth';
import { postLogin, postRegister, postSendOtp, postVerifyEmail } from '../../api/auth';
import {
TLoginRequest,
TLoginResponse,
TRegisterRequest,
TSendOTPRequest,
TVerifyEmailRequest,
} from '../../types/auth';
@@ -44,3 +45,16 @@ export const usePostVerifyEmail = (): UseMutationResult<
mutationFn: async (payload) => await postVerifyEmail(payload),
});
};
export const usePostSendOTP = (): UseMutationResult<
TResponseMessage,
TResponseError,
TSendOTPRequest,
unknown
> => {
return useMutation({
mutationKey: ['post-send-otp'],
mutationFn: async (payload) => await postSendOtp(payload),
});
};
+4
View File
@@ -27,3 +27,7 @@ export type TVerifyEmailRequest = {
email: string;
otp: string;
};
export type TSendOTPRequest = {
email: string
};
+2 -1
View File
@@ -3,4 +3,5 @@ export * from './use-auth-store';
export * from './use-modal-login';
export * from './use-session';
export * from './use-register';
export * from './use-otp';
export * from './use-otp';
export * from './use-send-otp';
+25
View File
@@ -0,0 +1,25 @@
import { TSendOTPRequest, usePostSendOTP } from '@imphnen-frontend-service/service';
import { toast } from 'sonner';
export const useSendOTP = () => {
const { mutate, isPending } = usePostSendOTP();
const resendOTP = (payload: TSendOTPRequest) => {
mutate(payload, {
onSuccess: (data) => {
toast.success('Berhasil Mengirim Ulang OTP');
},
onError: (err) => {
toast.error(
err?.response?.data?.message ??
'Terjadi Kesalahan yang tidak diketahui'
);
},
});
};
return {
resendOTP,
isLoading: isPending,
};
};