chore: phone number validation added
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user