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

198 lines
5.5 KiB
TypeScript

import { useRef, useState } from 'react';
import { AuthenticationCard } from '../AuthenticationCard';
import { ArrowLeft, Edit2, Eye, EyeSlash } from 'iconsax-react';
import {
Box,
Button,
IconButton,
Stack,
TextField,
Typography,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import type { AuthType } from '../../types/authTypes';
import type { CountryCode, GUID } from '@/types/commonTypes';
import {
loginWithPassword,
sendEmailOtp,
sendSmsOtp,
} from '../../api/authorizationAPI';
import type { LoginResult, PasswordLoginRequest } from '../../types/userTypes';
import { Icon, useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import { useAuth } from '@/hooks/useAuth';
import { generateTokenWithPassword } from '../../api/identityAPI';
export interface EnterPasswordFormProps {
onEditValue: () => void;
onLoginWithOTP: () => void;
onLoggedIn: (loginResult: LoginResult) => void;
emailOrPhone: string;
authType: AuthType;
loginRegisterValue: string;
countryCode: CountryCode;
authReturnUrl: string;
}
export const EnterPasswordForm = ({
onEditValue,
onLoginWithOTP,
onLoggedIn,
emailOrPhone,
authType,
loginRegisterValue,
countryCode,
authReturnUrl,
}: EnterPasswordFormProps) => {
const { t } = useTranslation('authentication');
const [passValue, setPassValue] = useState<string>('');
const [inputTouched, setInputTouched] = useState<boolean>(false);
const [showPassword, setShowPassword] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const toast = useToast();
const { loading: smsResendLoading, execute: smsResendCall } =
useApi(sendSmsOtp);
const { loading: emailResendLoading, execute: emailResendCall } =
useApi(sendEmailOtp);
const { loading: loginWithPassLoading, execute: loginWithPassCall } =
useApi(loginWithPassword);
const auth = useAuth();
const handleBlur = () => {
setInputTouched(true);
};
const handleSubmit = async () => {
if (!passValue) {
inputRef.current?.focus();
} else {
const apiRequest: PasswordLoginRequest = {
phoneNumber:
authType === 'phone' ? countryCode + loginRegisterValue : undefined,
email: authType === 'email' ? loginRegisterValue : undefined,
password: passValue,
returnUrl: authReturnUrl,
};
const res = await loginWithPassCall(apiRequest);
if (!res) return;
if (res.success) {
const tokenRes = await generateTokenWithPassword({
username: apiRequest.email ?? (apiRequest.phoneNumber as string),
password: apiRequest.password,
});
auth.login({
...tokenRes.data,
});
onLoggedIn(res);
toast({
message: t('verify.youHaveSuccessfullyLoggedIn'),
severity: 'success',
});
} else {
toast({
message: res.message,
severity: 'error',
});
}
}
};
const handleLoginWithOtp = async () => {
if (authType === 'phone') {
await smsResendCall({ phoneNumber: countryCode + loginRegisterValue });
} else {
await emailResendCall({ email: loginRegisterValue });
}
onLoginWithOTP();
};
return (
<AuthenticationCard>
<Box
sx={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 4,
mb: 0.5,
}}
>
<Typography variant="h5">
{t('enterPassword.loginWithPassword')}
</Typography>
<Button
variant="outlined"
size="large"
sx={{ width: 'auto' }}
endIcon={<Icon Component={Edit2} />}
onClick={onEditValue}
>
{emailOrPhone}
</Button>
</Box>
<Typography variant="body2" color="textSecondary" sx={{ mt: 1, mb: 2 }}>
{t('enterPassword.enterThePasswordYouSetForYourAccount')}
</Typography>
<TextField
label={t('enterPassword.loginPassword')}
type={showPassword ? 'text' : 'password'}
value={passValue}
inputRef={inputRef}
onChange={(e) => setPassValue(e.target.value)}
onBlur={handleBlur}
error={!passValue && inputTouched}
helperText={
!passValue && inputTouched ? t('loginForm.thisFieldIsRequired') : ''
}
autoFocus
slotProps={{
htmlInput: { sx: { lineHeight: 1.5 } },
input: {
endAdornment: (
<IconButton
color="primary"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<Icon Component={Eye} />
) : (
<Icon Component={EyeSlash} />
)}
</IconButton>
),
},
}}
sx={{ my: 4 }}
/>
<Button
onClick={handleLoginWithOtp}
sx={{ width: 'auto', mb: 2 }}
variant="text"
loading={emailResendLoading || smsResendLoading}
endIcon={<Icon Component={ArrowLeft} />}
>
{t('enterPassword.loginWithOneTimeCode')}
</Button>
<Stack spacing={1}>
<Button loading={loginWithPassLoading} onClick={handleSubmit}>
{t('verify.confirmAndLogin')}
</Button>
<Link to="/forget-password">
<Button variant="text">{t('enterPassword.iForgotMyPassword')}</Button>
</Link>
</Stack>
</AuthenticationCard>
);
};