chore: phone number validation added

This commit is contained in:
مهرزاد قدرتی
2025-07-26 13:42:18 +03:30
parent 2e10a5496c
commit 62747f6ca8
7 changed files with 451 additions and 106 deletions

View File

@@ -72,6 +72,7 @@ export function CountryCodeSelector({
() =>
countries.filter(
(country) =>
t(country.label).toLowerCase().includes(searchTerm.toLowerCase()) ||
country.label.toLowerCase().includes(searchTerm.toLowerCase()) ||
country.phone.includes(searchTerm),
),
@@ -205,7 +206,7 @@ export function CountryCodeSelector({
}}
/>
</ListItemIcon>
<ListItemText primary={country.label} />
<ListItemText primary={t(country.label)} />
<Typography color="text.secondary">
{country.phone}
</Typography>

View File

@@ -1,90 +0,0 @@
import { Box, Button, Stack, TextField, Typography } from '@mui/material';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { CountryCodeSelector } from './CountryCodeSelector';
import { Google } from 'iconsax-reactjs';
import { isNumeric } from '@/utils/regexes/isNumeric';
export function LoginForm() {
const { t, i18n } = useTranslation('authentication');
const [value, setValue] = useState('');
const [countryCode, setCountryCode] = useState('+41');
const [inputType, setInputType] = useState<'phone' | 'email'>('phone');
const textFieldRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const dir = i18n.dir();
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value;
setValue(newValue);
// If the new value contains only digits (or is empty), it's a phone number
if (isNumeric(newValue)) {
setInputType('phone');
} else {
setInputType('email');
}
};
const handleBlur = () => {
// setTouched(true);
// setError(validate(value, inputType));
};
const showAdornment = inputType === 'phone' && value.length > 0;
return (
<Box sx={{ width: '100%' }}>
<Stack spacing={1}>
<Typography variant="h5">{t('loginForm.title')}</Typography>
<Typography variant="body2" color="text.secondary">
{t('loginForm.description')}
</Typography>
</Stack>
<TextField
ref={textFieldRef}
inputRef={inputRef}
label={t('loginForm.emailOrPhoneLabel')}
value={value}
onChange={handleInputChange}
onBlur={handleBlur}
// error={touched && !!error}
autoFocus
slotProps={{
htmlInput: { dir: 'auto', sx: { lineHeight: 1.5, paddingX: 0 } },
input: {
startAdornment: dir === 'ltr' && (
<CountryCodeSelector
value={countryCode}
onChange={setCountryCode}
show={showAdornment}
menuAnchor={textFieldRef.current}
onCloseFocusRef={inputRef}
/>
),
endAdornment: dir === 'rtl' && (
<CountryCodeSelector
value={countryCode}
onChange={setCountryCode}
show={showAdornment}
menuAnchor={textFieldRef.current}
onCloseFocusRef={inputRef}
/>
),
},
}}
sx={{ my: 4 }}
/>
<Stack spacing={2}>
<Button onClick={() => inputRef.current?.focus()}>
{t('loginForm.submitButton')}
</Button>
<Button variant="outlined" startIcon={<Google variant="Bold" />}>
{t('loginForm.loginWithGoogle')}
</Button>
</Stack>
</Box>
);
}

View File

@@ -6,6 +6,7 @@ import { Google } from 'iconsax-reactjs';
import { isNumeric } from '@/utils/regexes/isNumeric';
import type { AuthMode, AuthType } from '../types/auth-types';
import { isEmail } from '@/utils/regexes/isEmail';
import parsePhoneNumberFromString from 'libphonenumber-js';
export interface LoginRegisterFormProps {
authType: AuthType;
@@ -49,13 +50,19 @@ export function LoginRegisterForm({
setError(t('loginForm.thisFieldIsRequired'));
} else if (authType === 'email' && !isEmail(value)) {
setError(t('loginForm.emailIsInvalid'));
} else if (authType === 'phone' && false /* TODO */) {
setError(t('loginForm.emailIsInvalid'));
} else if (authType === 'phone' && !isPhoneValid(countryCode, value)) {
setError(t('loginForm.phoneNumberIsInvalid'));
} else {
setError(undefined);
}
};
const isPhoneValid = (code: string, phone: string) => {
const phoneNumber = parsePhoneNumberFromString(code + phone);
return phoneNumber && phoneNumber.isValid();
};
const isInputValid = (value: string, authType: AuthType): boolean => {
if (!value) {
return false;
@@ -65,7 +72,7 @@ export function LoginRegisterForm({
return false;
}
if (authType === 'phone' && false /* TODO */) {
if (authType === 'phone' && !isPhoneValid(countryCode, value)) {
return false;
}
@@ -104,16 +111,7 @@ export function LoginRegisterForm({
slotProps={{
htmlInput: { dir: 'auto', sx: { lineHeight: 1.5, paddingX: 0 } },
input: {
startAdornment: dir === 'ltr' && (
<CountryCodeSelector
value={countryCode}
onChange={setCountryCode}
show={showAdornment}
menuAnchor={textFieldRef.current}
onCloseFocusRef={inputRef}
/>
),
endAdornment: dir === 'rtl' && (
endAdornment: (
<CountryCodeSelector
value={countryCode}
onChange={setCountryCode}