fix: styles and add responsiveness
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
"allowedFormat": "Allowed formats: PNG, JPEG, GIF (maximum 10 MB)",
|
"allowedFormat": "Allowed formats: PNG, JPEG, GIF (maximum 10 MB)",
|
||||||
"uploadPicture": "Upload image",
|
"uploadPicture": "Upload image",
|
||||||
"phoneNumberText": "Your new contact number will replace your previous contact number.",
|
"phoneNumberText": "Your new contact number will replace your previous contact number.",
|
||||||
"verb": "."
|
"verb": ".",
|
||||||
|
"notDetermined": "Not determined"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"allowedFormat": "فرمتهای مجاز: PNG، JPEG، GIF (حداکثر ۱۰ مگابایت)",
|
"allowedFormat": "فرمتهای مجاز: PNG، JPEG، GIF (حداکثر ۱۰ مگابایت)",
|
||||||
"uploadPicture": "بارگذاری تصویر",
|
"uploadPicture": "بارگذاری تصویر",
|
||||||
"phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی",
|
"phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی",
|
||||||
"verb": "خواهد شد"
|
"verb": "خواهد شد",
|
||||||
|
"notDetermined": "تعیین نشده"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ export function CardContainer({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
xs: '100%',
|
xs: '100%',
|
||||||
sm: '500pxpx',
|
sm: '500px',
|
||||||
md: '786px',
|
md: '818px',
|
||||||
},
|
},
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
px: { xs: 2, sm: 3, md: 4 },
|
px: { xs: 2, sm: 3, md: 4 },
|
||||||
py: 2,
|
// py: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
@@ -1,25 +1,16 @@
|
|||||||
import {
|
import { Box, Button } from '@mui/material';
|
||||||
Box,
|
import { useState } from 'react';
|
||||||
Typography,
|
|
||||||
Button,
|
|
||||||
TextField,
|
|
||||||
FormControl,
|
|
||||||
Select,
|
|
||||||
MenuItem,
|
|
||||||
Avatar,
|
|
||||||
Autocomplete,
|
|
||||||
type SelectChangeEvent,
|
|
||||||
} from '@mui/material';
|
|
||||||
import { useState, type ChangeEvent } from 'react';
|
|
||||||
import { CardContainer } from '@/components/CardContainer';
|
|
||||||
import { CountryFlag, countryCodeMap } from '@/components/CountryFlag';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Camera } from 'iconsax-react';
|
import { CardContainer } from '@/components/CardContainer';
|
||||||
|
import { ProfileImage } from './personlInformation/ProfileImage';
|
||||||
|
import { InfoRowDisplay } from './personlInformation/InfoRowDisplay';
|
||||||
|
import { InfoRowEdit } from './personlInformation/InfoRowEdit';
|
||||||
|
|
||||||
export function PersonalInformation() {
|
export function PersonalInformation() {
|
||||||
const { t } = useTranslation('profileSetting');
|
const { t } = useTranslation('profileSetting');
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [gender, setGender] = useState('');
|
const [gender, setGender] = useState('');
|
||||||
|
const [uploadedImageUrl, setUploadedImageUrl] = useState<string | null>(null);
|
||||||
|
|
||||||
const initialData = {
|
const initialData = {
|
||||||
firstName: 'محمد حسین',
|
firstName: 'محمد حسین',
|
||||||
@@ -29,15 +20,8 @@ export function PersonalInformation() {
|
|||||||
nationalCode: '',
|
nationalCode: '',
|
||||||
};
|
};
|
||||||
const [data, setData] = useState(initialData);
|
const [data, setData] = useState(initialData);
|
||||||
const [uploadedImageUrl, setUploadedImageUrl] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const initials = `${data.firstName?.trim()[0] || ''}${data.lastName?.trim()[0] || ''}`;
|
||||||
const { name, value } = e.target;
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleEdit = () => {
|
const toggleEdit = () => {
|
||||||
setIsEditing((prev) => !prev);
|
setIsEditing((prev) => !prev);
|
||||||
@@ -53,30 +37,13 @@ export function PersonalInformation() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeGender = (e: SelectChangeEvent) => {
|
|
||||||
setGender(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const displayValue = (value: string | null | undefined) => {
|
|
||||||
return value && value.trim() !== '' ? value : 'تعیین نشده';
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const file = e.target.files?.[0];
|
|
||||||
if (file) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
setUploadedImageUrl(reader.result as string);
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const initials = `${data.firstName?.trim()[0] || ''}${data.lastName?.trim()[0] || ''}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<CardContainer
|
<CardContainer
|
||||||
title={t('settingForm.titlePersonalInfo')}
|
title={t('settingForm.titlePersonalInfo')}
|
||||||
@@ -130,199 +97,39 @@ export function PersonalInformation() {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
|
// width: '754px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isEditing && (
|
{isEditing && (
|
||||||
<Box
|
<ProfileImage
|
||||||
sx={{
|
initials={initials}
|
||||||
display: 'flex',
|
uploadedImageUrl={uploadedImageUrl}
|
||||||
alignItems: 'center',
|
onImageChange={(e) => {
|
||||||
gap: 2,
|
const file = e.target.files?.[0];
|
||||||
flexWrap: 'wrap',
|
if (file) {
|
||||||
}}
|
const reader = new FileReader();
|
||||||
>
|
reader.onload = () =>
|
||||||
<Avatar
|
setUploadedImageUrl(reader.result as string);
|
||||||
sx={{
|
reader.readAsDataURL(file);
|
||||||
bgcolor: 'secondary.main',
|
|
||||||
width: 88,
|
|
||||||
height: 88,
|
|
||||||
fontSize: '20px',
|
|
||||||
}}
|
|
||||||
src={uploadedImageUrl || undefined}
|
|
||||||
>
|
|
||||||
{initials}
|
|
||||||
</Avatar>
|
|
||||||
<Box>
|
|
||||||
<Typography variant="body1">
|
|
||||||
{t('settingForm.profilePicture')}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body2" color="text.secondary">
|
|
||||||
{t('settingForm.allowedFormat')}
|
|
||||||
</Typography>
|
|
||||||
<Box mt={1}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
component="label"
|
|
||||||
sx={{
|
|
||||||
borderRadius: 2,
|
|
||||||
textTransform: 'none',
|
|
||||||
height: '30px',
|
|
||||||
fontSize: '13px',
|
|
||||||
}}
|
|
||||||
startIcon={<Camera size={18} color="white" />}
|
|
||||||
>
|
|
||||||
{t('settingForm.uploadPicture')}
|
|
||||||
<input
|
|
||||||
hidden
|
|
||||||
accept="image/png, image/jpeg, image/gif"
|
|
||||||
type="file"
|
|
||||||
onChange={handleImageChange}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>
|
|
||||||
{[
|
|
||||||
{
|
|
||||||
name: 'firstName',
|
|
||||||
label: t('settingForm.name'),
|
|
||||||
value: data.firstName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'lastName',
|
|
||||||
label: t('settingForm.familyName'),
|
|
||||||
value: data.lastName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'nationalCode',
|
|
||||||
label: t('settingForm.nationalCode'),
|
|
||||||
value: data.nationalCode,
|
|
||||||
},
|
|
||||||
].map((field, index) => (
|
|
||||||
<Box
|
|
||||||
key={index}
|
|
||||||
sx={{
|
|
||||||
width: {
|
|
||||||
xs: '100%',
|
|
||||||
sm: '48%',
|
|
||||||
md: 'calc(50% - 8px)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isEditing ? (
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
name={field.name}
|
|
||||||
value={field.value}
|
|
||||||
onChange={handleChange}
|
|
||||||
label={field.label}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Box sx={{ px: 2 }}>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
{field.label}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body1" color="text.primary">
|
|
||||||
{displayValue(field.value)}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: {
|
|
||||||
xs: '100%',
|
|
||||||
sm: '48%',
|
|
||||||
md: 'calc(50% - 8px)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isEditing ? (
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<Select
|
|
||||||
value={gender}
|
|
||||||
onChange={handleChangeGender}
|
|
||||||
displayEmpty
|
|
||||||
renderValue={(selected) => {
|
|
||||||
if (!selected) {
|
|
||||||
return (
|
|
||||||
<span style={{ color: '#aaa' }}>
|
|
||||||
{t('settingForm.genderPlaceholder')}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return selected === 'male'
|
|
||||||
? t('settingForm.man')
|
|
||||||
: t('settingForm.woman');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuItem value="male">{t('settingForm.man')}</MenuItem>
|
|
||||||
<MenuItem value="female">{t('settingForm.woman')}</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
) : (
|
|
||||||
<Box sx={{ px: 2 }}>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
{t('settingForm.gender')}
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="body1" color="text.primary">
|
|
||||||
{displayValue(data.gender)}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{isEditing && (
|
|
||||||
<Autocomplete
|
|
||||||
sx={{
|
|
||||||
width: {
|
|
||||||
xs: '100%',
|
|
||||||
sm: '48%',
|
|
||||||
md: 'calc(50% - 8px)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
options={Object.keys(countryCodeMap)}
|
|
||||||
value={data.country}
|
|
||||||
onChange={(_, newValue) =>
|
|
||||||
setData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
country: newValue || '',
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
renderOption={(props, option) => (
|
}}
|
||||||
<Box component="li" {...props}>
|
/>
|
||||||
<CountryFlag country={option} />
|
)}
|
||||||
</Box>
|
{isEditing ? (
|
||||||
)}
|
<InfoRowEdit
|
||||||
renderInput={(params) => (
|
data={data}
|
||||||
<TextField {...params} label={t('settingForm.country')} />
|
setData={setData}
|
||||||
)}
|
gender={gender}
|
||||||
/>
|
setGender={setGender}
|
||||||
)}
|
/>
|
||||||
|
) : (
|
||||||
{!isEditing && (
|
<InfoRowDisplay
|
||||||
<Box
|
data={data}
|
||||||
sx={{
|
uploadedImageUrl={uploadedImageUrl}
|
||||||
px: 2,
|
initials={initials}
|
||||||
width: {
|
/>
|
||||||
xs: '100%',
|
)}
|
||||||
sm: '48%',
|
|
||||||
md: 'calc(50% - 8px)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
{t('settingForm.country')}
|
|
||||||
</Typography>
|
|
||||||
<CountryFlag country={data.country} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export function PhoneNumber() {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
px: 2,
|
px: 2,
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContainer
|
<CardContainer
|
||||||
@@ -104,7 +105,9 @@ export function PhoneNumber() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<Box sx={{ px: { xs: 2, sm: 4 } }}>
|
<Box
|
||||||
|
sx={{ px: { xs: 2, sm: 4 }, backgroundColor: 'background.paper' }}
|
||||||
|
>
|
||||||
<Box sx={{ mb: 2 }}>
|
<Box sx={{ mb: 2 }}>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
{t('settingForm.editPhoneNumber')}
|
{t('settingForm.editPhoneNumber')}
|
||||||
@@ -120,6 +123,7 @@ export function PhoneNumber() {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
|
height: '88px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -128,7 +132,7 @@ export function PhoneNumber() {
|
|||||||
type="tel"
|
type="tel"
|
||||||
value={phoneNumber}
|
value={phoneNumber}
|
||||||
onChange={handlePhoneNumberChange}
|
onChange={handlePhoneNumberChange}
|
||||||
sx={{ flex: 1, minWidth: '250px' }}
|
sx={{ flex: 1, minWidth: '250px', mb: 2 }}
|
||||||
placeholder="09123456789"
|
placeholder="09123456789"
|
||||||
inputProps={{
|
inputProps={{
|
||||||
dir: 'rtl',
|
dir: 'rtl',
|
||||||
@@ -169,25 +173,28 @@ export function PhoneNumber() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Box sx={{}}>
|
||||||
variant="text"
|
<Button
|
||||||
onClick={handleSendCode}
|
variant="text"
|
||||||
disabled={buttonState === 'counting'}
|
onClick={handleSendCode}
|
||||||
sx={{
|
disabled={buttonState === 'counting'}
|
||||||
textTransform: 'none',
|
sx={{
|
||||||
minWidth: '170px',
|
textTransform: 'none',
|
||||||
color: 'primary.main',
|
minWidth: '170px',
|
||||||
}}
|
color: 'primary.main',
|
||||||
>
|
height: '56px',
|
||||||
{buttonState === 'counting' ? (
|
}}
|
||||||
<CountDownTimer
|
>
|
||||||
initialSeconds={60}
|
{buttonState === 'counting' ? (
|
||||||
onComplete={() => setButtonState('default')}
|
<CountDownTimer
|
||||||
/>
|
initialSeconds={60}
|
||||||
) : (
|
onComplete={() => setButtonState('default')}
|
||||||
t('settingForm.verificationCodeButton')
|
/>
|
||||||
)}
|
) : (
|
||||||
</Button>
|
t('settingForm.verificationCodeButton')
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -198,6 +205,7 @@ export function PhoneNumber() {
|
|||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
mt: 2,
|
mt: 2,
|
||||||
|
height: '88px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -221,6 +229,7 @@ export function PhoneNumber() {
|
|||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
minWidth: '170px',
|
minWidth: '170px',
|
||||||
backgroundColor: 'primary.main',
|
backgroundColor: 'primary.main',
|
||||||
|
height: '56px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isVerifying ? (
|
{isVerifying ? (
|
||||||
@@ -229,6 +238,10 @@ export function PhoneNumber() {
|
|||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
animation: 'spin 1s linear infinite',
|
animation: 'spin 1s linear infinite',
|
||||||
|
'@keyframes spin': {
|
||||||
|
'0%': { transform: 'rotate(0deg)' },
|
||||||
|
'100%': { transform: 'rotate(360deg)' },
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Refresh size="20" color="white" />
|
<Refresh size="20" color="white" />
|
||||||
@@ -249,7 +262,7 @@ export function PhoneNumber() {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
py: 1,
|
height: '148px',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export function SocialMedia() {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
px: 2,
|
px: 2,
|
||||||
|
backgroundColor: 'background.paper',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContainer
|
<CardContainer
|
||||||
@@ -155,7 +156,6 @@ export function SocialMedia() {
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: 'background.paper',
|
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
p: { xs: 1, sm: 2 },
|
p: { xs: 1, sm: 2 },
|
||||||
}}
|
}}
|
||||||
@@ -170,8 +170,6 @@ export function SocialMedia() {
|
|||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
py: 1,
|
py: 1,
|
||||||
gap: 1,
|
gap: 1,
|
||||||
borderBottom:
|
|
||||||
index !== emailList.length - 1 ? '1px solid #eee' : 'none',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||||
@@ -209,7 +207,6 @@ export function SocialMedia() {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
// backgroundColor: 'background.paper',
|
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
gap: 1,
|
gap: 1,
|
||||||
@@ -258,7 +255,7 @@ export function SocialMedia() {
|
|||||||
sx={{
|
sx={{
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
backgroundColor: '#1976d2',
|
// backgroundColor: '#1976d2',
|
||||||
}}
|
}}
|
||||||
disabled={emailError || emailInput === ''}
|
disabled={emailError || emailInput === ''}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Box, Typography } from '@mui/material';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export function DisplayField({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation('profileSetting');
|
||||||
|
const displayValue = value?.trim() || t('settingForm.notDetermined');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{label}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" color="text.primary">
|
||||||
|
{displayValue}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { Box, Typography, Avatar } from '@mui/material';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { CountryFlag } from '@/components/CountryFlag';
|
||||||
|
import { DisplayField } from './DisplayField';
|
||||||
|
|
||||||
|
export function InfoRowDisplay({
|
||||||
|
data,
|
||||||
|
uploadedImageUrl,
|
||||||
|
initials,
|
||||||
|
}: {
|
||||||
|
data: any;
|
||||||
|
uploadedImageUrl: string | null;
|
||||||
|
initials: string;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation('profileSetting');
|
||||||
|
|
||||||
|
const displayValue = (value: string) =>
|
||||||
|
value?.trim() || t('settingForm.notDetermined');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', sm: 'row' },
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
alignItems: { xs: 'flex-start', sm: 'center' },
|
||||||
|
gap: { xs: 2, sm: 1 },
|
||||||
|
px: 2,
|
||||||
|
mb: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '337px',
|
||||||
|
// maxWidth: '337px',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
src={uploadedImageUrl || undefined}
|
||||||
|
sx={{
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
bgcolor: 'secondary.main',
|
||||||
|
fontSize: '16px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{initials}
|
||||||
|
</Avatar>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{t('settingForm.name')} و {t('settingForm.familyName')}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1" color="text.primary">
|
||||||
|
{`${displayValue(data.firstName)} ${displayValue(data.lastName)}`}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{t('settingForm.country')}
|
||||||
|
</Typography>
|
||||||
|
<CountryFlag country={data.country} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', sm: 'row' },
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 2,
|
||||||
|
px: 6,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DisplayField
|
||||||
|
label={t('settingForm.gender')}
|
||||||
|
value={displayValue(data.gender)}
|
||||||
|
/>
|
||||||
|
<DisplayField
|
||||||
|
label={t('settingForm.nationalCode')}
|
||||||
|
value={displayValue(data.nationalCode)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
TextField,
|
||||||
|
FormControl,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
Autocomplete,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { CountryFlag, countryCodeMap } from '@/components/CountryFlag';
|
||||||
|
|
||||||
|
export function InfoRowEdit({ data, setData, gender, setGender }: any) {
|
||||||
|
const { t } = useTranslation('profileSetting');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
name: 'firstName',
|
||||||
|
label: t('settingForm.name'),
|
||||||
|
value: data.firstName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lastName',
|
||||||
|
label: t('settingForm.familyName'),
|
||||||
|
value: data.lastName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nationalCode',
|
||||||
|
label: t('settingForm.nationalCode'),
|
||||||
|
value: data.nationalCode,
|
||||||
|
},
|
||||||
|
].map((field, idx) => (
|
||||||
|
<Box
|
||||||
|
key={idx}
|
||||||
|
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name={field.name}
|
||||||
|
value={field.value}
|
||||||
|
onChange={(e) =>
|
||||||
|
setData((prev: any) => ({
|
||||||
|
...prev,
|
||||||
|
[field.name]: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
label={field.label}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Box sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<Select
|
||||||
|
value={gender}
|
||||||
|
onChange={(e) => setGender(e.target.value)}
|
||||||
|
displayEmpty
|
||||||
|
renderValue={(selected) =>
|
||||||
|
selected ? (
|
||||||
|
selected === 'male' ? (
|
||||||
|
t('settingForm.man')
|
||||||
|
) : (
|
||||||
|
t('settingForm.woman')
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<span style={{ color: '#aaa' }}>
|
||||||
|
{t('settingForm.genderPlaceholder')}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuItem value="male">{t('settingForm.man')}</MenuItem>
|
||||||
|
<MenuItem value="female">{t('settingForm.woman')}</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Autocomplete
|
||||||
|
sx={{ width: { xs: '100%', sm: '48%', md: 'calc(50% - 8px)' } }}
|
||||||
|
options={Object.keys(countryCodeMap)}
|
||||||
|
value={data.country}
|
||||||
|
onChange={(_, newValue) =>
|
||||||
|
setData((prev: any) => ({ ...prev, country: newValue || '' }))
|
||||||
|
}
|
||||||
|
renderOption={(props, option) => (
|
||||||
|
<Box component="li" {...props}>
|
||||||
|
<CountryFlag country={option} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField {...params} label={t('settingForm.country')} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { Box, Avatar, Typography, Button } from '@mui/material';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Camera } from 'iconsax-react';
|
||||||
|
|
||||||
|
export function ProfileImage({
|
||||||
|
initials,
|
||||||
|
uploadedImageUrl,
|
||||||
|
onImageChange,
|
||||||
|
}: {
|
||||||
|
initials: string;
|
||||||
|
uploadedImageUrl: string | null;
|
||||||
|
onImageChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation('profileSetting');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{ display: 'flex', alignItems: 'center', gap: 2, flexWrap: 'wrap' }}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
bgcolor: 'secondary.main',
|
||||||
|
width: 88,
|
||||||
|
height: 88,
|
||||||
|
fontSize: '20px',
|
||||||
|
}}
|
||||||
|
src={uploadedImageUrl || undefined}
|
||||||
|
>
|
||||||
|
{initials}
|
||||||
|
</Avatar>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body1">
|
||||||
|
{t('settingForm.profilePicture')}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{t('settingForm.allowedFormat')}
|
||||||
|
</Typography>
|
||||||
|
<Box mt={1}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
component="label"
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
height: '30px',
|
||||||
|
fontSize: '13px',
|
||||||
|
}}
|
||||||
|
startIcon={<Camera size={18} color="white" />}
|
||||||
|
>
|
||||||
|
{t('settingForm.uploadPicture')}
|
||||||
|
<input
|
||||||
|
hidden
|
||||||
|
accept="image/png, image/jpeg, image/gif"
|
||||||
|
type="file"
|
||||||
|
onChange={onImageChange}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user