feat: add navigation to forger password page, show password icon, toasts for different situations and changes of some styles
This commit is contained in:
@@ -6,123 +6,175 @@ import {
|
||||
MenuItem,
|
||||
Select,
|
||||
Autocomplete,
|
||||
FormHelperText,
|
||||
} from '@mui/material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { countries } from '@/data/countries';
|
||||
import { Gender } from '@/features/profile/types/settingsType';
|
||||
import { type InfoRowEditProps } from '@/features/profile/types/settingsType';
|
||||
import ReactCountryFlag from 'react-country-flag';
|
||||
import { useState, forwardRef, useImperativeHandle } from 'react';
|
||||
|
||||
export function InfoRowEdit({ data, setData }: InfoRowEditProps) {
|
||||
const { t } = useTranslation(['countries', 'setting']);
|
||||
export const InfoRowEdit = forwardRef(
|
||||
({ data, setData }: InfoRowEditProps, ref) => {
|
||||
const { t } = useTranslation(['country', 'setting']);
|
||||
const [touched, setTouched] = useState({
|
||||
firstName: false,
|
||||
lastName: false,
|
||||
gender: false,
|
||||
country: false,
|
||||
});
|
||||
|
||||
const countryOptions = countries.map((c) => ({
|
||||
code: c.code,
|
||||
label: t(c.label, { ns: 'countries' }),
|
||||
}));
|
||||
const isValidName = (str: string) => /[A-Za-z\u0600-\u06FF]+/.test(str);
|
||||
|
||||
const currentCountry =
|
||||
countryOptions.find((c) => c.code === data.country) || null;
|
||||
const fields = [
|
||||
{
|
||||
name: 'firstName' as const,
|
||||
label: t('settingForm.name', { ns: 'setting' }),
|
||||
value: data.firstName,
|
||||
},
|
||||
{
|
||||
name: 'lastName' as const,
|
||||
label: t('settingForm.familyName', { ns: 'setting' }),
|
||||
value: data.lastName,
|
||||
},
|
||||
{
|
||||
name: 'nationalCode' as const,
|
||||
label: t('settingForm.nationalCode', { ns: 'setting' }),
|
||||
value: data.nationalCode,
|
||||
},
|
||||
];
|
||||
useImperativeHandle(ref, () => ({
|
||||
validateFields: () => {
|
||||
const newTouched = {
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
gender: true,
|
||||
country: true,
|
||||
};
|
||||
setTouched(newTouched);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
||||
{fields.map(({ name, label, value }) => (
|
||||
<Box
|
||||
key={name}
|
||||
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||
>
|
||||
<TextField
|
||||
fullWidth
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={(e) =>
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
[name]: e.target.value,
|
||||
}))
|
||||
}
|
||||
label={label}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
return (
|
||||
data.firstName.trim() !== '' &&
|
||||
isValidName(data.firstName) &&
|
||||
data.lastName.trim() !== '' &&
|
||||
isValidName(data.lastName) &&
|
||||
data.gender !== Gender.None &&
|
||||
data.country !== ''
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
<Box sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>
|
||||
{t('settingForm.genderPlaceholder', { ns: 'setting' })}
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={data.gender === Gender.None ? '' : data.gender}
|
||||
label={t('settingForm.genderPlaceholder', { ns: 'setting' })}
|
||||
onChange={(e) =>
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
gender: e.target.value as Gender,
|
||||
}))
|
||||
}
|
||||
const countryOptions = countries.map((c) => ({
|
||||
code: c.code,
|
||||
label: t(c.label, { ns: 'country' }),
|
||||
}));
|
||||
const currentCountry =
|
||||
countryOptions.find((c) => c.code === data.country) || null;
|
||||
|
||||
const fields = [
|
||||
{
|
||||
name: 'firstName' as const,
|
||||
label: t('settingForm.name', { ns: 'setting' }),
|
||||
value: data.firstName,
|
||||
},
|
||||
{
|
||||
name: 'lastName' as const,
|
||||
label: t('settingForm.familyName', { ns: 'setting' }),
|
||||
value: data.lastName,
|
||||
},
|
||||
{
|
||||
name: 'nationalCode' as const,
|
||||
label: t('settingForm.optionalNationalCode', { ns: 'setting' }),
|
||||
value: data.nationalCode,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
||||
{fields.map(({ name, label, value }) => (
|
||||
<Box
|
||||
key={name}
|
||||
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||
>
|
||||
<MenuItem value={Gender.Male}>
|
||||
{t('settingForm.man', { ns: 'setting' })}
|
||||
</MenuItem>
|
||||
<MenuItem value={Gender.Female}>
|
||||
{t('settingForm.woman', { ns: 'setting' })}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
|
||||
<Autocomplete
|
||||
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||
options={countryOptions}
|
||||
getOptionLabel={(option) => option.label}
|
||||
value={currentCountry}
|
||||
onChange={(_, newValue) =>
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
country: newValue?.code || '',
|
||||
}))
|
||||
}
|
||||
renderOption={(props, option) => (
|
||||
<Box component="li" {...props} key={option.code}>
|
||||
<ReactCountryFlag
|
||||
countryCode={option.code}
|
||||
svg
|
||||
style={{
|
||||
height: '1.5rem',
|
||||
width: '1.5rem',
|
||||
// TODO: Check alignment for better styling definition
|
||||
marginTop: '-2px',
|
||||
marginRight: '4px',
|
||||
}}
|
||||
<TextField
|
||||
fullWidth
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={(e) =>
|
||||
setData((prev) => ({ ...prev, [name]: e.target.value }))
|
||||
}
|
||||
label={label}
|
||||
error={
|
||||
name !== 'nationalCode' &&
|
||||
touched[name] &&
|
||||
(value.trim() === '' || !isValidName(value))
|
||||
}
|
||||
helperText={
|
||||
name !== 'nationalCode' &&
|
||||
touched[name] &&
|
||||
(value.trim() === '' || !isValidName(value))
|
||||
? t('settingForm.thisFieldIsRequired', { ns: 'setting' })
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
{option.label}
|
||||
</Box>
|
||||
)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label={t('settingForm.country', { ns: 'setting' })}
|
||||
/>
|
||||
)}
|
||||
clearOnEscape
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
))}
|
||||
|
||||
<Box sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}>
|
||||
<FormControl
|
||||
fullWidth
|
||||
error={touched.gender && data.gender === Gender.None}
|
||||
>
|
||||
<InputLabel>
|
||||
{t('settingForm.genderPlaceholder', { ns: 'setting' })}
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={data.gender === Gender.None ? '' : data.gender}
|
||||
label={t('settingForm.genderPlaceholder', { ns: 'setting' })}
|
||||
onChange={(e) =>
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
gender: e.target.value as Gender,
|
||||
}))
|
||||
}
|
||||
>
|
||||
<MenuItem value={Gender.Male}>
|
||||
{t('settingForm.man', { ns: 'setting' })}
|
||||
</MenuItem>
|
||||
<MenuItem value={Gender.Female}>
|
||||
{t('settingForm.woman', { ns: 'setting' })}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{touched.gender && data.gender === Gender.None
|
||||
? t('settingForm.thisFieldIsRequired', { ns: 'setting' })
|
||||
: ''}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Box>
|
||||
|
||||
<Autocomplete
|
||||
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||
options={countryOptions}
|
||||
getOptionLabel={(option) => option.label}
|
||||
value={currentCountry}
|
||||
onChange={(_, newValue) =>
|
||||
setData((prev) => ({ ...prev, country: newValue?.code || '' }))
|
||||
}
|
||||
renderOption={(props, option) => (
|
||||
<Box
|
||||
component="li"
|
||||
{...props}
|
||||
key={option.code}
|
||||
sx={{ gap: 1, alignItems: 'center' }}
|
||||
>
|
||||
<ReactCountryFlag
|
||||
countryCode={option.code}
|
||||
svg
|
||||
style={{ height: '1.5rem', width: '1.5rem' }}
|
||||
/>
|
||||
{option.label}
|
||||
</Box>
|
||||
)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label={t('settingForm.country', { ns: 'setting' })}
|
||||
error={touched.country && data.country === ''}
|
||||
helperText={
|
||||
touched.country && data.country === ''
|
||||
? t('settingForm.thisFieldIsRequired', { ns: 'setting' })
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
)}
|
||||
clearOnEscape
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user