resend
This commit is contained in:
@@ -15,6 +15,7 @@ import { useParams } from 'next/navigation'
|
|||||||
import { toast } from '@/components/Toast'
|
import { toast } from '@/components/Toast'
|
||||||
import StepOtp from './StepOtp'
|
import StepOtp from './StepOtp'
|
||||||
import { extractErrorMessage } from '@/lib/func'
|
import { extractErrorMessage } from '@/lib/func'
|
||||||
|
import { useCountdown } from '@/hooks/useCountdown'
|
||||||
|
|
||||||
type StepEnterNumberProps = {
|
type StepEnterNumberProps = {
|
||||||
pending?: boolean
|
pending?: boolean
|
||||||
@@ -29,6 +30,10 @@ function StepEnterNumber(_props: StepEnterNumberProps = {}) {
|
|||||||
const { name } = useParams()
|
const { name } = useParams()
|
||||||
const [step, setStep] = useState(AUTH_STEP.ENTER_NUMBER)
|
const [step, setStep] = useState(AUTH_STEP.ENTER_NUMBER)
|
||||||
const { mutate: mutateOtpRequest, isPending } = useOtpRequest()
|
const { mutate: mutateOtpRequest, isPending } = useOtpRequest()
|
||||||
|
const { timerRunning, secondsLeft, restart } = useCountdown(
|
||||||
|
step === AUTH_STEP.ENTER_OTP,
|
||||||
|
120
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
const formik = useFormik<LoginOTPRequestType>({
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -100,7 +121,14 @@ function StepEnterNumber(_props: StepEnterNumberProps = {}) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{step === AUTH_STEP.ENTER_OTP && (
|
{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>
|
</div>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ type Props = {
|
|||||||
pending?: boolean | undefined
|
pending?: boolean | undefined
|
||||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'id'>
|
} & 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 ({
|
function StepEnterOtp ({
|
||||||
onChange,
|
onChange,
|
||||||
onClick,
|
onClick,
|
||||||
@@ -87,10 +96,7 @@ function StepEnterOtp ({
|
|||||||
<div>
|
<div>
|
||||||
{timerRunning ? (
|
{timerRunning ? (
|
||||||
<div>
|
<div>
|
||||||
{t('OTP.TimerRunning').replace(
|
{t('OTP.TimerRunning', { time: formatCountdown(secondsLeft) })}
|
||||||
'{seconds}',
|
|
||||||
String(secondsLeft)
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -12,14 +12,28 @@ import { useReceiptStore } from '@/zustand/receiptStore'
|
|||||||
import { useBulkCart } from '@/app/[name]/(Main)/cart/hooks/useCartData'
|
import { useBulkCart } from '@/app/[name]/(Main)/cart/hooks/useCartData'
|
||||||
import { setRefreshToken, setToken } from '@/lib/api/func'
|
import { setRefreshToken, setToken } from '@/lib/api/func'
|
||||||
import { useSearchParams } from 'next/navigation'
|
import { useSearchParams } from 'next/navigation'
|
||||||
|
import { AUTH_PAGE_ELEMENT } from '@/enums'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
phone: string,
|
phone: string
|
||||||
slug: 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 searchParams = useSearchParams()
|
||||||
const redirectUrl = searchParams.get('redirect')
|
const redirectUrl = searchParams.get('redirect')
|
||||||
const { t } = useTranslation('auth')
|
const { t } = useTranslation('auth')
|
||||||
@@ -89,6 +103,7 @@ const StepOtp = ({ phone, slug }: Props) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<div className='mt-6 sm:mt-8 dltr otp'>
|
<div className='mt-6 sm:mt-8 dltr otp'>
|
||||||
<OTPInput
|
<OTPInput
|
||||||
shouldAutoFocus
|
shouldAutoFocus
|
||||||
@@ -106,6 +121,33 @@ const StepOtp = ({ phone, slug }: Props) => {
|
|||||||
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' />
|
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
|
<Button
|
||||||
className='mt-10 dark:bg-white dark:text-black hover:dark:bg-white'
|
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')}
|
{t('OTP.ButtonSubmit')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
"Heading": "Enter Activation Code",
|
"Heading": "Enter Activation Code",
|
||||||
"Description": "Please enter the 6-digit code sent to the number {{phoneNumber}}.",
|
"Description": "Please enter the 6-digit code sent to the number {{phoneNumber}}.",
|
||||||
"Label": "",
|
"Label": "",
|
||||||
"TimerRunning": "{seconds} seconds left to receive the code",
|
"TimerRunning": "Resend available in {{time}}",
|
||||||
"TimerOut": "Didn’t receive the code?",
|
"TimerOut": "Didn’t receive the code?",
|
||||||
"TimerReset": "Try again",
|
"TimerReset": "Resend",
|
||||||
"ButtonSubmit": "Next"
|
"ButtonSubmit": "Next"
|
||||||
},
|
},
|
||||||
"NewPassword": {
|
"NewPassword": {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
"Heading": "کد فعالسازی را وارد کنید",
|
"Heading": "کد فعالسازی را وارد کنید",
|
||||||
"Description": "کد ۵ رقمی ارسال شده به شماره {{phoneNumber}} را وارد نمایید.",
|
"Description": "کد ۵ رقمی ارسال شده به شماره {{phoneNumber}} را وارد نمایید.",
|
||||||
"Label": "",
|
"Label": "",
|
||||||
"TimerRunning": "{seconds} ثانیه دیگر تا دریافت کد",
|
"TimerRunning": "ارسال مجدد تا {{time}} دیگر",
|
||||||
"TimerOut": "کد را دریافت نکردید؟",
|
"TimerOut": "کد را دریافت نکردید؟",
|
||||||
"TimerReset": "دوباره امتحان کنید",
|
"TimerReset": "ارسال مجدد",
|
||||||
"ButtonSubmit": "بعدی"
|
"ButtonSubmit": "بعدی"
|
||||||
},
|
},
|
||||||
"NewPassword": {
|
"NewPassword": {
|
||||||
|
|||||||
Reference in New Issue
Block a user