From 2d68e441e47148d8ff38624440f6061b7b0a1ec2 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:30:12 +0330 Subject: [PATCH 01/24] feat: add user completion form --- .../components/UserCompletionForm.tsx | 353 ++++++++++++++++++ .../profile/component/PersonalInformation.tsx | 229 ++++++++++++ .../profile/component/PhoneNumber.tsx | 306 +++++++++++++++ .../profile/component/SocialMedia.tsx | 210 +++++++++++ src/features/profile/component/UserForm.tsx | 13 + 5 files changed, 1111 insertions(+) create mode 100644 src/features/authentication/components/UserCompletionForm.tsx create mode 100644 src/features/profile/component/PersonalInformation.tsx create mode 100644 src/features/profile/component/PhoneNumber.tsx create mode 100644 src/features/profile/component/SocialMedia.tsx create mode 100644 src/features/profile/component/UserForm.tsx 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/component/PersonalInformation.tsx b/src/features/profile/component/PersonalInformation.tsx new file mode 100644 index 0000000..21967f1 --- /dev/null +++ b/src/features/profile/component/PersonalInformation.tsx @@ -0,0 +1,229 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function PersonalInformation() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + if (isEditing) { + setData((prev) => ({ + ...prev, + gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', + })); + } else { + setGender( + data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', + ); + } + }; + + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + {isEditing && ( + + )} + + + + + + + {isEditing ? ( + + ) : ( + + + نام + + + {displayValue(data.firstName)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + نام خانوادگی + + + {displayValue(data.lastName)} + + + )} + + + + {isEditing ? ( + + + + ) : ( + + + جنسیت + + + {displayValue(data.gender)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + کد ملی + + + {displayValue(data.nationalCode)} + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/PhoneNumber.tsx b/src/features/profile/component/PhoneNumber.tsx new file mode 100644 index 0000000..ccaff35 --- /dev/null +++ b/src/features/profile/component/PhoneNumber.tsx @@ -0,0 +1,306 @@ +import { + Box, + Typography, + Button, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { Edit, CloseSquare } from 'iconsax-react'; +import { useState, useEffect } from 'react'; + +export function PhoneNumber() { + const [open, setOpen] = useState(false); + const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( + 'enterPhone', + ); + const [buttonState, setButtonState] = useState('default'); // default | counting | sent + const [countdown, setCountdown] = useState(120); + + const handleChangePhoneNumber = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + setDialogStep('enterPhone'); + }; + const handleSendCode = () => { + setDialogStep('verifyCode'); + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + const handleResendCode = () => { + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + + useEffect(() => { + if (buttonState === 'counting' && countdown > 0) { + const timer = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + } + if (countdown === 0 && buttonState === 'counting') { + setButtonState('default'); + } + }, [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 'ارسال دوباره کد'; + }; + + const handleEdit = () => { + setDialogStep('enterPhone'); + }; + + return ( +
+ + + + شماره تماس من + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + 09909366045 + + + ۱ ماه پیش + + + + {/* */} + + + + + + ویرایش شماره تماس + + + + + + + {dialogStep === 'enterPhone' ? ( + <> + + شماره تماس جدید + + + شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد + + + + + ) : ( + <> + + + + اعتبار سنجی + + + کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را + وارد کنید + + + + + + + + + + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/SocialMedia.tsx b/src/features/profile/component/SocialMedia.tsx new file mode 100644 index 0000000..8e84bf9 --- /dev/null +++ b/src/features/profile/component/SocialMedia.tsx @@ -0,0 +1,210 @@ +import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; +import { + Box, + Button, + Typography, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { useState } from 'react'; + +export function SocialMedia() { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const emailList = [ + { email: 'emailtemp@email.com', provider: 'email' }, + { email: 'emailtemp@gmail.com', provider: 'google' }, + ]; + + return ( +
+ + + + ایمیل و شبکه‌های اجتماعی من + + این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + {emailList.map((item, index) => ( + + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + + {item.email} + + ۱ ماه پیش + + + + + + + + ))} + + + + + افزودن ایمیل / سوشال + + + + + + + + + + + + + یا + + + + + + + + + + + +
+ ); +} diff --git a/src/features/profile/component/UserForm.tsx b/src/features/profile/component/UserForm.tsx new file mode 100644 index 0000000..329fc83 --- /dev/null +++ b/src/features/profile/component/UserForm.tsx @@ -0,0 +1,13 @@ +import { PersonalInformation } from './PersonalInformation'; +import { PhoneNumber } from './PhoneNumber'; +import { SocialMedia } from './SocialMedia'; + +export function UserForm() { + return ( + <> + + + + + ); +} From 9ad386e54ab9c2ffb65a30c1f90edc0cca7d7d46 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:37:05 +0330 Subject: [PATCH 02/24] fix: issue in user profile --- package-lock.json | 13 + package.json | 1 + src/App.tsx | 3 + .../components/PersonalInformation.tsx | 229 +++++++++++++ .../profile/components/PhoneNumber.tsx | 306 ++++++++++++++++++ .../profile/components/SocialMedia.tsx | 210 ++++++++++++ src/features/profile/components/UserForm.tsx | 13 + 7 files changed, 775 insertions(+) create mode 100644 src/features/profile/components/PersonalInformation.tsx create mode 100644 src/features/profile/components/PhoneNumber.tsx create mode 100644 src/features/profile/components/SocialMedia.tsx create mode 100644 src/features/profile/components/UserForm.tsx diff --git a/package-lock.json b/package-lock.json index 1204723..fe1023c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "i18next": "^25.3.0", "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", + "iconsax-react": "^0.0.8", "react": "^19.1.0", "react-dom": "^19.1.0", "react-i18next": "^15.6.0", @@ -3102,6 +3103,18 @@ "cross-fetch": "4.0.0" } }, + "node_modules/iconsax-react": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/iconsax-react/-/iconsax-react-0.0.8.tgz", + "integrity": "sha512-l3dVk4zGtkkJHgvNYqAf0wDKqnKxXykee5/DoESGo2JvSYwaxajJUHSX2YrPRXSov8Hd8ClGFwJxCEaEjrFD1Q==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", diff --git a/package.json b/package.json index 666890c..91571b6 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "i18next": "^25.3.0", "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", + "iconsax-react": "^0.0.8", "react": "^19.1.0", "react-dom": "^19.1.0", "react-i18next": "^15.6.0", diff --git a/src/App.tsx b/src/App.tsx index 43fe290..b6dffad 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,9 +7,12 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; +<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; +======= +>>>>>>> 58445fe (feat: add user profile which includes three sections: Personal Information, Phone Number and Email and Social media) function App() { const { t } = useTranslation(); diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx new file mode 100644 index 0000000..21967f1 --- /dev/null +++ b/src/features/profile/components/PersonalInformation.tsx @@ -0,0 +1,229 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function PersonalInformation() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + if (isEditing) { + setData((prev) => ({ + ...prev, + gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', + })); + } else { + setGender( + data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', + ); + } + }; + + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + {isEditing && ( + + )} + + + + + + + {isEditing ? ( + + ) : ( + + + نام + + + {displayValue(data.firstName)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + نام خانوادگی + + + {displayValue(data.lastName)} + + + )} + + + + {isEditing ? ( + + + + ) : ( + + + جنسیت + + + {displayValue(data.gender)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + کد ملی + + + {displayValue(data.nationalCode)} + + + )} + + + +
+ ); +} diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx new file mode 100644 index 0000000..24a9a50 --- /dev/null +++ b/src/features/profile/components/PhoneNumber.tsx @@ -0,0 +1,306 @@ +import { + Box, + Typography, + Button, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { Edit, CloseSquare } from 'iconsax-react'; +import { useState, useEffect } from 'react'; + +export function PhoneNumber() { + const [open, setOpen] = useState(false); + const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( + 'enterPhone', + ); + const [buttonState, setButtonState] = useState('default'); // default | counting | sent + const [countdown, setCountdown] = useState(120); + + const handleChangePhoneNumber = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + setDialogStep('enterPhone'); + }; + const handleSendCode = () => { + setDialogStep('verifyCode'); + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + const handleResendCode = () => { + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + + useEffect(() => { + if (buttonState === 'counting' && countdown > 0) { + const timer = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + } + if (countdown === 0 && buttonState === 'counting') { + setButtonState('default'); + } + }, [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 'ارسال دوباره کد'; + }; + + const handleEdit = () => { + setDialogStep('enterPhone'); + }; + + return ( +
+ + + + شماره تماس من + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + 09909366045 + + + ۱ ماه پیش + + + + {/* */} + + + + + + ویرایش شماره تماس + + + + + + + {dialogStep === 'enterPhone' ? ( + <> + + شماره تماس جدید + + + شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد + + + + + ) : ( + <> + + + + اعتبار سنجی + + + کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را + وارد کنید + + + + + + + + + + + + )} + + + +
+ ); +} diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx new file mode 100644 index 0000000..8e84bf9 --- /dev/null +++ b/src/features/profile/components/SocialMedia.tsx @@ -0,0 +1,210 @@ +import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; +import { + Box, + Button, + Typography, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { useState } from 'react'; + +export function SocialMedia() { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const emailList = [ + { email: 'emailtemp@email.com', provider: 'email' }, + { email: 'emailtemp@gmail.com', provider: 'google' }, + ]; + + return ( +
+ + + + ایمیل و شبکه‌های اجتماعی من + + این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + {emailList.map((item, index) => ( + + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + + {item.email} + + ۱ ماه پیش + + + + + + + + ))} + + + + + افزودن ایمیل / سوشال + + + + + + + + + + + + + یا + + + + + + + + + + + +
+ ); +} diff --git a/src/features/profile/components/UserForm.tsx b/src/features/profile/components/UserForm.tsx new file mode 100644 index 0000000..329fc83 --- /dev/null +++ b/src/features/profile/components/UserForm.tsx @@ -0,0 +1,13 @@ +import { PersonalInformation } from './PersonalInformation'; +import { PhoneNumber } from './PhoneNumber'; +import { SocialMedia } from './SocialMedia'; + +export function UserForm() { + return ( + <> + + + + + ); +} From 4cd801a32cf2275acba93b684acb0ba5b783dc26 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:38:57 +0330 Subject: [PATCH 03/24] fix: issue in user profile --- src/App.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index b6dffad..b2b7076 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,12 +7,8 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; -<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; - -======= ->>>>>>> 58445fe (feat: add user profile which includes three sections: Personal Information, Phone Number and Email and Social media) function App() { const { t } = useTranslation(); From 73788454725f232ea0fd6ede286511657ab65462 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:39:21 +0330 Subject: [PATCH 04/24] fix: issue in user profile --- src/App.tsx | 11 + .../profile/components/UserProfileForm.tsx | 216 ++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 src/features/profile/components/UserProfileForm.tsx diff --git a/src/App.tsx b/src/App.tsx index b2b7076..73b994d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,12 +7,18 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; +<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; +======= +import { UserProfileForm } from './features/profile/components/UserProfileForm'; + +>>>>>>> 3698cbf (feat: implement user profile form) function App() { const { t } = useTranslation(); return ( +<<<<<<< HEAD <> @@ -41,6 +47,11 @@ function App() { +======= +
+ +
+>>>>>>> 3698cbf (feat: implement user profile form) ); } diff --git a/src/features/profile/components/UserProfileForm.tsx b/src/features/profile/components/UserProfileForm.tsx new file mode 100644 index 0000000..9166dc6 --- /dev/null +++ b/src/features/profile/components/UserProfileForm.tsx @@ -0,0 +1,216 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + InputLabel, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function UserProfileForm() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + }; + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + نام + {isEditing ? ( + + ) : ( + + {displayValue(data.firstName)} + + )} + + + + جنسیت + {isEditing ? ( + + جنسیت + + + ) : ( + + {displayValue(data.gender)} + + )} + + + + + + + نام خانوادگی + + {isEditing ? ( + + ) : ( + + {displayValue(data.lastName)} + + )} + + + + کد ملی + {isEditing ? ( + + ) : ( + + {displayValue(data.nationalCode)} + + )} + + + + +
+ ); +} From 2a81ae4a907773496a51ba0b6ea3803b16ee6bef Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:40:27 +0330 Subject: [PATCH 05/24] fix: issue in user profile --- .../profile/component/PersonalInformation.tsx | 229 ------------- .../profile/component/PhoneNumber.tsx | 306 ------------------ .../profile/component/SocialMedia.tsx | 210 ------------ src/features/profile/component/UserForm.tsx | 13 - .../profile/components/PhoneNumber.tsx | 18 +- .../profile/components/UserProfileForm.tsx | 216 ------------- 6 files changed, 9 insertions(+), 983 deletions(-) delete mode 100644 src/features/profile/component/PersonalInformation.tsx delete mode 100644 src/features/profile/component/PhoneNumber.tsx delete mode 100644 src/features/profile/component/SocialMedia.tsx delete mode 100644 src/features/profile/component/UserForm.tsx delete mode 100644 src/features/profile/components/UserProfileForm.tsx diff --git a/src/features/profile/component/PersonalInformation.tsx b/src/features/profile/component/PersonalInformation.tsx deleted file mode 100644 index 21967f1..0000000 --- a/src/features/profile/component/PersonalInformation.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { - Box, - Typography, - Button, - TextField, - Grid, - FormControl, - Select, - MenuItem, - type SelectChangeEvent, -} from '@mui/material'; -import { useState, type ChangeEvent } from 'react'; - -export function PersonalInformation() { - const [isEditing, setIsEditing] = useState(false); - const [gender, setGender] = useState(''); - const [data, setData] = useState({ - firstName: 'محمد حسین', - lastName: 'برزه‌گر', - gender: 'مرد', - nationalCode: '', - }); - - const handleChange = (e: ChangeEvent) => { - setData((prev) => ({ - ...prev, - [e.target.name]: e.target.value, - })); - }; - - const toggleEdit = () => { - setIsEditing((prev) => !prev); - if (isEditing) { - setData((prev) => ({ - ...prev, - gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', - })); - } else { - setGender( - data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', - ); - } - }; - - const handleChangeGender = (e: SelectChangeEvent) => { - setGender(e.target.value); - }; - - const displayValue = (value: string | null | undefined) => { - return value && value.trim() !== '' ? value : 'تعیین نشده'; - }; - - return ( -
- - - - - اطلاعات شخصی من - - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - {isEditing && ( - - )} - - - - - - - {isEditing ? ( - - ) : ( - - - نام - - - {displayValue(data.firstName)} - - - )} - - - - {isEditing ? ( - - ) : ( - - - نام خانوادگی - - - {displayValue(data.lastName)} - - - )} - - - - {isEditing ? ( - - - - ) : ( - - - جنسیت - - - {displayValue(data.gender)} - - - )} - - - - {isEditing ? ( - - ) : ( - - - کد ملی - - - {displayValue(data.nationalCode)} - - - )} - - - -
- ); -} diff --git a/src/features/profile/component/PhoneNumber.tsx b/src/features/profile/component/PhoneNumber.tsx deleted file mode 100644 index ccaff35..0000000 --- a/src/features/profile/component/PhoneNumber.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import { - Box, - Typography, - Button, - Dialog, - DialogTitle, - DialogContent, - IconButton, - TextField, -} from '@mui/material'; -import { Edit, CloseSquare } from 'iconsax-react'; -import { useState, useEffect } from 'react'; - -export function PhoneNumber() { - const [open, setOpen] = useState(false); - const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( - 'enterPhone', - ); - const [buttonState, setButtonState] = useState('default'); // default | counting | sent - const [countdown, setCountdown] = useState(120); - - const handleChangePhoneNumber = () => { - setOpen(true); - }; - const handleClose = () => { - setOpen(false); - setDialogStep('enterPhone'); - }; - const handleSendCode = () => { - setDialogStep('verifyCode'); - setButtonState('sent'); - setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); - }; - const handleResendCode = () => { - setButtonState('sent'); - setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); - }; - - useEffect(() => { - if (buttonState === 'counting' && countdown > 0) { - const timer = setInterval(() => { - setCountdown((prev) => prev - 1); - }, 1000); - return () => clearInterval(timer); - } - if (countdown === 0 && buttonState === 'counting') { - setButtonState('default'); - } - }, [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 'ارسال دوباره کد'; - }; - - const handleEdit = () => { - setDialogStep('enterPhone'); - }; - - return ( -
- - - - شماره تماس من - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - - - - 09909366045 - - - ۱ ماه پیش - - - - {/* */} - - - - - - ویرایش شماره تماس - - - - - - - {dialogStep === 'enterPhone' ? ( - <> - - شماره تماس جدید - - - شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد - - - - - ) : ( - <> - - - - اعتبار سنجی - - - کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را - وارد کنید - - - - - - - - - - - - )} - - - -
- ); -} diff --git a/src/features/profile/component/SocialMedia.tsx b/src/features/profile/component/SocialMedia.tsx deleted file mode 100644 index 8e84bf9..0000000 --- a/src/features/profile/component/SocialMedia.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; -import { - Box, - Button, - Typography, - Dialog, - DialogTitle, - DialogContent, - IconButton, - TextField, -} from '@mui/material'; -import { useState } from 'react'; - -export function SocialMedia() { - const [open, setOpen] = useState(false); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); - - const emailList = [ - { email: 'emailtemp@email.com', provider: 'email' }, - { email: 'emailtemp@gmail.com', provider: 'google' }, - ]; - - return ( -
- - - - ایمیل و شبکه‌های اجتماعی من - - این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - {emailList.map((item, index) => ( - - - {item.provider === 'google' && ( - - )} - {item.provider === 'apple' && ( - - )} - {item.provider === 'email' && ( - - )} - - - - {item.email} - - ۱ ماه پیش - - - - - - - - ))} - - - - - افزودن ایمیل / سوشال - - - - - - - - - - - - - یا - - - - - - - - - - - -
- ); -} diff --git a/src/features/profile/component/UserForm.tsx b/src/features/profile/component/UserForm.tsx deleted file mode 100644 index 329fc83..0000000 --- a/src/features/profile/component/UserForm.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { PersonalInformation } from './PersonalInformation'; -import { PhoneNumber } from './PhoneNumber'; -import { SocialMedia } from './SocialMedia'; - -export function UserForm() { - return ( - <> - - - - - ); -} diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index 24a9a50..ccaff35 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -149,15 +149,15 @@ export function PhoneNumber() { {/* */} + sx={{ + border: '1px solid #1976d2', + color: '#1976d2', + borderRadius: '12px', + width: '40px', + height: '40px', + }} + onClick={handleChangePhoneNumber} + > */} diff --git a/src/features/profile/components/UserProfileForm.tsx b/src/features/profile/components/UserProfileForm.tsx deleted file mode 100644 index 9166dc6..0000000 --- a/src/features/profile/components/UserProfileForm.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { - Box, - Typography, - Button, - TextField, - Grid, - FormControl, - InputLabel, - Select, - MenuItem, - type SelectChangeEvent, -} from '@mui/material'; -import { useState, type ChangeEvent } from 'react'; - -export function UserProfileForm() { - const [isEditing, setIsEditing] = useState(false); - const [gender, setGender] = useState(''); - const [data, setData] = useState({ - firstName: 'محمد حسین', - lastName: 'برزه‌گر', - gender: 'مرد', - nationalCode: '', - }); - - const handleChange = (e: ChangeEvent) => { - setData((prev) => ({ - ...prev, - [e.target.name]: e.target.value, - })); - }; - - const toggleEdit = () => { - setIsEditing((prev) => !prev); - }; - const handleChangeGender = (e: SelectChangeEvent) => { - setGender(e.target.value); - }; - const displayValue = (value: string | null | undefined) => { - return value && value.trim() !== '' ? value : 'تعیین نشده'; - }; - - return ( -
- - - - - اطلاعات شخصی من - - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - - - - نام - {isEditing ? ( - - ) : ( - - {displayValue(data.firstName)} - - )} - - - - جنسیت - {isEditing ? ( - - جنسیت - - - ) : ( - - {displayValue(data.gender)} - - )} - - - - - - - نام خانوادگی - - {isEditing ? ( - - ) : ( - - {displayValue(data.lastName)} - - )} - - - - کد ملی - {isEditing ? ( - - ) : ( - - {displayValue(data.nationalCode)} - - )} - - - - -
- ); -} From a47cba4ee4425e84bbbaed69c3712ba1af13d015 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 08:35:54 +0330 Subject: [PATCH 06/24] feat: complete phone number and edit of that in user-profile --- .../profile/components/UserProfileForm.tsx | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/features/profile/components/UserProfileForm.tsx diff --git a/src/features/profile/components/UserProfileForm.tsx b/src/features/profile/components/UserProfileForm.tsx new file mode 100644 index 0000000..bd48a23 --- /dev/null +++ b/src/features/profile/components/UserProfileForm.tsx @@ -0,0 +1,237 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + InputLabel, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function UserProfileForm() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + }; + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + + نام + + {isEditing ? ( + + ) : ( + + {displayValue(data.firstName)} + + )} + + + + + جنسیت + + {isEditing ? ( + + جنسیت + + + ) : ( + + {displayValue(data.gender)} + + )} + + + + + + + نام خانوادگی + + {isEditing ? ( + + ) : ( + + {displayValue(data.lastName)} + + )} + + + + + کد ملی + + {isEditing ? ( + + ) : ( + + {displayValue(data.nationalCode)} + + )} + + + + +
+ ); +} From 553dd3a95b2a546d6d716f6f07fd10d09c13ba37 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Fri, 18 Jul 2025 21:30:47 +0330 Subject: [PATCH 07/24] fix: merge conflict --- src/App.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 73b994d..b2b7076 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,18 +7,12 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; -<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; -======= -import { UserProfileForm } from './features/profile/components/UserProfileForm'; - ->>>>>>> 3698cbf (feat: implement user profile form) function App() { const { t } = useTranslation(); return ( -<<<<<<< HEAD <> @@ -47,11 +41,6 @@ function App() { -======= -
- -
->>>>>>> 3698cbf (feat: implement user profile form) ); } From 400fd9b0600d2be108221962507510430fbae901 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:30:12 +0330 Subject: [PATCH 08/24] feat: add user completion form --- .../profile/component/PersonalInformation.tsx | 229 +++++++++++++ .../profile/component/PhoneNumber.tsx | 306 ++++++++++++++++++ .../profile/component/SocialMedia.tsx | 210 ++++++++++++ src/features/profile/component/UserForm.tsx | 13 + 4 files changed, 758 insertions(+) create mode 100644 src/features/profile/component/PersonalInformation.tsx create mode 100644 src/features/profile/component/PhoneNumber.tsx create mode 100644 src/features/profile/component/SocialMedia.tsx create mode 100644 src/features/profile/component/UserForm.tsx diff --git a/src/features/profile/component/PersonalInformation.tsx b/src/features/profile/component/PersonalInformation.tsx new file mode 100644 index 0000000..21967f1 --- /dev/null +++ b/src/features/profile/component/PersonalInformation.tsx @@ -0,0 +1,229 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function PersonalInformation() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + if (isEditing) { + setData((prev) => ({ + ...prev, + gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', + })); + } else { + setGender( + data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', + ); + } + }; + + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + {isEditing && ( + + )} + + + + + + + {isEditing ? ( + + ) : ( + + + نام + + + {displayValue(data.firstName)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + نام خانوادگی + + + {displayValue(data.lastName)} + + + )} + + + + {isEditing ? ( + + + + ) : ( + + + جنسیت + + + {displayValue(data.gender)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + کد ملی + + + {displayValue(data.nationalCode)} + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/PhoneNumber.tsx b/src/features/profile/component/PhoneNumber.tsx new file mode 100644 index 0000000..ccaff35 --- /dev/null +++ b/src/features/profile/component/PhoneNumber.tsx @@ -0,0 +1,306 @@ +import { + Box, + Typography, + Button, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { Edit, CloseSquare } from 'iconsax-react'; +import { useState, useEffect } from 'react'; + +export function PhoneNumber() { + const [open, setOpen] = useState(false); + const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( + 'enterPhone', + ); + const [buttonState, setButtonState] = useState('default'); // default | counting | sent + const [countdown, setCountdown] = useState(120); + + const handleChangePhoneNumber = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + setDialogStep('enterPhone'); + }; + const handleSendCode = () => { + setDialogStep('verifyCode'); + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + const handleResendCode = () => { + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + + useEffect(() => { + if (buttonState === 'counting' && countdown > 0) { + const timer = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + } + if (countdown === 0 && buttonState === 'counting') { + setButtonState('default'); + } + }, [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 'ارسال دوباره کد'; + }; + + const handleEdit = () => { + setDialogStep('enterPhone'); + }; + + return ( +
+ + + + شماره تماس من + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + 09909366045 + + + ۱ ماه پیش + + + + {/* */} + + + + + + ویرایش شماره تماس + + + + + + + {dialogStep === 'enterPhone' ? ( + <> + + شماره تماس جدید + + + شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد + + + + + ) : ( + <> + + + + اعتبار سنجی + + + کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را + وارد کنید + + + + + + + + + + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/SocialMedia.tsx b/src/features/profile/component/SocialMedia.tsx new file mode 100644 index 0000000..8e84bf9 --- /dev/null +++ b/src/features/profile/component/SocialMedia.tsx @@ -0,0 +1,210 @@ +import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; +import { + Box, + Button, + Typography, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { useState } from 'react'; + +export function SocialMedia() { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const emailList = [ + { email: 'emailtemp@email.com', provider: 'email' }, + { email: 'emailtemp@gmail.com', provider: 'google' }, + ]; + + return ( +
+ + + + ایمیل و شبکه‌های اجتماعی من + + این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + {emailList.map((item, index) => ( + + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + + {item.email} + + ۱ ماه پیش + + + + + + + + ))} + + + + + افزودن ایمیل / سوشال + + + + + + + + + + + + + یا + + + + + + + + + + + +
+ ); +} diff --git a/src/features/profile/component/UserForm.tsx b/src/features/profile/component/UserForm.tsx new file mode 100644 index 0000000..329fc83 --- /dev/null +++ b/src/features/profile/component/UserForm.tsx @@ -0,0 +1,13 @@ +import { PersonalInformation } from './PersonalInformation'; +import { PhoneNumber } from './PhoneNumber'; +import { SocialMedia } from './SocialMedia'; + +export function UserForm() { + return ( + <> + + + + + ); +} From d879d30b8c8d36fedafe6b187203d3c6e8e69f52 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:37:05 +0330 Subject: [PATCH 09/24] fix: issue in user profile --- src/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/App.tsx b/src/App.tsx index b2b7076..43fe290 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,6 +9,7 @@ import { import './App.css'; import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; + function App() { const { t } = useTranslation(); From be6c80c1365a243a87ab3c37ce27260ae11ed604 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:38:57 +0330 Subject: [PATCH 10/24] fix: issue in user profile --- src/App.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index 43fe290..3c17e69 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,10 @@ import { import './App.css'; import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; +<<<<<<< HEAD +======= +>>>>>>> f1620b6 (fix: issue in user profile) function App() { const { t } = useTranslation(); From 3d5869318a1ba1772351741657390b81a2fc776d Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:39:21 +0330 Subject: [PATCH 11/24] fix: issue in user profile --- src/App.tsx | 14 ++++++++++++++ .../profile/components/UserProfileForm.tsx | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index 3c17e69..3533cc8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,16 +7,25 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; +<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> f1620b6 (fix: issue in user profile) +======= +======= +import { UserProfileForm } from './features/profile/components/UserProfileForm'; + +>>>>>>> 3698cbf (feat: implement user profile form) +>>>>>>> f9815fb (fix: issue in user profile) function App() { const { t } = useTranslation(); return ( +<<<<<<< HEAD <> @@ -45,6 +54,11 @@ function App() { +======= +
+ +
+>>>>>>> 3698cbf (feat: implement user profile form) ); } diff --git a/src/features/profile/components/UserProfileForm.tsx b/src/features/profile/components/UserProfileForm.tsx index bd48a23..b1f711b 100644 --- a/src/features/profile/components/UserProfileForm.tsx +++ b/src/features/profile/components/UserProfileForm.tsx @@ -108,12 +108,16 @@ export function UserProfileForm() { +<<<<<<< HEAD نام +======= + نام +>>>>>>> f9815fb (fix: issue in user profile) {isEditing ? ( >>>>>> f9815fb (fix: issue in user profile) }, }} /> @@ -139,12 +146,16 @@ export function UserProfileForm() { +<<<<<<< HEAD جنسیت +======= + جنسیت +>>>>>>> f9815fb (fix: issue in user profile) {isEditing ? ( جنسیت @@ -175,10 +186,14 @@ export function UserProfileForm() { +<<<<<<< HEAD +======= + +>>>>>>> f9815fb (fix: issue in user profile) نام خانوادگی {isEditing ? ( @@ -203,12 +218,16 @@ export function UserProfileForm() { +<<<<<<< HEAD کد ملی +======= + کد ملی +>>>>>>> f9815fb (fix: issue in user profile) {isEditing ? ( Date: Wed, 16 Jul 2025 23:40:27 +0330 Subject: [PATCH 12/24] fix: issue in user profile --- .../profile/component/PersonalInformation.tsx | 229 ------------- .../profile/component/PhoneNumber.tsx | 306 ------------------ .../profile/component/SocialMedia.tsx | 210 ------------ src/features/profile/component/UserForm.tsx | 13 - 4 files changed, 758 deletions(-) delete mode 100644 src/features/profile/component/PersonalInformation.tsx delete mode 100644 src/features/profile/component/PhoneNumber.tsx delete mode 100644 src/features/profile/component/SocialMedia.tsx delete mode 100644 src/features/profile/component/UserForm.tsx diff --git a/src/features/profile/component/PersonalInformation.tsx b/src/features/profile/component/PersonalInformation.tsx deleted file mode 100644 index 21967f1..0000000 --- a/src/features/profile/component/PersonalInformation.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { - Box, - Typography, - Button, - TextField, - Grid, - FormControl, - Select, - MenuItem, - type SelectChangeEvent, -} from '@mui/material'; -import { useState, type ChangeEvent } from 'react'; - -export function PersonalInformation() { - const [isEditing, setIsEditing] = useState(false); - const [gender, setGender] = useState(''); - const [data, setData] = useState({ - firstName: 'محمد حسین', - lastName: 'برزه‌گر', - gender: 'مرد', - nationalCode: '', - }); - - const handleChange = (e: ChangeEvent) => { - setData((prev) => ({ - ...prev, - [e.target.name]: e.target.value, - })); - }; - - const toggleEdit = () => { - setIsEditing((prev) => !prev); - if (isEditing) { - setData((prev) => ({ - ...prev, - gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', - })); - } else { - setGender( - data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', - ); - } - }; - - const handleChangeGender = (e: SelectChangeEvent) => { - setGender(e.target.value); - }; - - const displayValue = (value: string | null | undefined) => { - return value && value.trim() !== '' ? value : 'تعیین نشده'; - }; - - return ( -
- - - - - اطلاعات شخصی من - - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - {isEditing && ( - - )} - - - - - - - {isEditing ? ( - - ) : ( - - - نام - - - {displayValue(data.firstName)} - - - )} - - - - {isEditing ? ( - - ) : ( - - - نام خانوادگی - - - {displayValue(data.lastName)} - - - )} - - - - {isEditing ? ( - - - - ) : ( - - - جنسیت - - - {displayValue(data.gender)} - - - )} - - - - {isEditing ? ( - - ) : ( - - - کد ملی - - - {displayValue(data.nationalCode)} - - - )} - - - -
- ); -} diff --git a/src/features/profile/component/PhoneNumber.tsx b/src/features/profile/component/PhoneNumber.tsx deleted file mode 100644 index ccaff35..0000000 --- a/src/features/profile/component/PhoneNumber.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import { - Box, - Typography, - Button, - Dialog, - DialogTitle, - DialogContent, - IconButton, - TextField, -} from '@mui/material'; -import { Edit, CloseSquare } from 'iconsax-react'; -import { useState, useEffect } from 'react'; - -export function PhoneNumber() { - const [open, setOpen] = useState(false); - const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( - 'enterPhone', - ); - const [buttonState, setButtonState] = useState('default'); // default | counting | sent - const [countdown, setCountdown] = useState(120); - - const handleChangePhoneNumber = () => { - setOpen(true); - }; - const handleClose = () => { - setOpen(false); - setDialogStep('enterPhone'); - }; - const handleSendCode = () => { - setDialogStep('verifyCode'); - setButtonState('sent'); - setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); - }; - const handleResendCode = () => { - setButtonState('sent'); - setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); - }; - - useEffect(() => { - if (buttonState === 'counting' && countdown > 0) { - const timer = setInterval(() => { - setCountdown((prev) => prev - 1); - }, 1000); - return () => clearInterval(timer); - } - if (countdown === 0 && buttonState === 'counting') { - setButtonState('default'); - } - }, [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 'ارسال دوباره کد'; - }; - - const handleEdit = () => { - setDialogStep('enterPhone'); - }; - - return ( -
- - - - شماره تماس من - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - - - - 09909366045 - - - ۱ ماه پیش - - - - {/* */} - - - - - - ویرایش شماره تماس - - - - - - - {dialogStep === 'enterPhone' ? ( - <> - - شماره تماس جدید - - - شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد - - - - - ) : ( - <> - - - - اعتبار سنجی - - - کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را - وارد کنید - - - - - - - - - - - - )} - - - -
- ); -} diff --git a/src/features/profile/component/SocialMedia.tsx b/src/features/profile/component/SocialMedia.tsx deleted file mode 100644 index 8e84bf9..0000000 --- a/src/features/profile/component/SocialMedia.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; -import { - Box, - Button, - Typography, - Dialog, - DialogTitle, - DialogContent, - IconButton, - TextField, -} from '@mui/material'; -import { useState } from 'react'; - -export function SocialMedia() { - const [open, setOpen] = useState(false); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); - - const emailList = [ - { email: 'emailtemp@email.com', provider: 'email' }, - { email: 'emailtemp@gmail.com', provider: 'google' }, - ]; - - return ( -
- - - - ایمیل و شبکه‌های اجتماعی من - - این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - {emailList.map((item, index) => ( - - - {item.provider === 'google' && ( - - )} - {item.provider === 'apple' && ( - - )} - {item.provider === 'email' && ( - - )} - - - - {item.email} - - ۱ ماه پیش - - - - - - - - ))} - - - - - افزودن ایمیل / سوشال - - - - - - - - - - - - - یا - - - - - - - - - - - -
- ); -} diff --git a/src/features/profile/component/UserForm.tsx b/src/features/profile/component/UserForm.tsx deleted file mode 100644 index 329fc83..0000000 --- a/src/features/profile/component/UserForm.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { PersonalInformation } from './PersonalInformation'; -import { PhoneNumber } from './PhoneNumber'; -import { SocialMedia } from './SocialMedia'; - -export function UserForm() { - return ( - <> - - - - - ); -} From e2ff5c94834717c6e4508360a3ec3b808e2f3e63 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 08:35:54 +0330 Subject: [PATCH 13/24] feat: complete phone number and edit of that in user-profile --- .../profile/components/UserProfileForm.tsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/features/profile/components/UserProfileForm.tsx b/src/features/profile/components/UserProfileForm.tsx index b1f711b..87a9a91 100644 --- a/src/features/profile/components/UserProfileForm.tsx +++ b/src/features/profile/components/UserProfileForm.tsx @@ -109,15 +109,21 @@ export function UserProfileForm() { <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) نام +<<<<<<< HEAD ======= نام >>>>>>> f9815fb (fix: issue in user profile) +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) {isEditing ? ( >>>>>> f9815fb (fix: issue in user profile) +======= + fontSize: '16px', + fontWeight: 'bold', + direction: 'rtl', +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) }, }} /> @@ -147,15 +159,21 @@ export function UserProfileForm() { <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) جنسیت +<<<<<<< HEAD ======= جنسیت >>>>>>> f9815fb (fix: issue in user profile) +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) {isEditing ? ( جنسیت @@ -187,13 +205,19 @@ export function UserProfileForm() { <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) +<<<<<<< HEAD ======= >>>>>>> f9815fb (fix: issue in user profile) +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) نام خانوادگی {isEditing ? ( @@ -219,15 +243,21 @@ export function UserProfileForm() { <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) کد ملی +<<<<<<< HEAD ======= کد ملی >>>>>>> f9815fb (fix: issue in user profile) +======= +>>>>>>> 280b19d (feat: complete phone number and edit of that in user-profile) {isEditing ? ( Date: Fri, 18 Jul 2025 21:30:47 +0330 Subject: [PATCH 14/24] fix: merge conflict --- src/App.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 3533cc8..10a1234 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,11 +7,11 @@ import { useColorScheme, } from '@mui/material'; import './App.css'; -<<<<<<< HEAD import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> f1620b6 (fix: issue in user profile) @@ -21,11 +21,12 @@ import { UserProfileForm } from './features/profile/components/UserProfileForm'; >>>>>>> 3698cbf (feat: implement user profile form) >>>>>>> f9815fb (fix: issue in user profile) +======= +>>>>>>> 2a79376 (fix: merge conflict) function App() { const { t } = useTranslation(); return ( -<<<<<<< HEAD <> @@ -54,11 +55,6 @@ function App() { -======= -
- -
->>>>>>> 3698cbf (feat: implement user profile form) ); } From ff7b5ce4acba4481b63c12468f5313eea3796fb2 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Sat, 19 Jul 2025 17:27:39 +0330 Subject: [PATCH 15/24] fix: styles --- src/App.tsx | 5 + src/components/CardContainer.tsx | 56 +++ src/components/CountDownTimer.tsx | 39 ++ .../components/PersonalInformation.tsx | 176 +++---- .../profile/components/PhoneNumber.tsx | 472 ++++++++---------- .../profile/components/SocialMedia.tsx | 423 ++++++++++------ 6 files changed, 658 insertions(+), 513 deletions(-) create mode 100644 src/components/CardContainer.tsx create mode 100644 src/components/CountDownTimer.tsx diff --git a/src/App.tsx b/src/App.tsx index 10a1234..76660a8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,6 +12,7 @@ import { LanguageManager } from './components/LanguageManager'; <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> f1620b6 (fix: issue in user profile) @@ -23,6 +24,9 @@ import { UserProfileForm } from './features/profile/components/UserProfileForm'; >>>>>>> f9815fb (fix: issue in user profile) ======= >>>>>>> 2a79376 (fix: merge conflict) +======= +import { UserForm } from './features/profile/components/UserForm'; +>>>>>>> 60c6dc1 (fix: styles) function App() { const { t } = useTranslation(); @@ -30,6 +34,7 @@ function App() { <> +
{t('helloWorld')} + + + + {title} + + + {subtitle} + + + {action} + + + {children} + + ); +} 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/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx index 21967f1..9975735 100644 --- a/src/features/profile/components/PersonalInformation.tsx +++ b/src/features/profile/components/PersonalInformation.tsx @@ -3,13 +3,13 @@ import { Typography, Button, TextField, - Grid, FormControl, Select, MenuItem, type SelectChangeEvent, } from '@mui/material'; import { useState, type ChangeEvent } from 'react'; +import { CardContainer } from '@/components/CardContainer'; export function PersonalInformation() { const [isEditing, setIsEditing] = useState(false); @@ -51,58 +51,30 @@ export function PersonalInformation() { }; return ( -
- - - - - اطلاعات شخصی من - - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - + {isEditing && ( - - - - + } + > + + {isEditing ? ( ) : ( - - + + نام - + {displayValue(data.firstName)} )} - + - + {isEditing ? ( ) : ( - - + + نام خانوادگی - + {displayValue(data.lastName)} )} - + - + {isEditing ? ( ) : ( - - + + جنسیت - + {displayValue(data.gender)} )} - + - + {isEditing ? ( ) : ( - - + + کد ملی - + {displayValue(data.nationalCode)} )} - - - -
+ + + + ); } diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index ccaff35..8e08d09 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -2,305 +2,253 @@ import { Box, Typography, Button, - Dialog, - DialogTitle, - DialogContent, - IconButton, TextField, + IconButton, + GlobalStyles, } from '@mui/material'; -import { Edit, CloseSquare } from 'iconsax-react'; -import { useState, useEffect } from 'react'; +import { Edit, Refresh, TickCircle } from 'iconsax-react'; +import { useState, useEffect, type ChangeEvent } from 'react'; +import { CardContainer } from '@/components/CardContainer'; +import { CountDownTimer } from '@/components/CountDownTimer'; export function PhoneNumber() { - const [open, setOpen] = useState(false); - const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( - 'enterPhone', + const [isEditing, setIsEditing] = useState(false); + const [phoneNumber, setPhoneNumber] = useState(''); + const [verificationCode, setVerificationCode] = useState(''); + const [buttonState, setButtonState] = useState<'default' | 'counting'>( + 'default', ); - const [buttonState, setButtonState] = useState('default'); // default | counting | sent - const [countdown, setCountdown] = useState(120); + const [isVerifying, setIsVerifying] = useState(false); + const [isVerified, setIsVerified] = useState(false); - const handleChangePhoneNumber = () => { - setOpen(true); - }; - const handleClose = () => { - setOpen(false); - setDialogStep('enterPhone'); - }; const handleSendCode = () => { - setDialogStep('verifyCode'); - setButtonState('sent'); + setButtonState('counting'); + setIsVerified(false); + }; + + const handleVerifyCode = () => { + setIsVerifying(true); setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); - }; - const handleResendCode = () => { - setButtonState('sent'); - setTimeout(() => { - setButtonState('counting'); - setCountdown(120); - }, 1000); + setIsVerifying(false); + setIsVerified(true); + }, 1500); }; - useEffect(() => { - if (buttonState === 'counting' && countdown > 0) { - const timer = setInterval(() => { - setCountdown((prev) => prev - 1); - }, 1000); - return () => clearInterval(timer); - } - if (countdown === 0 && buttonState === 'counting') { - setButtonState('default'); - } - }, [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 'ارسال دوباره کد'; + const toggleEdit = () => { + setIsEditing((prev) => !prev); + setButtonState('default'); + setIsVerified(false); + setVerificationCode(''); }; - const handleEdit = () => { - setDialogStep('enterPhone'); + 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); }; return ( -
+ <> + - - - شماره تماس من - - این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - - - - 09909366045 - - - ۱ ماه پیش - - - - {/* */} - - - - - - ویرایش شماره تماس - - - - - - - {dialogStep === 'enterPhone' ? ( - <> - - شماره تماس جدید - - - شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد - - + + {isEditing && ( - - ) : ( - <> - - - - اعتبار سنجی - - - کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را - وارد کنید - - - - + )} + + + } + > + {isEditing ? ( + + + + تغییر شماره تماس + + + شماره تماس جدید شما جایگزین شماره تماس قبلی(+989123456789) + خواهد شد. + + + + setButtonState('default')} + > + + + ) : null, }} /> - + + {isVerified ? ( + + + تایید شد + + ) : ( + )} + + {buttonState === 'counting' && !isVerified && ( + + - - )} - - - -
+ )} + + ) : ( + + + 09909366045 + + + ۱ ماه پیش + + + )} + + + ); } diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx index 8e84bf9..cd543b5 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -1,4 +1,12 @@ -import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; +import { + Google, + Apple, + Sms, + Trash, + CloseSquare, + Message, + ArrowDown3, +} from 'iconsax-react'; import { Box, Button, @@ -8,13 +16,33 @@ import { DialogContent, IconButton, TextField, + Menu, + MenuItem, + ListItemIcon, + ListItemText, } from '@mui/material'; -import { useState } from 'react'; +import React, { useState } from 'react'; +import { CardContainer } from '@/components/CardContainer'; export function SocialMedia() { - const [open, setOpen] = useState(false); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); + const [openDialog, setOpenDialog] = useState(false); + const [emailInput, setEmailInput] = useState(''); + const [emailError, setEmailError] = useState(false); + const [anchor, setAnchor] = useState(null); + const openMenu = Boolean(anchor); + + 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' }, @@ -22,189 +50,256 @@ export function SocialMedia() { ]; return ( -
- + + + { + handleCloseMenu(); + handleOpenDialog(); + }} + > + + + + ایمیل + + { + handleCloseMenu(); + handleOpenDialog(); + }} + > + + + + گوگل + + { + handleCloseMenu(); + handleOpenDialog(); + }} + > + + + + اپل + + + + } > - - ایمیل و شبکه‌های اجتماعی من - - این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی - می‌ماند - - - - - - {emailList.map((item, index) => ( - - - {item.provider === 'google' && ( - - )} - {item.provider === 'apple' && ( - - )} - {item.provider === 'email' && ( - - )} - - - - {item.email} - - ۱ ماه پیش - - - - - - - - ))} - - - - - افزودن ایمیل / سوشال - - - - - - - ( + - - - - - - یا - - + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + {item.email} + + + ۱ ماه پیش + + + + + + + ))} + - - + /> + + + + + یا + + + + + + + + - - - -
+ + + + ); } From 8bef6bb9ee49a6a09ade4fe345def3d4fb1b1c5a Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Sun, 20 Jul 2025 17:19:22 +0330 Subject: [PATCH 16/24] fix: translation and styles --- public/locales/fa/profileSetting.json | 36 +++++++++ src/App.tsx | 4 +- src/components/CountryFlag.tsx | 46 ++++++++++++ .../components/PersonalInformation.tsx | 73 ++++++++++++------- .../profile/components/PhoneNumber.tsx | 65 ++++++++++------- .../profile/components/SocialMedia.tsx | 41 ++++++----- 6 files changed, 193 insertions(+), 72 deletions(-) create mode 100644 public/locales/fa/profileSetting.json create mode 100644 src/components/CountryFlag.tsx diff --git a/public/locales/fa/profileSetting.json b/public/locales/fa/profileSetting.json new file mode 100644 index 0000000..ab5053b --- /dev/null +++ b/public/locales/fa/profileSetting.json @@ -0,0 +1,36 @@ +{ + "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": "لطفا یک ایمیل معتبر وارد کنید" + } +} diff --git a/src/App.tsx b/src/App.tsx index 76660a8..0172e04 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import { LanguageManager } from './components/LanguageManager'; <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> f1620b6 (fix: issue in user profile) @@ -27,6 +28,8 @@ import { UserProfileForm } from './features/profile/components/UserProfileForm'; ======= import { UserForm } from './features/profile/components/UserForm'; >>>>>>> 60c6dc1 (fix: styles) +======= +>>>>>>> afc7ff8 (fix: translation and styles) function App() { const { t } = useTranslation(); @@ -34,7 +37,6 @@ function App() { <> -
{t('helloWorld')} + {country} + {country} + + ); +} diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx index 9975735..8905e48 100644 --- a/src/features/profile/components/PersonalInformation.tsx +++ b/src/features/profile/components/PersonalInformation.tsx @@ -10,21 +10,27 @@ import { } from '@mui/material'; import { useState, type ChangeEvent } from 'react'; import { CardContainer } from '@/components/CardContainer'; +import { CountryFlag } from '@/components/CountryFlag'; +import { useTranslation } from 'react-i18next'; +import { Profile } from 'iconsax-react'; export function PersonalInformation() { + const { t } = useTranslation('profileSetting'); const [isEditing, setIsEditing] = useState(false); const [gender, setGender] = useState(''); - const [data, setData] = useState({ + const initialData = { firstName: 'محمد حسین', lastName: 'برزه‌گر', + country: 'قطر', gender: 'مرد', nationalCode: '', - }); - + }; + const [data, setData] = useState(initialData); const handleChange = (e: ChangeEvent) => { + const { name, value } = e.target; setData((prev) => ({ ...prev, - [e.target.name]: e.target.value, + [name]: value, })); }; @@ -62,8 +68,8 @@ export function PersonalInformation() { }} > @@ -77,7 +83,7 @@ export function PersonalInformation() { width: '43px', }} > - لغو + {t('settingForm.rejectButton')} )} } @@ -115,24 +122,30 @@ export function PersonalInformation() { name="firstName" value={data.firstName} onChange={handleChange} - label="نام" + label={t('settingForm.name')} /> ) : ( - نام - - - {displayValue(data.firstName)} + {`${t('settingForm.name')} و ${t('settingForm.familyName')}`} + + + + + {displayValue(data.firstName + ' ' + data.lastName)} + + )} @@ -144,7 +157,7 @@ export function PersonalInformation() { name="lastName" value={data.lastName} onChange={handleChange} - label="نام خانوادگی" + label={t('settingForm.familyName')} /> ) : ( - نام خانوادگی - - - {displayValue(data.lastName)} + {t('settingForm.country')} + )} @@ -172,9 +183,21 @@ export function PersonalInformation() { value={gender} onChange={handleChangeGender} displayEmpty + renderValue={(selected) => { + if (!selected) { + return ( + + {t('settingForm.genderPlaceholder')} + + ); + } + return selected === 'male' + ? t('settingForm.man') + : t('settingForm.woman'); + }} > - زن - مرد + {t('settingForm.man')} + {t('settingForm.woman')} ) : ( @@ -188,7 +211,7 @@ export function PersonalInformation() { }} > - جنسیت + {t('settingForm.gender')} {displayValue(data.gender)} @@ -204,7 +227,7 @@ export function PersonalInformation() { name="nationalCode" value={data.nationalCode} onChange={handleChange} - label="کد ملی" + label={t('settingForm.nationalCode')} /> ) : ( - کد ملی + {t('settingForm.nationalCode')}{' '} {displayValue(data.nationalCode)} diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index 8e08d09..3e40c18 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -7,11 +7,13 @@ import { GlobalStyles, } from '@mui/material'; import { Edit, Refresh, TickCircle } from 'iconsax-react'; -import { useState, useEffect, type ChangeEvent } from 'react'; +import { useState, type ChangeEvent } from 'react'; import { CardContainer } from '@/components/CardContainer'; import { CountDownTimer } from '@/components/CountDownTimer'; +import { useTranslation } from 'react-i18next'; export function PhoneNumber() { + const { t } = useTranslation('profileSetting'); const [isEditing, setIsEditing] = useState(false); const [phoneNumber, setPhoneNumber] = useState(''); const [verificationCode, setVerificationCode] = useState(''); @@ -21,6 +23,8 @@ export function PhoneNumber() { const [isVerifying, setIsVerifying] = useState(false); const [isVerified, setIsVerified] = useState(false); + const phones = [{ phone: '09123456789', time: '۱ ماه پیش' }]; + const handleSendCode = () => { setButtonState('counting'); setIsVerified(false); @@ -71,8 +75,8 @@ export function PhoneNumber() { }} > @@ -83,7 +87,7 @@ export function PhoneNumber() { size="large" sx={{ color: '#2979FF', width: '43px' }} > - لغو + {t('settingForm.rejectButton')} )} } @@ -108,7 +114,7 @@ export function PhoneNumber() { - تغییر شماره تماس + {t('settingForm.editPhoneNumber')} شماره تماس جدید شما جایگزین شماره تماس قبلی(+989123456789) @@ -127,7 +133,7 @@ export function PhoneNumber() { - تایید شد + {t('profileSetting.successButton')} ) : ( )} @@ -192,8 +198,8 @@ export function PhoneNumber() { > ) : ( - 'بررسی کد' + t('settingForm.checkCode') )} )} ) : ( - - - 09909366045 - - - ۱ ماه پیش - + + {phones.map((item, index) => ( + + + {item.phone} + + + {item.time} + + + ))} )} diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx index cd543b5..4db2ee7 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -23,8 +23,10 @@ import { } from '@mui/material'; import React, { useState } from 'react'; import { CardContainer } from '@/components/CardContainer'; +import { useTranslation } from 'react-i18next'; export function SocialMedia() { + const { t } = useTranslation('profileSetting'); const [openDialog, setOpenDialog] = useState(false); const [emailInput, setEmailInput] = useState(''); const [emailError, setEmailError] = useState(false); @@ -45,8 +47,8 @@ export function SocialMedia() { }; const emailList = [ - { email: 'emailtemp@email.com', provider: 'email' }, - { email: 'emailtemp@gmail.com', provider: 'google' }, + { email: 'emailtemp@email.com', provider: 'email', time: '1 ماه پیش' }, + { email: 'emailtemp@gmail.com', provider: 'google', time: '1 ماه پیش' }, ]; return ( @@ -59,8 +61,8 @@ export function SocialMedia() { }} > - ایمیل + {t('settingForm.email')} { @@ -113,7 +115,7 @@ export function SocialMedia() { - گوگل + {t('settingForm.google')} { @@ -124,7 +126,7 @@ export function SocialMedia() { - اپل + {t('settingForm.apple')} @@ -180,7 +182,7 @@ export function SocialMedia() { {item.email} - ۱ ماه پیش + {item.time} @@ -211,7 +213,7 @@ export function SocialMedia() { - افزودن ایمیل + {t('settingForm.addEmailButton')} - ایمیل جدید + + {t('settingForm.newEmail')} + - با فعال‌سازی ایمیل می‌توانید در دفعات بعدی ورود برای ورود از - این ایمیل استفاده کنید + {t('settingForm.dialogHeader')} - ارسال کد تایید + {t('settingForm.verificationCodeButton')} - یا + {t('settingForm.or')} @@ -278,7 +281,7 @@ export function SocialMedia() { }} > - گوگل + {t('settingForm.google')} From 3b3db1be41cbbfaff73d39a1f37ce2775ee30b3d Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Mon, 21 Jul 2025 17:14:19 +0330 Subject: [PATCH 17/24] fix: button of google and apple --- src/features/profile/components/SocialMedia.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx index 4db2ee7..57cc939 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -106,23 +106,13 @@ export function SocialMedia() { {t('settingForm.email')} - { - handleCloseMenu(); - handleOpenDialog(); - }} - > + {t('settingForm.google')} - { - handleCloseMenu(); - handleOpenDialog(); - }} - > + From 9c9e14842686db914e9ca62104f5c4696d5e97b9 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 23 Jul 2025 17:28:25 +0330 Subject: [PATCH 18/24] fix: styles and add a country textfield in personal field --- public/locales/fa/profileSetting.json | 7 +- src/App.tsx | 5 + src/components/CardContainer.tsx | 6 +- src/components/CountryFlag.tsx | 2 +- .../components/PersonalInformation.tsx | 322 +++++++++------- .../profile/components/PhoneNumber.tsx | 362 +++++++++--------- .../profile/components/SocialMedia.tsx | 4 +- 7 files changed, 381 insertions(+), 327 deletions(-) diff --git a/public/locales/fa/profileSetting.json b/public/locales/fa/profileSetting.json index ab5053b..b97e10f 100644 --- a/public/locales/fa/profileSetting.json +++ b/public/locales/fa/profileSetting.json @@ -31,6 +31,11 @@ "newEmail": "ایمیل جدید", "dialogHeader": "با فعال‌سازی ایمیل می‌توانید در دفعات بعدی ورود برای ورود از این ایمیل استفاده کنید", "or": "یا", - "emailError": "لطفا یک ایمیل معتبر وارد کنید" + "emailError": "لطفا یک ایمیل معتبر وارد کنید", + "profilePicture": "تصویر حساب کاربری", + "allowedFormat": "فرمت‌های مجاز: PNG، JPEG، GIF (حداکثر ۱۰ مگابایت)", + "uploadPicture": "بارگذاری تصویر", + "phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی", + "verb": "خواهد شد" } } diff --git a/src/App.tsx b/src/App.tsx index 0172e04..47481fa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,6 +14,7 @@ import { LanguageManager } from './components/LanguageManager'; <<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> f1620b6 (fix: issue in user profile) @@ -30,6 +31,9 @@ import { UserForm } from './features/profile/components/UserForm'; >>>>>>> 60c6dc1 (fix: styles) ======= >>>>>>> afc7ff8 (fix: translation and styles) +======= +import { UserForm } from './features/profile/components/UserForm'; +>>>>>>> b327e7a (fix: styles and add a country textfield in personal field) function App() { const { t } = useTranslation(); @@ -37,6 +41,7 @@ function App() { <> +
{t('helloWorld')} (null); + const handleChange = (e: ChangeEvent) => { const { name, value } = e.target; setData((prev) => ({ @@ -56,16 +61,22 @@ export function PersonalInformation() { return value && value.trim() !== '' ? value : 'تعیین نشده'; }; + const handleImageChange = (e: React.ChangeEvent) => { + 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 ( setIsEditing(false)} size="large" - sx={{ - color: '#2979FF', - width: '43px', - }} + sx={{ color: '#2979FF', width: '43px' }} > {t('settingForm.rejectButton')} @@ -109,142 +117,178 @@ export function PersonalInformation() { > - - {isEditing ? ( - - ) : ( - + - - {`${t('settingForm.name')} و ${t('settingForm.familyName')}`} + {initials} + + + + {t('settingForm.profilePicture')} - - - - - {displayValue(data.firstName + ' ' + data.lastName)} - + + {t('settingForm.allowedFormat')} + + + - )} - + + )} - - {isEditing ? ( - + + {isEditing ? ( + + ) : ( + + + {`${t('settingForm.name')} و ${t('settingForm.familyName')}`} + + + {initials} + + {displayValue(data.firstName + ' ' + data.lastName)} + + + + )} + + + + {isEditing ? ( + + ) : ( + + + {t('settingForm.country')} + + + + )} + + + + {isEditing ? ( + + + + ) : ( + + + {t('settingForm.gender')} + + + {displayValue(data.gender)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + {t('settingForm.nationalCode')} + + + {displayValue(data.nationalCode)} + + + )} + + {isEditing && ( + + setData((prev) => ({ + ...prev, + country: newValue || '', + })) + } + renderOption={(props, option) => ( + + + + )} + renderInput={(params) => ( + + )} /> - ) : ( - - - {t('settingForm.country')} - - - - )} - - - - {isEditing ? ( - - - - ) : ( - - - {t('settingForm.gender')} - - - {displayValue(data.gender)} - - - )} - - - - {isEditing ? ( - - ) : ( - - - {t('settingForm.nationalCode')}{' '} - - - {displayValue(data.nationalCode)} - - )} diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index 3e40c18..b185a00 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -23,7 +23,9 @@ export function PhoneNumber() { const [isVerifying, setIsVerifying] = useState(false); const [isVerified, setIsVerified] = useState(false); - const phones = [{ phone: '09123456789', time: '۱ ماه پیش' }]; + const phones = [ + { phone: '09123456789', time: '۱ ماه پیش', withCode: '+989123456789' }, + ]; const handleSendCode = () => { setButtonState('counting'); @@ -56,210 +58,206 @@ export function PhoneNumber() { }; return ( - <> - - - - {isEditing && ( - - )} + + + {isEditing && ( + )} + + + } + > + {isEditing ? ( + + + + {t('settingForm.editPhoneNumber')} + + + {t('settingForm.phoneNumberText')}( + {phones.map((p) => p.withCode)}){t('settingForm.verb')} + - } - > - {isEditing ? ( - - - - {t('settingForm.editPhoneNumber')} - - - شماره تماس جدید شما جایگزین شماره تماس قبلی(+989123456789) - خواهد شد. - - + + setButtonState('default')} + sx={{ mr: 1 }} + > + + + ) : null, + }} + /> + + {isVerified ? ( + + + {t('settingForm.successButton')} + + ) : ( + + )} + + + {buttonState === 'counting' && !isVerified && ( setButtonState('default')} - > - - - ) : null, - }} /> - - {isVerified ? ( - - - {t('profileSetting.successButton')} - - ) : ( - - )} - - - {buttonState === 'counting' && !isVerified && ( - - - - - )} - - ) : ( - - {phones.map((item, index) => ( - - - {item.phone} - - - {item.time} - - - ))} - - )} - - - + {isVerifying ? ( + + + + ) : ( + t('settingForm.checkCode') + )} + + + )} + + ) : ( + + {phones.map((item, index) => ( + + + {item.phone} + + + {item.time} + + + ))} + + )} + + ); } diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx index 57cc939..5631bda 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -54,10 +54,10 @@ export function SocialMedia() { return ( Date: Wed, 23 Jul 2025 17:29:03 +0330 Subject: [PATCH 19/24] fix: styles --- src/features/profile/components/PhoneNumber.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index b185a00..26b402e 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -1,11 +1,4 @@ -import { - Box, - Typography, - Button, - TextField, - IconButton, - GlobalStyles, -} from '@mui/material'; +import { Box, Typography, Button, TextField, IconButton } from '@mui/material'; import { Edit, Refresh, TickCircle } from 'iconsax-react'; import { useState, type ChangeEvent } from 'react'; import { CardContainer } from '@/components/CardContainer'; From 40c0415b63d0bbb5aeec2ac125d96a2189ec404d Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 23 Jul 2025 21:38:01 +0330 Subject: [PATCH 20/24] feat: responsive design and english translator for this section --- public/locales/en/profileSetting.json | 41 +++ src/App.tsx | 25 +- src/components/CardContainer.tsx | 16 +- .../components/PersonalInformation.tsx | 170 ++++++----- .../profile/components/PhoneNumber.tsx | 87 +++--- .../profile/components/SocialMedia.tsx | 122 +++++--- .../profile/components/UserProfileForm.tsx | 286 ------------------ 7 files changed, 276 insertions(+), 471 deletions(-) create mode 100644 public/locales/en/profileSetting.json delete mode 100644 src/features/profile/components/UserProfileForm.tsx diff --git a/public/locales/en/profileSetting.json b/public/locales/en/profileSetting.json new file mode 100644 index 0000000..3cd0346 --- /dev/null +++ b/public/locales/en/profileSetting.json @@ -0,0 +1,41 @@ +{ + "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": "." + } +} diff --git a/src/App.tsx b/src/App.tsx index 47481fa..853a2c8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,31 +9,8 @@ import { import './App.css'; import { useTranslation } from 'react-i18next'; import { LanguageManager } from './components/LanguageManager'; -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD - -======= ->>>>>>> f1620b6 (fix: issue in user profile) -======= -======= -import { UserProfileForm } from './features/profile/components/UserProfileForm'; - ->>>>>>> 3698cbf (feat: implement user profile form) ->>>>>>> f9815fb (fix: issue in user profile) -======= ->>>>>>> 2a79376 (fix: merge conflict) -======= import { UserForm } from './features/profile/components/UserForm'; ->>>>>>> 60c6dc1 (fix: styles) -======= ->>>>>>> afc7ff8 (fix: translation and styles) -======= -import { UserForm } from './features/profile/components/UserForm'; ->>>>>>> b327e7a (fix: styles and add a country textfield in personal field) + function App() { const { t } = useTranslation(); diff --git a/src/components/CardContainer.tsx b/src/components/CardContainer.tsx index d62672b..80250f0 100644 --- a/src/components/CardContainer.tsx +++ b/src/components/CardContainer.tsx @@ -1,4 +1,5 @@ import { Box, Typography } from '@mui/material'; + export function CardContainer({ title, subtitle, @@ -15,13 +16,16 @@ export function CardContainer({ return ( @@ -30,7 +34,7 @@ export function CardContainer({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', - backgroundColor: highlighted ? '#E3F2FD' : '#F5F5F5', + backgroundColor: highlighted ? 'primary.light' : 'background.default', p: 2, borderRadius: 1, }} @@ -38,12 +42,12 @@ export function CardContainer({ {title} {subtitle} diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx index 291d075..a195047 100644 --- a/src/features/profile/components/PersonalInformation.tsx +++ b/src/features/profile/components/PersonalInformation.tsx @@ -89,7 +89,11 @@ export function PersonalInformation() { variant="text" onClick={() => setIsEditing(false)} size="large" - sx={{ color: '#2979FF', width: '43px' }} + sx={{ + color: 'primary.main', + width: '43px', + textTransform: 'none', + }} > {t('settingForm.rejectButton')} @@ -97,12 +101,16 @@ export function PersonalInformation() {
- ); -} From 67a4c4dee4c28759d16978a843490f74f4fdc094 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Sat, 26 Jul 2025 11:42:37 +0330 Subject: [PATCH 21/24] fix: styles and add responsiveness --- public/locales/en/profileSetting.json | 3 +- public/locales/fa/profileSetting.json | 3 +- src/components/CardContainer.tsx | 6 +- .../components/PersonalInformation.tsx | 277 +++--------------- .../profile/components/PhoneNumber.tsx | 57 ++-- .../profile/components/SocialMedia.tsx | 7 +- .../personlInformation/DisplayField.tsx | 24 ++ .../personlInformation/InfoRowDisplay.tsx | 92 ++++++ .../personlInformation/InfoRowEdit.tsx | 97 ++++++ .../personlInformation/ProfileImage.tsx | 62 ++++ 10 files changed, 361 insertions(+), 267 deletions(-) create mode 100644 src/features/profile/components/personlInformation/DisplayField.tsx create mode 100644 src/features/profile/components/personlInformation/InfoRowDisplay.tsx create mode 100644 src/features/profile/components/personlInformation/InfoRowEdit.tsx create mode 100644 src/features/profile/components/personlInformation/ProfileImage.tsx diff --git a/public/locales/en/profileSetting.json b/public/locales/en/profileSetting.json index 3cd0346..cbc6846 100644 --- a/public/locales/en/profileSetting.json +++ b/public/locales/en/profileSetting.json @@ -36,6 +36,7 @@ "allowedFormat": "Allowed formats: PNG, JPEG, GIF (maximum 10 MB)", "uploadPicture": "Upload image", "phoneNumberText": "Your new contact number will replace your previous contact number.", - "verb": "." + "verb": ".", + "notDetermined": "Not determined" } } diff --git a/public/locales/fa/profileSetting.json b/public/locales/fa/profileSetting.json index b97e10f..44d2a5e 100644 --- a/public/locales/fa/profileSetting.json +++ b/public/locales/fa/profileSetting.json @@ -36,6 +36,7 @@ "allowedFormat": "فرمت‌های مجاز: PNG، JPEG، GIF (حداکثر ۱۰ مگابایت)", "uploadPicture": "بارگذاری تصویر", "phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی", - "verb": "خواهد شد" + "verb": "خواهد شد", + "notDetermined": "تعیین نشده" } } diff --git a/src/components/CardContainer.tsx b/src/components/CardContainer.tsx index 80250f0..0bdb5d3 100644 --- a/src/components/CardContainer.tsx +++ b/src/components/CardContainer.tsx @@ -19,14 +19,14 @@ export function CardContainer({ width: '100%', maxWidth: { xs: '100%', - sm: '500pxpx', - md: '786px', + sm: '500px', + md: '818px', }, display: 'flex', flexDirection: 'column', gap: 2, px: { xs: 2, sm: 3, md: 4 }, - py: 2, + // py: 2, }} > (null); const initialData = { firstName: 'محمد حسین', @@ -29,15 +20,8 @@ export function PersonalInformation() { nationalCode: '', }; const [data, setData] = useState(initialData); - const [uploadedImageUrl, setUploadedImageUrl] = useState(null); - const handleChange = (e: ChangeEvent) => { - const { name, value } = e.target; - setData((prev) => ({ - ...prev, - [name]: value, - })); - }; + const initials = `${data.firstName?.trim()[0] || ''}‌${data.lastName?.trim()[0] || ''}`; const toggleEdit = () => { 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) => { - 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 ( {isEditing && ( - - - {initials} - - - - {t('settingForm.profilePicture')} - - - {t('settingForm.allowedFormat')} - - - - - - - )} - - - {[ - { - 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) => ( - - {isEditing ? ( - - ) : ( - - - {field.label} - - - {displayValue(field.value)} - - - )} - - ))} - - - {isEditing ? ( - - - - ) : ( - - - {t('settingForm.gender')} - - - {displayValue(data.gender)} - - - )} - - - {isEditing && ( - - setData((prev) => ({ - ...prev, - country: newValue || '', - })) + { + const file = e.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = () => + setUploadedImageUrl(reader.result as string); + reader.readAsDataURL(file); } - renderOption={(props, option) => ( - - - - )} - renderInput={(params) => ( - - )} - /> - )} - - {!isEditing && ( - - - {t('settingForm.country')} - - - - )} - + }} + /> + )} + {isEditing ? ( + + ) : ( + + )}
diff --git a/src/features/profile/components/PhoneNumber.tsx b/src/features/profile/components/PhoneNumber.tsx index e3bce9e..4a620fc 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -57,6 +57,7 @@ export function PhoneNumber() { justifyContent: 'center', alignItems: 'center', px: 2, + backgroundColor: 'background.paper', }} > {isEditing ? ( - + {t('settingForm.editPhoneNumber')} @@ -120,6 +123,7 @@ export function PhoneNumber() { display: 'flex', flexWrap: 'wrap', gap: 2, + height: '88px', }} > ) : ( - + + + )} @@ -198,6 +205,7 @@ export function PhoneNumber() { flexWrap: 'wrap', gap: 2, mt: 2, + height: '88px', }} > {isVerifying ? ( @@ -229,6 +238,10 @@ export function PhoneNumber() { sx={{ display: 'flex', animation: 'spin 1s linear infinite', + '@keyframes spin': { + '0%': { transform: 'rotate(0deg)' }, + '100%': { transform: 'rotate(360deg)' }, + }, }} > @@ -249,7 +262,7 @@ export function PhoneNumber() { display: 'flex', flexDirection: 'column', justifyContent: 'center', - py: 1, + height: '148px', width: '100%', }} > diff --git a/src/features/profile/components/SocialMedia.tsx b/src/features/profile/components/SocialMedia.tsx index 51f6a82..3a90bed 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -58,6 +58,7 @@ export function SocialMedia() { justifyContent: 'center', alignItems: 'center', px: 2, + backgroundColor: 'background.paper', }} > @@ -209,7 +207,6 @@ export function SocialMedia() { display: 'flex', flexDirection: 'row', alignItems: 'center', - // backgroundColor: 'background.paper', fontWeight: 'bold', fontSize: '16px', gap: 1, @@ -258,7 +255,7 @@ export function SocialMedia() { sx={{ textTransform: 'none', borderRadius: '8px', - backgroundColor: '#1976d2', + // backgroundColor: '#1976d2', }} disabled={emailError || emailInput === ''} > 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..7ab268b --- /dev/null +++ b/src/features/profile/components/personlInformation/InfoRowDisplay.tsx @@ -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 ( + <> + + + + {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')} + + + + + + + ); +} From 8d72880695eccf91bb7046717da72e6cf26f0fd4 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Sat, 26 Jul 2025 17:08:32 +0330 Subject: [PATCH 22/24] fix: responsiveness --- src/App.tsx | 28 ++++++------- src/components/Countries.tsx | 40 +++++++++++++++++++ .../personlInformation/InfoRowDisplay.tsx | 25 +++++------- 3 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 src/components/Countries.tsx diff --git a/src/App.tsx b/src/App.tsx index 853a2c8..f76d272 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,7 +19,7 @@ function App() { -
+ {/*
{t('helloWorld')} -
+
*/} ); } export default App; -import { Button } from '@mui/material'; +// import { Button } from '@mui/material'; -export const ThemeToggleButton = () => { - const { mode, setMode } = useColorScheme(); +// export const ThemeToggleButton = () => { +// const { mode, setMode } = useColorScheme(); - return ( - - ); -}; +// return ( +// +// ); +// }; 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/features/profile/components/personlInformation/InfoRowDisplay.tsx b/src/features/profile/components/personlInformation/InfoRowDisplay.tsx index 7ab268b..d581865 100644 --- a/src/features/profile/components/personlInformation/InfoRowDisplay.tsx +++ b/src/features/profile/components/personlInformation/InfoRowDisplay.tsx @@ -13,32 +13,24 @@ export function InfoRowDisplay({ initials: string; }) { const { t } = useTranslation('profileSetting'); - const displayValue = (value: string) => value?.trim() || t('settingForm.notDetermined'); return ( - <> + - + {t('settingForm.country')} @@ -75,7 +67,8 @@ export function InfoRowDisplay({ flexDirection: { xs: 'column', sm: 'row' }, flexWrap: 'wrap', gap: 2, - px: 6, + mt: 2, + width: '690px', }} > - + ); } From 594de53486699b69dcca8d68dd6102da1093537c Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Sun, 27 Jul 2025 11:59:55 +0330 Subject: [PATCH 23/24] fix: responsiveness --- public/locales/fa/profileSetting.json | 3 +- src/App.tsx | 26 ++--- src/components/CardContainer.tsx | 71 ++++++++------ src/components/CustomAlert.tsx | 97 +++++++++++++++++++ .../components/PersonalInformation.tsx | 20 +++- .../profile/components/PhoneNumber.tsx | 61 +++++++++--- .../profile/components/SocialMedia.tsx | 2 +- 7 files changed, 220 insertions(+), 60 deletions(-) create mode 100644 src/components/CustomAlert.tsx diff --git a/public/locales/fa/profileSetting.json b/public/locales/fa/profileSetting.json index 44d2a5e..d1942d0 100644 --- a/public/locales/fa/profileSetting.json +++ b/public/locales/fa/profileSetting.json @@ -37,6 +37,7 @@ "uploadPicture": "بارگذاری تصویر", "phoneNumberText": "شماره تماس جدید شما جایگزین شماره تماس قبلی", "verb": "خواهد شد", - "notDetermined": "تعیین نشده" + "notDetermined": "تعیین نشده", + "successfulChangePhone": "شماره تماس با موفقیت تغییر کرد" } } diff --git a/src/App.tsx b/src/App.tsx index f76d272..bf30764 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,12 +19,12 @@ function App() { + {/*
{t('helloWorld')} - @@ -49,17 +49,17 @@ function App() { export default App; -// import { Button } from '@mui/material'; +import { Button } from '@mui/material'; -// export const ThemeToggleButton = () => { -// const { mode, setMode } = useColorScheme(); +export const ThemeToggleButton = () => { + const { mode, setMode } = useColorScheme(); -// return ( -// -// ); -// }; + return ( + + ); +}; diff --git a/src/components/CardContainer.tsx b/src/components/CardContainer.tsx index 0bdb5d3..b83cd82 100644 --- a/src/components/CardContainer.tsx +++ b/src/components/CardContainer.tsx @@ -17,46 +17,59 @@ export function CardContainer({ - - - {title} - - - {subtitle} - + + + + {title} + + + {subtitle} + + + {action} - {action} - - {children} + {children} + ); } diff --git a/src/components/CustomAlert.tsx b/src/components/CustomAlert.tsx new file mode 100644 index 0000000..32c413a --- /dev/null +++ b/src/components/CustomAlert.tsx @@ -0,0 +1,97 @@ +import React, { useState, useEffect } from 'react'; +import { Box, Alert, IconButton, type AlertColor } from '@mui/material'; +import { + TickCircle, + CloseSquare, + Warning2, + InfoCircle, + CloseCircle, +} from 'iconsax-react'; + +type AlertType = AlertColor; + +interface CustomAlertProps { + message: string; + onClose: () => void; + severity?: AlertType; + open: boolean; + duration?: number; + delayOnClose?: number; + rtl?: boolean; + icon?: React.ReactNode; +} + +const defaultIcons: Record = { + success: , + error: , + warning: , + info: , +}; + +export const CustomAlert: React.FC = ({ + message, + severity, + open, + onClose, + duration = 4000, + delayOnClose = 2000, + rtl = false, + icon, +}) => { + const [visible, setVisible] = useState(open); + + useEffect(() => { + setVisible(open); + }, [open]); + + useEffect(() => { + if (visible && duration > 0) { + const timer = setTimeout(() => { + setVisible(false); + onClose(); + }, duration); + return () => clearTimeout(timer); + } + }, [visible, duration, onClose]); + + const handleClose = () => { + setTimeout(() => { + setVisible(false); + onClose(); + }, delayOnClose); + }; + + if (!visible) return null; + + return ( + + + + + } + sx={{ + width: '396px', + flexDirection: 'row-reverse', + justifyContent: 'space-between', + alignItems: 'center', + textAlign: rtl ? 'right' : 'left', + direction: rtl ? 'rtl' : 'ltr', + }} + > + {message} + + + ); +}; diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx index 599e887..a0ad810 100644 --- a/src/features/profile/components/PersonalInformation.tsx +++ b/src/features/profile/components/PersonalInformation.tsx @@ -42,6 +42,8 @@ export function PersonalInformation() { sx={{ display: 'flex', justifyContent: 'center', + width: '100%', + px: { xs: 1, sm: 2 }, backgroundColor: 'background.paper', }} > @@ -50,7 +52,7 @@ export function PersonalInformation() { subtitle={t('settingForm.descriptionPersonalInfo')} highlighted={isEditing} action={ - + {isEditing && ( - )} + + {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 ? ( - - ) : ( - )} + - - + } + > + + {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 index 7e08f70..7cf2cff 100644 --- a/src/features/profile/components/PhoneNumber.tsx +++ b/src/features/profile/components/PhoneNumber.tsx @@ -1,58 +1,27 @@ +import React, { useState, type ChangeEvent } from 'react'; import { Box, Typography, Button, TextField, IconButton } from '@mui/material'; import { Edit, Refresh, TickCircle } from 'iconsax-react'; -import { useState, type ChangeEvent } from 'react'; +import { useTranslation } from 'react-i18next'; import { CardContainer } from '@/components/CardContainer'; import { CountDownTimer } from '@/components/CountDownTimer'; -import { useTranslation } from 'react-i18next'; -import { CustomAlert } from '@/components/CustomAlert'; +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 [showEmailAlert, setShowEmailAlert] = useState(false); + const [showToast, setShowToast] = useState(false); const [buttonState, setButtonState] = useState<'default' | 'counting'>( 'default', ); const [isVerifying, setIsVerifying] = useState(false); const [isVerified, setIsVerified] = useState(false); - const handleVerifyClick = () => { - if (!verificationCode || isVerifying) return; - handleVerifyCode(); - setTimeout(() => { - setShowEmailAlert(true); - }, 1600); - }; - const [phones, setPhone] = useState([ - { - phone: '09123456789', - time: '۱ ماه پیش', - withCode: '+989123456789', - }, + { phone: '09123456789', time: '۱ ماه پیش', withCode: '+989123456789' }, ]); - const handleSendCode = () => { - setButtonState('counting'); - setIsVerified(false); - }; - - const handleVerifyCode = () => { - setIsVerifying(true); - setTimeout(() => { - setIsVerifying(false); - setIsVerified(true); - setShowEmailAlert(true); - - const newPhone = '+98' + phoneNumber.slice(1); - setPhone([ - { phone: phoneNumber, time: 'چند ثانیه پیش', withCode: newPhone }, - ]); - }, 1500); - }; - const toggleEdit = () => { setIsEditing((prev) => { const enteringEditMode = !prev; @@ -61,7 +30,7 @@ export function PhoneNumber() { setVerificationCode(''); setIsVerified(false); setButtonState('default'); - setShowEmailAlert(false); + setShowToast(false); } return enteringEditMode; }); @@ -77,245 +46,241 @@ export function PhoneNumber() { 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 && ( - - } - > - {isEditing ? ( - - - - {t('settingForm.editPhoneNumber')} - - - {t('settingForm.phoneNumberText')}( - {phones.map((p) => p.withCode)}){t('settingForm.verb')} - - + {isEditing + ? t('settingForm.saveButton') + : t('settingForm.editPhoneNumber')} + + + } + > + {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 && ( { - setButtonState('default'); - setPhoneNumber(''); - }} - sx={{ mr: 1 }} - > - - - ) : null, - }} + value={verificationCode} + onChange={handleVerificationCodeChange} + sx={{ flex: '1 1 240px', minWidth: 0 }} + placeholder={t('settingForm.verificationCode')} + inputProps={{ dir: 'rtl', style: { textAlign: 'right' } }} /> - {isVerified ? ( - - - - {t('settingForm.successButton')} - - - ) : ( - - - - )} + + + ) : ( + t('settingForm.checkCode') + )} + + )} - {buttonState === 'counting' && !isVerified && ( - - - - - - )} - setShowEmailAlert(false)} - severity="success" - duration={4000} - delayOnClose={2000} - /> - - ) : ( - - {phones.map((item, index) => ( - - - {item.phone} - - - {item.time} - - - ))} - - )} - - + 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 index a053c86..1d8b3ab 100644 --- a/src/features/profile/components/SocialMedia.tsx +++ b/src/features/profile/components/SocialMedia.tsx @@ -1,12 +1,4 @@ -import { - Google, - Apple, - Sms, - Trash, - CloseSquare, - Message, - ArrowDown3, -} from 'iconsax-react'; +import React, { useState } from 'react'; import { Box, Button, @@ -20,10 +12,21 @@ import { MenuItem, ListItemIcon, ListItemText, + useMediaQuery, } from '@mui/material'; -import React, { useState } from 'react'; -import { CardContainer } from '@/components/CardContainer'; +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'); @@ -32,14 +35,17 @@ export function SocialMedia() { 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) => { + const handleClickMenu = (e: React.MouseEvent) => setAnchor(e.currentTarget); - }; const handleCloseMenu = () => setAnchor(null); + const handleEmailChange = (e: React.ChangeEvent) => { const value = e.target.value; setEmailInput(value); @@ -49,271 +55,277 @@ export function SocialMedia() { 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) => ( + - - - - - { - 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} - - - - - - - - ))} - + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} - + + {item.email} + + + {item.time} + + + + + + + + + ))} + + + + - + + + {t('settingForm.addEmailButton')} + + + + - - - - {t('settingForm.addEmailButton')} - - + + + {t('settingForm.newEmail')} + + + {t('settingForm.dialogHeader')} + + + + + + + + + + + {t('settingForm.or')} + + + + - - - {t('settingForm.newEmail')} - - - {t('settingForm.dialogHeader')} - - - - - - - - {t('settingForm.or')} - - - - - - - - + + {t('settingForm.google')} + + - - - - + + + + ); } diff --git a/src/features/profile/components/UserForm.tsx b/src/features/profile/components/UserForm.tsx index 329fc83..bcfd593 100644 --- a/src/features/profile/components/UserForm.tsx +++ b/src/features/profile/components/UserForm.tsx @@ -1,13 +1,14 @@ +import { Box } from '@mui/material'; import { PersonalInformation } from './PersonalInformation'; import { PhoneNumber } from './PhoneNumber'; import { SocialMedia } from './SocialMedia'; export function UserForm() { return ( - <> + - + ); }