diff --git a/src/components/CardContainer.tsx b/src/components/CardContainer.tsx index b83cd82..798b25a 100644 --- a/src/components/CardContainer.tsx +++ b/src/components/CardContainer.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { Box, Typography } from '@mui/material'; export function CardContainer({ @@ -14,27 +15,16 @@ export function CardContainer({ highlighted?: boolean; }) { return ( - + 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/components/Toast.tsx b/src/components/Toast.tsx new file mode 100644 index 0000000..947194f --- /dev/null +++ b/src/components/Toast.tsx @@ -0,0 +1,23 @@ +import { Alert, Snackbar, type AlertColor } from '@mui/material'; +import React, { type PropsWithChildren } from 'react'; + +export interface ToastProps extends PropsWithChildren { + color: AlertColor | undefined; + open: boolean; + onClose: () => void; +} + +export const Toast = ({ color, open, onClose, children }: ToastProps) => { + return ( + + + {children} + + + ); +}; diff --git a/src/features/profile/components/PersonalInformation.tsx b/src/features/profile/components/PersonalInformation.tsx index a0ad810..d06b551 100644 --- a/src/features/profile/components/PersonalInformation.tsx +++ b/src/features/profile/components/PersonalInformation.tsx @@ -1,5 +1,5 @@ +import React, { useState } from 'react'; import { Box, Button } from '@mui/material'; -import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { CardContainer } from '@/components/CardContainer'; import { ProfileImage } from './personlInformation/ProfileImage'; @@ -38,110 +38,92 @@ export function PersonalInformation() { }; return ( - - - {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 ( - <> + - + ); }