diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..538d79a --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@rkheftan:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=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 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1a205d6..ea48e01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@emotion/styled": "^11.14.1", "@mui/material": "^7.2.0", "@mui/stylis-plugin-rtl": "^7.2.0", - "@rkheftan/harmony-ui": "^0.1.2", + "@rkheftan/harmony-ui": "^0.1.4", "i18next": "^25.3.0", "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", @@ -1739,9 +1739,9 @@ } }, "node_modules/@rkheftan/harmony-ui": { - "version": "0.1.2", - "resolved": "https://npm.pkg.github.com/download/@rkheftan/harmony-ui/0.1.2/75290c938c36fe3cfe5f334b997192c0503ceb29", - "integrity": "sha512-0yM5E2ptuWKvlR3Skk/9tuDaoQue0Hdr9g7ycsKtM1TBsh6011IiewKCA/drPcPc7CbmYDIvrU03mpA77lUFXw==", + "version": "0.1.4", + "resolved": "https://npm.pkg.github.com/download/@rkheftan/harmony-ui/0.1.4/01829061a531171f16aa92ac2c006d2553254797", + "integrity": "sha512-hxwhuBfiHqaJpFC75s0/l+pUChE4gzr+ynZ4Wl/wCI4pdFvwQuTh6BrSl4LotfTKO6v0cK8Ii9brEX3Yr7bXBA==", "peerDependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", diff --git a/package.json b/package.json index b18f364..54fc38f 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@emotion/styled": "^11.14.1", "@mui/material": "^7.2.0", "@mui/stylis-plugin-rtl": "^7.2.0", - "@rkheftan/harmony-ui": "^0.1.2", + "@rkheftan/harmony-ui": "^0.1.4", "i18next": "^25.3.0", "i18next-browser-languagedetector": "^8.2.0", "i18next-http-backend": "^3.0.2", diff --git a/public/locales/en/profileSetting.json b/public/locales/en/profileSetting.json index cbc6846..b53e9ff 100644 --- a/public/locales/en/profileSetting.json +++ b/public/locales/en/profileSetting.json @@ -37,6 +37,7 @@ "uploadPicture": "Upload image", "phoneNumberText": "Your new contact number will replace your previous contact number.", "verb": ".", - "notDetermined": "Not determined" + "notDetermined": "Not determined", + "successfulChangePhone": "Phone number changed successfully" } } diff --git a/public/locales/en/security.json b/public/locales/en/security.json index 920f3fe..599e363 100644 --- a/public/locales/en/security.json +++ b/public/locales/en/security.json @@ -12,6 +12,11 @@ "hasUpperAndLower": "Contains a lowercase and uppercase letter", "hasSpecialChar": "Contains sign (!@#$%^&*)", "notCompatibility": "Confirm password is not the same as password.", - "alertSuccess": "Password has successfully changed" + "alertSuccess": "Password has successfully changed", + "lastChange": "Last change a few seconds ago", + "activePassword": "Password is active", + "recentLogins": "Recent logins", + "description": "In this section, you can see the recent logins to your Harmony account.", + "currentDevice": "Current device" } } diff --git a/public/locales/fa/security.json b/public/locales/fa/security.json index 8ff49f8..39376bc 100644 --- a/public/locales/fa/security.json +++ b/public/locales/fa/security.json @@ -17,6 +17,9 @@ "activePassword": "رمز عبور فعال است", "recentLogins": "ورود های اخیر", "description": "در این بخش از ورود های اخیر به اکانت هارمونی خود را مشاهده می کنید", - "currentDevice": "دستگاه فعلی" + "currentDevice": "دستگاه فعلی", + "changePassword": "تغییر رمز عبور", + "currentPassword": "رمز عبور فعلی", + "forgetPassword": "رمز عبور را فراموش کرده اید؟" } } diff --git a/src/features/profile/components/activeDevices/ActiveDevices.tsx b/src/features/profile/components/activeDevices/ActiveDevices.tsx index de1e4d8..0a19f38 100644 --- a/src/features/profile/components/activeDevices/ActiveDevices.tsx +++ b/src/features/profile/components/activeDevices/ActiveDevices.tsx @@ -86,7 +86,7 @@ export function ActiveDevices() { flex: 1, }} > - + {devices.map((device) => ( {device.timeAndDate} @@ -107,7 +107,7 @@ export function ActiveDevices() { sx={{ display: 'flex', alignItems: 'center', - width: { xs: '100%', sm: '172.5px' }, + width: { xs: '100%', sm: '138px' }, gap: 1, }} > @@ -122,13 +122,13 @@ export function ActiveDevices() { {device.ip} @@ -142,7 +142,7 @@ export function ActiveDevices() { height: '30px', whiteSpace: 'nowrap', color: 'success.main', - width: '93px', + // width: '93px', textTransform: 'none', }} > @@ -152,7 +152,7 @@ export function ActiveDevices() { @@ -163,7 +163,7 @@ export function ActiveDevices() { disabled={device.current} sx={{ color: 'error.main', - width: '80%', + // width: '80%', minWidth: 0, borderRadius: '15px', borderColor: 'error.main', diff --git a/src/features/profile/components/security/PasswordSecurity.tsx b/src/features/profile/components/security/PasswordSecurity.tsx index e11829b..d8daf3d 100644 --- a/src/features/profile/components/security/PasswordSecurity.tsx +++ b/src/features/profile/components/security/PasswordSecurity.tsx @@ -9,11 +9,12 @@ import { DialogActions, IconButton, useMediaQuery, + Link, } from '@mui/material'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'react-i18next'; import { useState, useEffect } from 'react'; -import { CloseSquare, Refresh } from 'iconsax-react'; +import { CloseCircle, Refresh } from 'iconsax-react'; import { PasswordValidationItem } from './PasswordValidation'; import { Toast } from '@/components/Toast'; import Logo from '@/components/Logo'; @@ -26,6 +27,7 @@ export function PasswordSecurity() { const [open, setOpen] = useState(false); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); + const [currentPassword, setCurrentPassword] = useState(''); const [showValidation, setShowValidation] = useState(false); const [showPasswordAlert, setShowPasswordAlert] = useState(false); const [changePassword, setChangePassword] = useState(false); @@ -50,6 +52,7 @@ export function PasswordSecurity() { handleClose(); setPassword(''); setConfirmPassword(''); + setCurrentPassword(''); }, 1500); }; @@ -83,19 +86,35 @@ export function PasswordSecurity() { title={t('securityForm.password')} subtitle={t('securityForm.determinePassword')} action={ - + changePassword ? ( + + ) : ( + + ) } > - + {t('securityForm.addPassword')} + {changePassword ? ( + + setCurrentPassword(e.target.value)} + sx={{ + '& .MuiOutlinedInput-root': { borderRadius: 2 }, + mt: 2, + }} + /> + + {t('securityForm.forgetPassword')} + + setPassword(e.target.value)} + sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} + /> - - setPassword(e.target.value)} - sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} - /> - - {password && showValidation && ( - - - - - - + {password && showValidation && ( + + + + + + + - - )} + )} - setConfirmPassword(e.target.value)} - error={confirmPassword.length > 0 && !matchPassword} - helperText={ - confirmPassword.length > 0 && !matchPassword - ? t('securityForm.notCompatibility') - : ' ' - } - sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} - /> - + setConfirmPassword(e.target.value)} + error={confirmPassword.length > 0 && !matchPassword} + helperText={ + confirmPassword.length > 0 && !matchPassword + ? t('securityForm.notCompatibility') + : ' ' + } + sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} + /> + + ) : ( + + setPassword(e.target.value)} + sx={{ + '& .MuiOutlinedInput-root': { borderRadius: 2 }, + mt: 2, + }} + /> + {password && showValidation && ( + + + + + + + + + )} + + setConfirmPassword(e.target.value)} + error={confirmPassword.length > 0 && !matchPassword} + helperText={ + confirmPassword.length > 0 && !matchPassword + ? t('securityForm.notCompatibility') + : ' ' + } + sx={{ '& .MuiOutlinedInput-root': { borderRadius: 2 } }} + /> + + )} - )} - - - } - > - {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')} - - - ) : ( + + + {isEditing && ( )} + + } + > + {isEditing ? ( + + + + {t('settingForm.editPhoneNumber')} + + + {t('settingForm.phoneNumberText')}( + {phones.map((p) => p.withCode)}){t('settingForm.verb')} + + - {buttonState === 'counting' && !isVerified && ( { + setButtonState('default'); + setPhoneNumber(''); + }} + sx={{ mr: 1 }} + > + + + ) : null, + }} /> - + )} + + + {buttonState === 'counting' && !isVerified && ( + - {isVerifying ? ( - - - - ) : ( - t('settingForm.checkCode') - )} - - - )} + - setShowToast(false)} - > - {t('settingForm.successfulChangePhone')} - - - ) : ( - - {phones.map((item, index) => ( - + {isVerifying ? ( + + + + ) : ( + t('settingForm.checkCode') + )} + + + )} + + setShowToast(false)} > - - {item.phone} - - - {item.time} - - - ))} - - )} - + {t('settingForm.successfulChangePhone')} + + + ) : ( + + {phones.map((item, index) => ( + + + {item.phone} + + + {item.time} + + + ))} + + )} + + ); } diff --git a/src/features/profile/components/userInformation/SocialMedia.tsx b/src/features/profile/components/userInformation/SocialMedia.tsx index f4c8a66..4bc6b1a 100644 --- a/src/features/profile/components/userInformation/SocialMedia.tsx +++ b/src/features/profile/components/userInformation/SocialMedia.tsx @@ -59,273 +59,275 @@ export function SocialMedia() { ] as const; return ( - + + - + + + + { + handleCloseMenu(); + handleOpenDialog(); + }} + > + + + + {t('settingForm.email')} + + + + + + {t('settingForm.google')} + + + + + + {t('settingForm.apple')} + + + + } + > + + {emailList.map((item, index) => ( + - {t('settingForm.addEmailOrSocialButton')} - - - - + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} - - { - handleCloseMenu(); - handleOpenDialog(); - }} - > - - - - {t('settingForm.email')} - - - - - - {t('settingForm.google')} - - - - - - {t('settingForm.apple')} - - + + + {item.email} + + + {item.time} + + + + + + + + + ))} - } - > - - {emailList.map((item, index) => ( - + + + + + {t('settingForm.addEmailButton')} + + + - {item.provider === 'google' && ( - - )} - {item.provider === 'apple' && ( - - )} - {item.provider === 'email' && ( - - )} - - - - {item.email} + + + {t('settingForm.newEmail')} - - {item.time} + + {t('settingForm.dialogHeader')} - - - - - - ))} - - - - - - - - {t('settingForm.addEmailButton')} - - - - - - - {t('settingForm.newEmail')} - - - {t('settingForm.dialogHeader')} - - - - - - - - - - - {t('settingForm.or')} - - - - - - + + + + + {t('settingForm.or')} + + + + + - - {t('settingForm.google')} - - + + + - - - - + + + + ); } diff --git a/src/features/profile/components/userInformation/personlInformation/InfoRowDisplay.tsx b/src/features/profile/components/userInformation/personlInformation/InfoRowDisplay.tsx index d581865..d838f37 100644 --- a/src/features/profile/components/userInformation/personlInformation/InfoRowDisplay.tsx +++ b/src/features/profile/components/userInformation/personlInformation/InfoRowDisplay.tsx @@ -30,23 +30,28 @@ export function InfoRowDisplay({ }} > - - {initials} - - - - {t('settingForm.name')} و {t('settingForm.familyName')} - + + {t('settingForm.name')} و {t('settingForm.familyName')} + + + + {initials} + {`${displayValue(data.firstName)} ${displayValue(data.lastName)}`} diff --git a/src/features/profile/routes/SettingPage.tsx b/src/features/profile/routes/SettingPage.tsx index 3c3a72f..3a1ccbb 100644 --- a/src/features/profile/routes/SettingPage.tsx +++ b/src/features/profile/routes/SettingPage.tsx @@ -16,6 +16,7 @@ import { Setting as SettingIcon, Shield, Sms, + Menu, } from 'iconsax-react'; import { Box, Typography, useTheme, useMediaQuery } from '@mui/material'; import { useTranslation } from 'react-i18next'; @@ -61,68 +62,126 @@ export function Layout() { const drawerWidth = 274; const minimizedWidth = 64; const navWidth = isMdUp ? drawerWidth : minimizedWidth; - const contentWidth = 790; + const contentWidth = 810; + const contentHeight = '78vh'; const totalWidth = navWidth + contentWidth; const navConfig: NavItemConfig[] = [ { text: t('side.account'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/profile', children: [ { text: t('side.personalInfo'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/profile#info', }, { text: t('side.phoneNumber'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/profile#contact-info', }, { text: t('side.email'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/profile#email', }, ], }, { text: t('side.security'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/security', children: [ { text: t('side.password'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/security#password', }, { text: t('side.verifiedAddress'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/security#locations', }, { text: t('side.recentLogins'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/security#sessions', }, ], }, { text: t('side.activeDevices'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/devices', }, { text: t('side.settings'), - icon: , + getIcon: (isSelected) => + isSelected ? ( + + ) : ( + + ), path: '/setting', }, ]; return ( - + } + header={isMdUp ?
: } activePath={location.pathname + location.hash} sideNavVariant={isMdUp ? 'full' : 'minimized'} positioning="absolute" @@ -143,10 +202,13 @@ export function Layout() { /> @@ -165,7 +227,16 @@ const router = createBrowserRouter([ { path: '/profile', element: ( - <> +
@@ -175,13 +246,21 @@ const router = createBrowserRouter([
- +
), }, { path: '/security', element: ( - <> +
@@ -189,11 +268,25 @@ const router = createBrowserRouter([
- +
+ ), + }, + { + path: '/devices', + element: ( + + + + ), + }, + { + path: '/setting', + element: ( + + + ), }, - { path: '/devices', element: }, - { path: '/setting', element: }, ], }, ]);