169 lines
4.8 KiB
TypeScript
169 lines
4.8 KiB
TypeScript
import { useTranslation } from 'react-i18next';
|
|
import { Box, Button, Stack, Typography } from '@mui/material';
|
|
import { Edit2 } from 'iconsax-react';
|
|
import DigitInput from '@/components/DigitsInput';
|
|
import { useEffect, useState } from 'react';
|
|
import { AuthenticationCard } from '../AuthenticationCard';
|
|
import type { ConfirmSmsOtpRequest } from '../../types/userTypes';
|
|
import { confirmSmsOtp, sendSmsOtp } from '../../api/authorizationAPI';
|
|
import type { CountryCode } from '@/types/commonTypes';
|
|
import { Icon, useToast } from '@rkheftan/harmony-ui';
|
|
import { useApi } from '@/hooks/useApi';
|
|
|
|
interface VerifyPhoneNumberProps {
|
|
value: string;
|
|
countryCode: CountryCode;
|
|
onEditValue: () => void;
|
|
onPhoneNumberVerified: () => void;
|
|
}
|
|
|
|
export function VerifyPhoneNumber({
|
|
value,
|
|
countryCode,
|
|
onEditValue,
|
|
onPhoneNumberVerified,
|
|
}: VerifyPhoneNumberProps) {
|
|
const [otpCode, setOtpCode] = useState<string>('');
|
|
const [otpDigitInvalid, setOtpDigitInvalid] = useState<boolean>(false);
|
|
const [isStatusSuccess, setIsStatusSuccess] = useState<boolean>();
|
|
const { t } = useTranslation('authentication');
|
|
const [resendTimer, setResendTimer] = useState<number>(120);
|
|
const [canResend, setCanResend] = useState(false);
|
|
const toast = useToast();
|
|
const { loading: smsResendLoading, execute: smsResendCall } =
|
|
useApi(sendSmsOtp);
|
|
const { loading: confirmSmsOtpLoading, execute: confirmSmsOtpCall } =
|
|
useApi(confirmSmsOtp);
|
|
|
|
useEffect(() => {
|
|
let interval: NodeJS.Timeout;
|
|
if (resendTimer > 0) {
|
|
interval = setInterval(() => {
|
|
setResendTimer((prev) => prev - 1);
|
|
}, 1000);
|
|
} else {
|
|
setCanResend(true);
|
|
}
|
|
|
|
return () => clearInterval(interval);
|
|
}, [resendTimer]);
|
|
|
|
const handleResendOTPCode = async () => {
|
|
await smsResendCall({ phoneNumber: countryCode + value });
|
|
|
|
setResendTimer(120);
|
|
setCanResend(false);
|
|
};
|
|
|
|
const formatTime = (seconds: number) => {
|
|
const min = Math.floor(seconds / 60);
|
|
const sec = seconds % 60;
|
|
return `${min}:${sec.toString().padStart(2, '0')}`;
|
|
};
|
|
|
|
const handleVerifyOTP = async () => {
|
|
if (!otpCode || otpCode.length < 4) {
|
|
setOtpDigitInvalid(true);
|
|
} else {
|
|
setOtpDigitInvalid(false);
|
|
|
|
const confirmSmsOtpRequest: ConfirmSmsOtpRequest = {
|
|
otpCode: otpCode,
|
|
phoneNumber: countryCode + value,
|
|
};
|
|
const res = await confirmSmsOtpCall(confirmSmsOtpRequest);
|
|
|
|
if (!res) return;
|
|
|
|
if (res.success) {
|
|
setIsStatusSuccess(true);
|
|
toast({
|
|
message: t('verify.youHaveSuccessfullyLoggedIn'),
|
|
severity: 'success',
|
|
});
|
|
onPhoneNumberVerified();
|
|
} else {
|
|
setIsStatusSuccess(false);
|
|
toast({
|
|
message: res.message ?? t('verify.theVerificationCodeIsIncorrect'),
|
|
severity: 'error',
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Stack alignItems="center">
|
|
<AuthenticationCard>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
gap: 4,
|
|
mb: 0.5,
|
|
}}
|
|
>
|
|
<Typography variant="h5">{t('verify.verify')}</Typography>
|
|
|
|
<Button
|
|
variant="outlined"
|
|
size="large"
|
|
sx={{ textTransform: 'lowercase', width: 'auto' }}
|
|
endIcon={<Icon Component={Edit2} />}
|
|
onClick={onEditValue}
|
|
>
|
|
{countryCode + value}
|
|
</Button>
|
|
</Box>
|
|
|
|
<Typography variant="body2" color="textSecondary" sx={{ mt: 1 }}>
|
|
{t(
|
|
'verify.a4DigitVerificationCodeHasBeenSentToYourBobileNumberPleaseEnterIt',
|
|
)}
|
|
</Typography>
|
|
|
|
<DigitInput
|
|
error={otpDigitInvalid || isStatusSuccess === false}
|
|
success={isStatusSuccess === true}
|
|
onChange={(value) => setOtpCode(value)}
|
|
/>
|
|
|
|
<Button onClick={handleVerifyOTP} loading={confirmSmsOtpLoading}>
|
|
{t('verify.confirmAndLogin')}
|
|
</Button>
|
|
</AuthenticationCard>
|
|
|
|
<Stack
|
|
direction="row"
|
|
sx={{
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
mt: 2.5,
|
|
}}
|
|
>
|
|
<Typography variant="body1">{t('verify.resendCodeIn')}</Typography>
|
|
|
|
<Typography
|
|
variant="body1"
|
|
sx={{ color: 'primary.main', marginInlineStart: 1 }}
|
|
>
|
|
{!canResend && `${formatTime(resendTimer)} ${t('verify.moreMinute')}`}
|
|
</Typography>
|
|
|
|
{canResend && (
|
|
<Button
|
|
variant="text"
|
|
loading={smsResendLoading}
|
|
sx={{ width: 'auto', p: 0 }}
|
|
onClick={canResend ? handleResendOTPCode : undefined}
|
|
>
|
|
{t('verify.resendCode')}
|
|
</Button>
|
|
)}
|
|
</Stack>
|
|
</Stack>
|
|
);
|
|
}
|