feat: login with password form added

This commit is contained in:
مهرزاد قدرتی
2025-07-29 13:06:39 +03:30
parent ab223af15b
commit bd34468332
5 changed files with 183 additions and 27 deletions

View File

@@ -7,24 +7,31 @@
"loginWithGoogle": "Login with google",
"emailIsInvalid": "Email is invalid",
"phoneNumberIsInvalid": "Phone number is invalid",
"thisFieldIsRequired": "This field is requried",
"verify": {
"verify": "Verify",
"a4DigitVerificationCodeHasBeenSentToYourBobileNumberPleaseEnterIt": "A 4-digit verification code has been sent to your mobile number. Please enter it.",
"thereIsNoAccountWithThisNumberA4DigitVerificationCodeHasBeenSentToThisNumberToCreateANewAccount": "There is no account with this number. A 4-digit verification code has been sent to this number to create a new account.",
"a4digitVerificationCodeHasBeenSentToYourEmailAddressPleaseEnterIt": "A 4-digit verification code has been sent to your email address. Please enter it.",
"thereIsNoAccountWithThisEmailAddressA4DigitVerificationCodeHasBeenSentToThisEmailAddressToCreateANewAccount": "There is no account with this email address. A 4-digit verification code has been sent to this email address to create a new account.",
"theVerificationCodeIsIncorrect": "The verification code is incorrect.",
"youHaveSuccessfullyLoggedIn": "You have successfully logged in",
"youHaveSuccessfullySignedIn": "You have successfully signed in",
"resendCodeIn": "Resend code in",
"moreMinute": "minute",
"resendCode": "Resend code"
},
"completeSignUp": {
"completeSignUp": "Complete Sign Up",
"emailHasBeenSuccessfullyVerifiedPleaseEnterYourContactNumberToContinue": "Email {{ email }} has been successfully verified. Please enter your contact number to continue.",
"phoneNumber": "Phone number"
}
"thisFieldIsRequired": "This field is requried"
},
"verify": {
"verify": "Verify",
"a4DigitVerificationCodeHasBeenSentToYourBobileNumberPleaseEnterIt": "A 4-digit verification code has been sent to your mobile number. Please enter it.",
"thereIsNoAccountWithThisNumberA4DigitVerificationCodeHasBeenSentToThisNumberToCreateANewAccount": "There is no account with this number. A 4-digit verification code has been sent to this number to create a new account.",
"a4digitVerificationCodeHasBeenSentToYourEmailAddressPleaseEnterIt": "A 4-digit verification code has been sent to your email address. Please enter it.",
"thereIsNoAccountWithThisEmailAddressA4DigitVerificationCodeHasBeenSentToThisEmailAddressToCreateANewAccount": "There is no account with this email address. A 4-digit verification code has been sent to this email address to create a new account.",
"theVerificationCodeIsIncorrect": "The verification code is incorrect.",
"youHaveSuccessfullyLoggedIn": "You have successfully logged in",
"youHaveSuccessfullySignedIn": "You have successfully signed in",
"resendCodeIn": "Resend code in",
"moreMinute": "minute",
"resendCode": "Resend code"
},
"completeSignUp": {
"completeSignUp": "Complete Sign Up",
"emailHasBeenSuccessfullyVerifiedPleaseEnterYourContactNumberToContinue": "Email {{ email }} has been successfully verified. Please enter your contact number to continue.",
"phoneNumber": "Phone number"
},
"enterPassword": {
"loginWithPassword": "Login with password",
"enterThePasswordYouSetForYourAccount": "Enter the password you set for your account.",
"loginPassword": "Login password",
"loginWithOneTimeCode": "Login with one-time code",
"iForgotMyPassword": "I forgot my password."
}
}

View File

@@ -28,5 +28,12 @@
"completeSignUp": "تکمیل ثبت نام",
"emailHasBeenSuccessfullyVerifiedPleaseEnterYourContactNumberToContinue": "ایمیل {{ email }} با موفقیت تایید شد. برای ادامه لطفا شماره تماس خود را وارد کنید",
"phoneNumber": "شماره تماس"
},
"enterPassword": {
"loginWithPassword": "ورود با رمز",
"enterThePasswordYouSetForYourAccount": "رمز ورودی که برای اکانت خود تعیین کردید را وارد کنید",
"loginPassword": "رمز ورود",
"loginWithOneTimeCode": "ورود با کد یکبار مصرف",
"iForgotMyPassword": "رمز ورودم را فراموش کردم"
}
}

View File

@@ -7,7 +7,7 @@ export const AuthenticationCard = ({ children }: PropsWithChildren) => {
<Paper
elevation={0}
sx={{
bor: 2,
borderRadius: 4,
p: 6,
width: '34.5rem',
}}

View File

@@ -23,7 +23,13 @@ export const AuthenticationContainer = (): JSX.Element => {
const handleLoginRegister = (value: string) => {
setLoginRegisterValue(value);
setAuthType(isNumeric(value) ? 'phone' : 'email');
setCurrentStep('verify');
// TODO: after api: send to password if it has account and has password
if (true) {
setCurrentStep('enterPassword');
} else {
setCurrentStep('verify');
}
};
const handleOTPVerfied = (otpCode: string) => {
@@ -45,9 +51,11 @@ export const AuthenticationContainer = (): JSX.Element => {
};
const handleCompleteSignUpEditValue = () => {
setCurrentStep('addPhoneNumber');
setCurrentStep('emailOrPassword');
};
const handleLoggedInWithPassowrd = () => {};
return (
<>
{currentStep === 'emailOrPassword' && (
@@ -72,7 +80,9 @@ export const AuthenticationContainer = (): JSX.Element => {
{currentStep === 'enterPassword' && (
<EnterPasswordForm
onLoginWithPassword={() => {}}
onLoggedIn={handleLoggedInWithPassowrd}
onEditValue={handleEditValue}
onLoginWithOTP={() => setCurrentStep('verify')}
emailOrPhone={loginRegisterValue}
/>
)}

View File

@@ -1,14 +1,146 @@
import React from 'react';
import React, { useRef, useState } from 'react';
import { AuthenticationCard } from './AuthenticationCard';
import { ArrowLeft, Edit2, Eye, EyeSlash, MaskLeft } from 'iconsax-reactjs';
import {
Box,
Button,
IconButton,
Stack,
TextField,
Typography,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { Toast } from '@/components/Toast';
export interface EnterPasswordFormProps {
onLoginWithPassword: () => void;
onEditValue: () => void;
onLoginWithOTP: () => void;
onLoggedIn: () => void;
emailOrPhone: string;
}
export const EnterPasswordForm = ({
onLoginWithPassword,
onEditValue,
onLoginWithOTP,
onLoggedIn,
emailOrPhone,
}: EnterPasswordFormProps) => {
return <AuthenticationCard></AuthenticationCard>;
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 [loginLoading, setLoginLoading] = useState<boolean>(false);
const [loginStatus, setLoginStatus] = useState<'success' | 'failed'>();
const [loginAlertOpen, setLoginAlertOpen] = useState<boolean>(false);
const [loginFailedMessage, setLoginFailedMessage] = useState<string>('');
const handleBlur = () => {
setInputTouched(true);
};
const handleSubmit = () => {
if (!passValue) {
inputRef.current?.focus();
} else {
setLoginLoading(true);
// Change setTimeout to api call
setTimeout(() => {
setLoginAlertOpen(true);
// setLoginStatus('success');
setLoginStatus('failed');
setLoginFailedMessage('رمز عبور اشتباه میباشد');
onLoggedIn();
setLoginLoading(false);
}, 1000);
}
};
return (
<AuthenticationCard>
<Toast
open={loginAlertOpen}
onClose={() => setLoginAlertOpen(false)}
color={loginStatus === 'failed' ? 'error' : 'success'}
>
{loginStatus === 'failed'
? loginFailedMessage
: t('verify.youHaveSuccessfullyLoggedIn')}
</Toast>
<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={{ textTransform: 'lowercase', width: 'auto' }}
endIcon={<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 ? <Eye /> : <EyeSlash />}
</IconButton>
),
},
}}
sx={{ my: 4 }}
/>
<Button
onClick={onLoginWithOTP}
sx={{ width: 'auto', mb: 2 }}
variant="text"
endIcon={<ArrowLeft />}
>
{t('enterPassword.loginWithOneTimeCode')}
</Button>
<Stack spacing={1}>
<Button loading={loginLoading} onClick={handleSubmit}>
{t('verify.confirmAndLogin')}
</Button>
<Button variant="text">{t('enterPassword.iForgotMyPassword')}</Button>
</Stack>
</AuthenticationCard>
);
};