resend
This commit is contained in:
@@ -15,6 +15,7 @@ import { useParams } from 'next/navigation'
|
||||
import { toast } from '@/components/Toast'
|
||||
import StepOtp from './StepOtp'
|
||||
import { extractErrorMessage } from '@/lib/func'
|
||||
import { useCountdown } from '@/hooks/useCountdown'
|
||||
|
||||
type StepEnterNumberProps = {
|
||||
pending?: boolean
|
||||
@@ -29,6 +30,10 @@ function StepEnterNumber(_props: StepEnterNumberProps = {}) {
|
||||
const { name } = useParams()
|
||||
const [step, setStep] = useState(AUTH_STEP.ENTER_NUMBER)
|
||||
const { mutate: mutateOtpRequest, isPending } = useOtpRequest()
|
||||
const { timerRunning, secondsLeft, restart } = useCountdown(
|
||||
step === AUTH_STEP.ENTER_OTP,
|
||||
120
|
||||
)
|
||||
|
||||
|
||||
const formik = useFormik<LoginOTPRequestType>({
|
||||
@@ -56,6 +61,22 @@ function StepEnterNumber(_props: StepEnterNumberProps = {}) {
|
||||
}
|
||||
})
|
||||
|
||||
const handleResendOtp = () => {
|
||||
if (timerRunning || !name) return
|
||||
|
||||
mutateOtpRequest(
|
||||
{ phone: formik.values.phone, slug: name as string },
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast(t('otp_sent'), 'success')
|
||||
restart()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast(extractErrorMessage(error), 'error')
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -100,7 +121,14 @@ function StepEnterNumber(_props: StepEnterNumberProps = {}) {
|
||||
/>
|
||||
)}
|
||||
{step === AUTH_STEP.ENTER_OTP && (
|
||||
<StepOtp phone={formik.values.phone} slug={formik.values.slug} />
|
||||
<StepOtp
|
||||
phone={formik.values.phone}
|
||||
slug={(name as string) || formik.values.slug}
|
||||
timerRunning={timerRunning}
|
||||
secondsLeft={secondsLeft}
|
||||
onResend={handleResendOtp}
|
||||
isResendPending={isPending}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{
|
||||
|
||||
@@ -22,6 +22,15 @@ type Props = {
|
||||
pending?: boolean | undefined
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'id'>
|
||||
|
||||
const formatCountdown = (seconds: number) => {
|
||||
const mins = Math.floor(seconds / 60)
|
||||
const secs = seconds % 60
|
||||
if (mins > 0) {
|
||||
return `${mins}:${String(secs).padStart(2, '0')}`
|
||||
}
|
||||
return String(seconds)
|
||||
}
|
||||
|
||||
function StepEnterOtp ({
|
||||
onChange,
|
||||
onClick,
|
||||
@@ -87,10 +96,7 @@ function StepEnterOtp ({
|
||||
<div>
|
||||
{timerRunning ? (
|
||||
<div>
|
||||
{t('OTP.TimerRunning').replace(
|
||||
'{seconds}',
|
||||
String(secondsLeft)
|
||||
)}
|
||||
{t('OTP.TimerRunning', { time: formatCountdown(secondsLeft) })}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
|
||||
@@ -12,14 +12,28 @@ import { useReceiptStore } from '@/zustand/receiptStore'
|
||||
import { useBulkCart } from '@/app/[name]/(Main)/cart/hooks/useCartData'
|
||||
import { setRefreshToken, setToken } from '@/lib/api/func'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
import { AUTH_PAGE_ELEMENT } from '@/enums'
|
||||
import clsx from 'clsx'
|
||||
|
||||
type Props = {
|
||||
phone: string,
|
||||
phone: string
|
||||
slug: string
|
||||
timerRunning: boolean
|
||||
secondsLeft: number
|
||||
onResend: () => void
|
||||
isResendPending?: boolean
|
||||
}
|
||||
|
||||
const StepOtp = ({ phone, slug }: Props) => {
|
||||
const formatCountdown = (seconds: number) => {
|
||||
const mins = Math.floor(seconds / 60)
|
||||
const secs = seconds % 60
|
||||
if (mins > 0) {
|
||||
return `${mins}:${String(secs).padStart(2, '0')}`
|
||||
}
|
||||
return String(seconds)
|
||||
}
|
||||
|
||||
const StepOtp = ({ phone, slug, timerRunning, secondsLeft, onResend, isResendPending }: Props) => {
|
||||
const searchParams = useSearchParams()
|
||||
const redirectUrl = searchParams.get('redirect')
|
||||
const { t } = useTranslation('auth')
|
||||
@@ -89,23 +103,51 @@ const StepOtp = ({ phone, slug }: Props) => {
|
||||
}
|
||||
})
|
||||
return (
|
||||
<div className='mt-6 sm:mt-8 dltr otp'>
|
||||
<OTPInput
|
||||
shouldAutoFocus
|
||||
value={formik.values.otp}
|
||||
numInputs={5}
|
||||
inputType='tel'
|
||||
containerStyle={{ direction: 'ltr' }}
|
||||
onChange={(otp: string) => formik.setFieldValue('otp', otp)}
|
||||
renderInput={(props) =>
|
||||
<input
|
||||
{...props}
|
||||
type='tel'
|
||||
autoComplete="one-time-code"
|
||||
inputMode="numeric"
|
||||
className='w-full h-[45px] sm:h-[50px] flex-1 mx-1 sm:mx-2 bg-container border border-border text-foreground outline-0 rounded-[10px] text-center text-sm' />
|
||||
}
|
||||
/>
|
||||
<>
|
||||
<div className='mt-6 sm:mt-8 dltr otp'>
|
||||
<OTPInput
|
||||
shouldAutoFocus
|
||||
value={formik.values.otp}
|
||||
numInputs={5}
|
||||
inputType='tel'
|
||||
containerStyle={{ direction: 'ltr' }}
|
||||
onChange={(otp: string) => formik.setFieldValue('otp', otp)}
|
||||
renderInput={(props) =>
|
||||
<input
|
||||
{...props}
|
||||
type='tel'
|
||||
autoComplete="one-time-code"
|
||||
inputMode="numeric"
|
||||
className='w-full h-[45px] sm:h-[50px] flex-1 mx-1 sm:mx-2 bg-container border border-border text-foreground outline-0 rounded-[10px] text-center text-sm' />
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='text-center w-full pt-6 text-xs'>
|
||||
{timerRunning ? (
|
||||
<div>
|
||||
{t('OTP.TimerRunning', { time: formatCountdown(secondsLeft) })}
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{t('OTP.TimerOut')}
|
||||
<button
|
||||
type='button'
|
||||
disabled={isResendPending}
|
||||
id={AUTH_PAGE_ELEMENT.RESEND_OTP}
|
||||
className={clsx(
|
||||
'px-1 transition-colors duration-200',
|
||||
!isResendPending
|
||||
? 'text-primary cursor-pointer'
|
||||
: 'text-neutral-200 cursor-auto'
|
||||
)}
|
||||
onClick={onResend}
|
||||
>
|
||||
{t('OTP.TimerReset')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className='mt-10 dark:bg-white dark:text-black hover:dark:bg-white'
|
||||
@@ -116,7 +158,7 @@ const StepOtp = ({ phone, slug }: Props) => {
|
||||
>
|
||||
{t('OTP.ButtonSubmit')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"Heading": "Enter Activation Code",
|
||||
"Description": "Please enter the 6-digit code sent to the number {{phoneNumber}}.",
|
||||
"Label": "",
|
||||
"TimerRunning": "{seconds} seconds left to receive the code",
|
||||
"TimerRunning": "Resend available in {{time}}",
|
||||
"TimerOut": "Didn’t receive the code?",
|
||||
"TimerReset": "Try again",
|
||||
"TimerReset": "Resend",
|
||||
"ButtonSubmit": "Next"
|
||||
},
|
||||
"NewPassword": {
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"Heading": "کد فعالسازی را وارد کنید",
|
||||
"Description": "کد ۵ رقمی ارسال شده به شماره {{phoneNumber}} را وارد نمایید.",
|
||||
"Label": "",
|
||||
"TimerRunning": "{seconds} ثانیه دیگر تا دریافت کد",
|
||||
"TimerRunning": "ارسال مجدد تا {{time}} دیگر",
|
||||
"TimerOut": "کد را دریافت نکردید؟",
|
||||
"TimerReset": "دوباره امتحان کنید",
|
||||
"TimerReset": "ارسال مجدد",
|
||||
"ButtonSubmit": "بعدی"
|
||||
},
|
||||
"NewPassword": {
|
||||
|
||||
Reference in New Issue
Block a user