Files
Account/src/features/authentication/components/AuthenticationSteps/VerifyPhoneNumber.tsx

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>
);
}