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 } }}
+ />
+
+ )}
-
- )}
+
- 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 (
-
+
+
-
+
+
+ {t('settingForm.addEmailOrSocialButton')}
+
+
+
+
+
+
+
+ }
+ >
+
+ {emailList.map((item, index) => (
+
- {t('settingForm.addEmailOrSocialButton')}
-
-
-
-
+ {item.provider === 'google' && (
+
+ )}
+ {item.provider === 'apple' && (
+
+ )}
+ {item.provider === 'email' && (
+
+ )}
-
+
+
+ {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')}
-
-
-
-
-
- ))}
-
-
-
-
+
+
+
+
);
}
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: },
],
},
]);