diff --git a/package-lock.json b/package-lock.json index fcab9b1..d0ad8a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3150,6 +3150,7 @@ "react": "*" } }, + "node_modules/iconsax-reactjs": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/iconsax-reactjs/-/iconsax-reactjs-0.0.8.tgz", @@ -3160,6 +3161,7 @@ "react": "*" } }, + "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", diff --git a/public/locales/en/profileSetting.json b/public/locales/en/profileSetting.json new file mode 100644 index 0000000..cbc6846 --- /dev/null +++ b/public/locales/en/profileSetting.json @@ -0,0 +1,42 @@ +{ + "settingForm": { + "titlePersonalInfo": "My Personal Information", + "descriptionPersonalInfo": "This information is only for your identification and remains with Harmony.", + "titlePhoneNumber": "My phone number", + "descriptionPhoneNumber": "This information is only for your identification and remains with Harmony.", + "titleSocial": "My email and social medias", + "descriptionSocial": "This information is only for your identification and remains with Harmony.", + "rejectButton": "Cancel", + "saveButton": "Save", + "editButton": "Edit", + "editPhoneNumber": "Change phone number", + "addEmailOrSocialButton": "Add email / social", + "addEmailButton": "Add email", + "name": "Name", + "familyName": "Family Name", + "country": "Country", + "gender": "Gender", + "nationalCode": "National code", + "man": "Male", + "woman": "Female", + "genderPlaceholder": "Male", + "newPhoneNumber": "New phone number", + "verificationCodeButton": "Send verification code", + "verificationCode": "Verification code", + "checkCode": "Check code", + "successButton": "Confirmed", + "email": "Email", + "apple": "Apple", + "google": "Google", + "newEmail": "New email", + "dialogHeader": "By activating your email, you can use this email to log in the next time you log in.", + "or": "Or", + "emailError": "Please enter a valid email.", + "profilePicture": "User account image", + "allowedFormat": "Allowed formats: PNG, JPEG, GIF (maximum 10 MB)", + "uploadPicture": "Upload image", + "phoneNumberText": "Your new contact number will replace your previous contact number.", + "verb": ".", + "notDetermined": "Not determined" + } +} diff --git a/public/locales/fa/profileSetting.json b/public/locales/fa/profileSetting.json new file mode 100644 index 0000000..d1942d0 --- /dev/null +++ b/public/locales/fa/profileSetting.json @@ -0,0 +1,43 @@ +{ + "settingForm": { + "titlePersonalInfo": "اطلاعات شخصی من", + "descriptionPersonalInfo": "این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی می‌ماند", + "titlePhoneNumber": "شماره تماس من", + "descriptionPhoneNumber": "این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی می‌ماند", + "titleSocial": "ایمیل و شبکه های اجتماعی من", + "descriptionSocial": "این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی می‌ماند", + "rejectButton": "لغو", + "saveButton": "ذخیره", + "editButton": "ویرایش", + "editPhoneNumber": "تغییر شماره تماس", + "addEmailOrSocialButton": "افزودن ایمیل / سوشال", + "addEmailButton": "افزودن ایمیل", + "name": "نام", + "familyName": "نام خانوادگی", + "country": "کشور", + "gender": "جنسیت", + "nationalCode": "کد ملی", + "man": "مرد", + "woman": "زن", + "genderPlaceholder": "مرد", + "newPhoneNumber": "شماره تماس جدید", + "verificationCodeButton": "ارسال کد تایید", + "verificationCode": "کد تایید", + "checkCode": "بررسی کد", + "successButton": "تایید شد", + "email": "ایمیل", + "apple": "اپل", + "google": "گوگل", + "newEmail": "ایمیل جدید", + "dialogHeader": "با فعال‌سازی ایمیل می‌توانید در دفعات بعدی ورود برای ورود از این ایمیل استفاده کنید", + "or": "یا", + "emailError": "لطفا یک ایمیل معتبر وارد کنید", + "profilePicture": "تصویر حساب کاربری", + "allowedFormat": "فرمت‌های مجاز: PNG، JPEG، GIF (حداکثر ۱۰ مگابایت)", + "uploadPicture": "بارگذاری تصویر", + "phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی", + "verb": "خواهد شد", + "notDetermined": "تعیین نشده", + "successfulChangePhone": "شماره تماس با موفقیت تغییر کرد" + } +} diff --git a/src/App.tsx b/src/App.tsx index 50ac647..b1c1097 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,25 +1,19 @@ import { CssBaseline, useColorScheme } from '@mui/material'; import './App.css'; import { LanguageManager } from './components/LanguageManager'; -import { Settings } from './features/profile/Settings'; + function App() { return ( <> - {/* */} - {/* */} - - {/* - - */} + {/*
{t('helloWorld')} - diff --git a/src/components/CountDownTimer.tsx b/src/components/CountDownTimer.tsx new file mode 100644 index 0000000..655fa9b --- /dev/null +++ b/src/components/CountDownTimer.tsx @@ -0,0 +1,39 @@ +import { useState, useEffect } from 'react'; + +interface CountdownTimerProps { + initialSeconds: number; + onComplete?: () => void; +} + +export function CountDownTimer({ + initialSeconds, + onComplete, +}: CountdownTimerProps) { + const [secondsLeft, setSecondsLeft] = useState(initialSeconds); + + useEffect(() => { + setSecondsLeft(initialSeconds); + }, [initialSeconds]); + + useEffect(() => { + if (secondsLeft <= 0) { + onComplete?.(); + return; + } + const timer = setInterval(() => { + setSecondsLeft((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + }, [secondsLeft, onComplete]); + + const toPersianDigits = (str: string) => + str.replace(/\d/g, (d: string) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]); + + const formatTime = (totalSeconds: number) => { + const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, '0'); + const seconds = String(totalSeconds % 60).padStart(2, '0'); + return toPersianDigits(`${minutes}:${seconds}`); + }; + + return {formatTime(secondsLeft)}; +} diff --git a/src/components/Countries.tsx b/src/components/Countries.tsx new file mode 100644 index 0000000..ee4f74a --- /dev/null +++ b/src/components/Countries.tsx @@ -0,0 +1,40 @@ +// components/Countries.ts + +export interface Country { + name: string; + fa: string; + flag: string; +} + +export const countries: Country[] = [ + { name: 'Afghanistan', fa: 'افغانستان', flag: 'af' }, + { name: 'Albania', fa: 'آلبانی', flag: 'al' }, + { name: 'Algeria', fa: 'الجزایر', flag: 'dz' }, + { name: 'Argentina', fa: 'آرژانتین', flag: 'ar' }, + { name: 'Armenia', fa: 'ارمنستان', flag: 'am' }, + { name: 'Australia', fa: 'استرالیا', flag: 'au' }, + { name: 'Austria', fa: 'اتریش', flag: 'at' }, + { name: 'Bahrain', fa: 'بحرین', flag: 'bh' }, + { name: 'Canada', fa: 'کانادا', flag: 'ca' }, + { name: 'China', fa: 'چین', flag: 'cn' }, + { name: 'France', fa: 'فرانسه', flag: 'fr' }, + { name: 'Germany', fa: 'آلمان', flag: 'de' }, + { name: 'India', fa: 'هند', flag: 'in' }, + { name: 'Iran', fa: 'ایران', flag: 'ir' }, + { name: 'Iraq', fa: 'عراق', flag: 'iq' }, + { name: 'Italy', fa: 'ایتالیا', flag: 'it' }, + { name: 'Japan', fa: 'ژاپن', flag: 'jp' }, + { name: 'Netherlands', fa: 'هلند', flag: 'nl' }, + { name: 'Pakistan', fa: 'پاکستان', flag: 'pk' }, + { name: 'Qatar', fa: 'قطر', flag: 'qa' }, + { name: 'Russia', fa: 'روسیه', flag: 'ru' }, + { name: 'Saudi Arabia', fa: 'عربستان سعودی', flag: 'sa' }, + { name: 'Spain', fa: 'اسپانیا', flag: 'es' }, + { name: 'Sweden', fa: 'سوئد', flag: 'se' }, + { name: 'Switzerland', fa: 'سوئیس', flag: 'ch' }, + { name: 'Turkey', fa: 'ترکیه', flag: 'tr' }, + { name: 'United Arab Emirates', fa: 'امارات متحده عربی', flag: 'ae' }, + { name: 'United Kingdom', fa: 'بریتانیا', flag: 'gb' }, + { name: 'United States', fa: 'ایالات متحده آمریکا', flag: 'us' }, + { name: 'Yemen', fa: 'یمن', flag: 'ye' }, +]; diff --git a/src/components/CountryFlag.tsx b/src/components/CountryFlag.tsx new file mode 100644 index 0000000..b7be516 --- /dev/null +++ b/src/components/CountryFlag.tsx @@ -0,0 +1,46 @@ +import { Box, Typography } from '@mui/material'; + +export const countryCodeMap: { [key: string]: string } = { + ایران: 'ir', + قطر: 'qa', + آلمان: 'de', + آمریکا: 'us', + فرانسه: 'fr', + ایتالیا: 'it', + اسپانیا: 'es', + انگلیس: 'gb', + کانادا: 'ca', + استرالیا: 'au', + چین: 'cn', + ژاپن: 'jp', + هند: 'in', + روسیه: 'ru', + برزیل: 'br', + آرژانتین: 'ar', + ترکیه: 'tr', + سوئیس: 'ch', + سوئد: 'se', + نروژ: 'no', + عربستان: 'sa', + امارات: 'ae', + عراق: 'iq', + پاکستان: 'pk', +}; + +export function CountryFlag({ country }: { country: string }) { + const countryCode = countryCodeMap[country] || 'un'; + const flagUrl = `https://flagcdn.com/w40/${countryCode}.png`; + + return ( + + {country} + {country} + + ); +} diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx index 713c36f..0f0927e 100644 --- a/src/components/Toast.tsx +++ b/src/components/Toast.tsx @@ -1,6 +1,8 @@ import { Alert, Snackbar, type AlertColor } from '@mui/material'; + import { type PropsWithChildren } from 'react'; + export interface ToastProps extends PropsWithChildren { color: AlertColor | undefined; open: boolean; diff --git a/src/features/authentication/components/UserCompletionForm.tsx b/src/features/authentication/components/UserCompletionForm.tsx new file mode 100644 index 0000000..7f71c92 --- /dev/null +++ b/src/features/authentication/components/UserCompletionForm.tsx @@ -0,0 +1,353 @@ +import { + TextField, + FormControl, + InputLabel, + MenuItem, + Select, + Box, + type SelectChangeEvent, + Switch, + FormGroup, + Button, + Typography, + Link, +} from '@mui/material'; +import React, { useEffect, useState } from 'react'; + +export function UserCompletionForm() { + const [sex, setSex] = useState(''); + const [showPassword, setShowPassword] = useState(false); + const [showEmail, setShowEmail] = useState(false); + const [password, setPassword] = useState(''); + const [email, setEmail] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [codeSent, setCodeSent] = useState(false); + const [verificationCode, setVerificationCode] = useState(''); + const [buttonState, setButtonState] = useState('default'); // default | counting | sent + const [countdown, setCountdown] = useState(60); + const matchPassword = password === confirmPassword; + const hasNumber = /\d/.test(password); + const hasMinLength = password.length >= 8; + const hasUpperAndLower = /[A-Z]/.test(password) && /[a-z]/.test(password); + const hasSpecialChar = /[!@#$%^&*]/.test(password); + const correctEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + + const handleTogglePassword = (e: React.ChangeEvent) => { + setShowPassword(e.target.checked); + }; + const handleToggleEmail = (e: React.ChangeEvent) => { + setShowEmail(e.target.checked); + }; + + const handleChange = (e: SelectChangeEvent) => { + setSex(e.target.value); + }; + + const onClickCodeSent = () => { + setCodeSent(true); + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(60); + }, 1000); + }; + + useEffect(() => { + let timer: ReturnType; + if (buttonState === 'counting' && countdown > 0) { + timer = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + } + if (countdown === 0) { + setButtonState('default'); + } + return () => clearInterval(timer); + }, [buttonState, countdown]); + + const toPersianDigits = (str: string) => + str.replace(/\d/g, (d: string) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]); + + const getButtonLabel = () => { + if (buttonState === 'sent') return 'ارسال شد!'; + if (buttonState === 'counting') { + const minutes = String(Math.floor(countdown / 60)).padStart(2, '0'); + const seconds = String(countdown % 60).padStart(2, '0'); + const time = `${minutes}:${seconds}`; + return toPersianDigits(time); + } + return 'ارسال کد تایید'; + }; + + return ( +
+ + + + تکمیل اطلاعات حساب کاربری + + + اطلاعات کسب و کار خود را وارد کنید + + + + + + + + + جنسیت + + + + + + + + + تعیین رمز عبور + + + {showPassword && ( + + + setPassword(e.target.value)} + variant="outlined" + sx={{ + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + {password && ( + + + شامل عدد + +
+ + حداقل 8 کاراکتر + +
+ + شامل یک حرف بزرگ و کوچک + +
+ + شامل علامت(!@#$%^&*) + +
+ )} +
+ {showPassword && ( + setConfirmPassword(e.target.value)} + error={confirmPassword.length > 0 && !matchPassword} + helperText={ + confirmPassword.length > 0 && !matchPassword + ? 'مطابقت ندارد' + : ' ' + } + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + )} +
+ )} + + + + + اتصال ایمیل خود + + + {showEmail && ( + + + + setEmail(e.target.value)} + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + {email && ( + + فرم درست ایمیل وارد کنید + + )} + + + + {codeSent && ( + + setVerificationCode(e.target.value)} + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + + + )} + + )} + + + ادامه فرایند ثبت نام به منزله تایید و قبول{' '} + + قوانین و مقررات هارمونی + {' '} + می باشد. + + + +
+
+ ); +} diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx new file mode 100644 index 0000000..d06b551 --- /dev/null +++ b/src/features/profile/components/PersonalInformation.tsx @@ -0,0 +1,129 @@ +import React, { useState } from 'react'; +import { Box, Button } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { CardContainer } from '@/components/CardContainer'; +import { ProfileImage } from './personlInformation/ProfileImage'; +import { InfoRowDisplay } from './personlInformation/InfoRowDisplay'; +import { InfoRowEdit } from './personlInformation/InfoRowEdit'; + +export function PersonalInformation() { + const { t } = useTranslation('profileSetting'); + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [uploadedImageUrl, setUploadedImageUrl] = useState(null); + + const initialData = { + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + country: 'قطر', + gender: 'مرد', + nationalCode: '', + }; + const [data, setData] = useState(initialData); + + const initials = `${data.firstName?.trim()[0] || ''}‌${data.lastName?.trim()[0] || ''}`; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + if (isEditing) { + setData((prev) => ({ + ...prev, + gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', + })); + } else { + setGender( + data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', + ); + } + }; + + return ( + + {isEditing && ( + + )} + +
+ } + > + + {isEditing && ( + { + const file = e.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = () => + setUploadedImageUrl(reader.result as string); + reader.readAsDataURL(file); + } + }} + /> + )} + + {isEditing ? ( + + ) : ( + + )} + + + ); +} diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx new file mode 100644 index 0000000..7cf2cff --- /dev/null +++ b/src/features/profile/components/PhoneNumber.tsx @@ -0,0 +1,286 @@ +import React, { useState, type ChangeEvent } from 'react'; +import { Box, Typography, Button, TextField, IconButton } from '@mui/material'; +import { Edit, Refresh, TickCircle } from 'iconsax-react'; +import { useTranslation } from 'react-i18next'; +import { CardContainer } from '@/components/CardContainer'; +import { CountDownTimer } from '@/components/CountDownTimer'; +import { Toast } from '@/components/Toast'; + +export function PhoneNumber() { + const { t } = useTranslation('profileSetting'); + const [isEditing, setIsEditing] = useState(false); + const [phoneNumber, setPhoneNumber] = useState(''); + const [verificationCode, setVerificationCode] = useState(''); + const [showToast, setShowToast] = useState(false); + const [buttonState, setButtonState] = useState<'default' | 'counting'>( + 'default', + ); + const [isVerifying, setIsVerifying] = useState(false); + const [isVerified, setIsVerified] = useState(false); + + const [phones, setPhone] = useState([ + { phone: '09123456789', time: '۱ ماه پیش', withCode: '+989123456789' }, + ]); + + const toggleEdit = () => { + setIsEditing((prev) => { + const enteringEditMode = !prev; + if (enteringEditMode) { + setPhoneNumber(''); + setVerificationCode(''); + setIsVerified(false); + setButtonState('default'); + setShowToast(false); + } + return enteringEditMode; + }); + }; + + const handlePhoneNumberChange = (e: ChangeEvent) => { + const value = e.target.value.replace(/\D/g, ''); + setPhoneNumber(value); + }; + + const handleVerificationCodeChange = (e: ChangeEvent) => { + const value = e.target.value.replace(/\D/g, ''); + setVerificationCode(value); + }; + + const handleSendCode = () => { + if (!phoneNumber) return; + setButtonState('counting'); + setIsVerified(false); + }; + + const handleVerifyCode = () => { + setIsVerifying(true); + setTimeout(() => { + setIsVerifying(false); + setIsVerified(true); + setShowToast(true); + const newPhone = '+98' + phoneNumber.slice(1); + setPhone([ + { phone: phoneNumber, time: 'چند ثانیه پیش', withCode: newPhone }, + ]); + }, 1500); + }; + + const handleVerifyClick = () => { + if (!verificationCode || isVerifying) return; + handleVerifyCode(); + setTimeout(() => setShowToast(true), 1600); + }; + + return ( + + {isEditing && ( + + )} + + + } + > + {isEditing ? ( + + + + {t('settingForm.editPhoneNumber')} + + + {t('settingForm.phoneNumberText')}({phones.map((p) => p.withCode)} + ){t('settingForm.verb')} + + + + + { + setButtonState('default'); + setPhoneNumber(''); + }} + sx={{ mr: 1 }} + > + + + ) : null, + }} + /> + + {isVerified ? ( + + + + {t('settingForm.successButton')} + + + ) : ( + + )} + + + {buttonState === 'counting' && !isVerified && ( + + + + + + )} + + setShowToast(false)} + > + {t('settingForm.successfulChangePhone')} + + + ) : ( + + {phones.map((item, index) => ( + + + {item.phone} + + + {item.time} + + + ))} + + )} + + ); +} diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx new file mode 100644 index 0000000..1d8b3ab --- /dev/null +++ b/src/features/profile/components/SocialMedia.tsx @@ -0,0 +1,331 @@ +import React, { useState } from 'react'; +import { + Box, + Button, + Typography, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, + Menu, + MenuItem, + ListItemIcon, + ListItemText, + useMediaQuery, +} from '@mui/material'; +import type { Theme } from '@mui/material/styles'; +import { useTranslation } from 'react-i18next'; +import { CardContainer } from '@/components/CardContainer'; + +import { + Google, + Apple, + Sms, + Trash, + CloseSquare, + Message, + ArrowDown3, +} from 'iconsax-react'; + +export function SocialMedia() { + const { t } = useTranslation('profileSetting'); + const [openDialog, setOpenDialog] = useState(false); + const [emailInput, setEmailInput] = useState(''); + const [emailError, setEmailError] = useState(false); + const [anchor, setAnchor] = useState(null); + const openMenu = Boolean(anchor); + const fullScreen = useMediaQuery((theme: Theme) => + theme.breakpoints.down('sm'), + ); + + const handleOpenDialog = () => setOpenDialog(true); + const handleCloseDialog = () => setOpenDialog(false); + + const handleClickMenu = (e: React.MouseEvent) => + setAnchor(e.currentTarget); + const handleCloseMenu = () => setAnchor(null); + + const handleEmailChange = (e: React.ChangeEvent) => { + const value = e.target.value; + setEmailInput(value); + setEmailError(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)); + }; + + const emailList = [ + { email: 'emailtemp@email.com', provider: 'email', time: '1 ماه پیش' }, + { email: 'emailtemp@gmail.com', provider: 'google', time: '1 ماه پیش' }, + { email: 'emailtemp@icloud.com', provider: 'apple', time: '1 ماه پیش' }, + ] as const; + + return ( + + + + + + + { + handleCloseMenu(); + handleOpenDialog(); + }} + > + + + + {t('settingForm.email')} + + + + + + {t('settingForm.google')} + + + + + + {t('settingForm.apple')} + + + + } + > + + {emailList.map((item, index) => ( + + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + + {item.email} + + + {item.time} + + + + + + + + + ))} + + + + + + + + {t('settingForm.addEmailButton')} + + + + + + + {t('settingForm.newEmail')} + + + {t('settingForm.dialogHeader')} + + + + + + + + + + + {t('settingForm.or')} + + + + + + + + + + + + + ); +} diff --git a/src/features/profile/components/UserForm.tsx b/src/features/profile/components/UserForm.tsx new file mode 100644 index 0000000..bcfd593 --- /dev/null +++ b/src/features/profile/components/UserForm.tsx @@ -0,0 +1,14 @@ +import { Box } from '@mui/material'; +import { PersonalInformation } from './PersonalInformation'; +import { PhoneNumber } from './PhoneNumber'; +import { SocialMedia } from './SocialMedia'; + +export function UserForm() { + return ( + + + + + + ); +} diff --git a/src/features/profile/components/personlInformation/DisplayField.tsx b/src/features/profile/components/personlInformation/DisplayField.tsx new file mode 100644 index 0000000..f6690fd --- /dev/null +++ b/src/features/profile/components/personlInformation/DisplayField.tsx @@ -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 ( + + + {label} + + + {displayValue} + + + ); +} diff --git a/src/features/profile/components/personlInformation/InfoRowDisplay.tsx b/src/features/profile/components/personlInformation/InfoRowDisplay.tsx new file mode 100644 index 0000000..d581865 --- /dev/null +++ b/src/features/profile/components/personlInformation/InfoRowDisplay.tsx @@ -0,0 +1,85 @@ +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 ( + + + + + {initials} + + + + {t('settingForm.name')} و {t('settingForm.familyName')} + + + {`${displayValue(data.firstName)} ${displayValue(data.lastName)}`} + + + + + + + {t('settingForm.country')} + + + + + + + + + + + ); +} diff --git a/src/features/profile/components/personlInformation/InfoRowEdit.tsx b/src/features/profile/components/personlInformation/InfoRowEdit.tsx new file mode 100644 index 0000000..5969583 --- /dev/null +++ b/src/features/profile/components/personlInformation/InfoRowEdit.tsx @@ -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 ( + + {[ + { + 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) => ( + + + setData((prev: any) => ({ + ...prev, + [field.name]: e.target.value, + })) + } + label={field.label} + /> + + ))} + + + + + + + + + setData((prev: any) => ({ ...prev, country: newValue || '' })) + } + renderOption={(props, option) => ( + + + + )} + renderInput={(params) => ( + + )} + /> + + ); +} diff --git a/src/features/profile/components/personlInformation/ProfileImage.tsx b/src/features/profile/components/personlInformation/ProfileImage.tsx new file mode 100644 index 0000000..3d848c8 --- /dev/null +++ b/src/features/profile/components/personlInformation/ProfileImage.tsx @@ -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) => void; +}) { + const { t } = useTranslation('profileSetting'); + + return ( + + + {initials} + + + + {t('settingForm.profilePicture')} + + + {t('settingForm.allowedFormat')} + + + + + + + ); +}