diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..e301f93
--- /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 fe1023c..d0ad8a6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,13 +12,16 @@
"@emotion/styled": "^11.14.1",
"@mui/material": "^7.2.0",
"@mui/stylis-plugin-rtl": "^7.2.0",
+ "@rkheftan/harmony-ui": "^0.0.3",
"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-country-flag": "^3.1.0",
"react-dom": "^19.1.0",
"react-i18next": "^15.6.0",
+ "react-virtuoso": "^4.13.0",
"stylis": "^4.3.6",
"stylis-plugin-rtl": "^2.1.1"
},
@@ -27,6 +30,7 @@
"@types/node": "^24.0.10",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
+ "@types/stylis": "^4.2.7",
"@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.35.1",
"@vitejs/plugin-react": "^4.5.2",
@@ -1067,9 +1071,9 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz",
- "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==",
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz",
+ "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1482,6 +1486,20 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@rkheftan/harmony-ui": {
+ "version": "0.0.3",
+ "resolved": "https://npm.pkg.github.com/download/@rkheftan/harmony-ui/0.0.3/68af74cdbd6fce03e7d7fba0dee51f95bccd87ad",
+ "integrity": "sha512-ZH9zroehY4tVszlcz04L9X32AhgsXGiLSUbnYDL7I80DI5VcRYS0EirQkwIun4gnZI0ncoTX6pKlQOwCFK+8bw==",
+ "peerDependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/material": "^7.2.0",
+ "iconsax-reactjs": "^0.0.8",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-router-dom": "^7.7.1"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.19",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz",
@@ -1878,6 +1896,13 @@
"@types/react": "*"
}
},
+ "node_modules/@types/stylis": {
+ "version": "4.2.7",
+ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.7.tgz",
+ "integrity": "sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.35.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz",
@@ -2401,6 +2426,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -3115,6 +3150,18 @@
"react": "*"
}
},
+
+ "node_modules/iconsax-reactjs": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/iconsax-reactjs/-/iconsax-reactjs-0.0.8.tgz",
+ "integrity": "sha512-cb+uTMxbkSFNbu8ZclX7BWQVfOWQt8+m/PsDjnsm/H+mcYrnfTYMjHxiof1FB43k7UAgt1ds+0oFeMVKdqyslw==",
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
+
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3722,6 +3769,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-country-flag": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.1.0.tgz",
+ "integrity": "sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "react": ">=16"
+ }
+ },
"node_modules/react-dom": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
@@ -3776,6 +3835,46 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.1.tgz",
+ "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.1.tgz",
+ "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "react-router": "7.7.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -3792,6 +3891,16 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/react-virtuoso": {
+ "version": "4.13.0",
+ "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.13.0.tgz",
+ "integrity": "sha512-XHv2Fglpx80yFPdjZkV9d1baACKghg/ucpDFEXwaix7z0AfVQj+mF6lM+YQR6UC/TwzXG2rJKydRMb3+7iV3PA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16 || >=17 || >= 18 || >= 19",
+ "react-dom": ">=16 || >=17 || >= 18 || >=19"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -3912,6 +4021,13 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
diff --git a/package.json b/package.json
index 91571b6..3f7bdc0 100644
--- a/package.json
+++ b/package.json
@@ -15,13 +15,16 @@
"@emotion/styled": "^11.14.1",
"@mui/material": "^7.2.0",
"@mui/stylis-plugin-rtl": "^7.2.0",
+ "@rkheftan/harmony-ui": "^0.0.3",
"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-country-flag": "^3.1.0",
"react-dom": "^19.1.0",
"react-i18next": "^15.6.0",
+ "react-virtuoso": "^4.13.0",
"stylis": "^4.3.6",
"stylis-plugin-rtl": "^2.1.1"
},
@@ -30,6 +33,7 @@
"@types/node": "^24.0.10",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
+ "@types/stylis": "^4.2.7",
"@typescript-eslint/eslint-plugin": "^8.35.1",
"@typescript-eslint/parser": "^8.35.1",
"@vitejs/plugin-react": "^4.5.2",
diff --git a/public/locales/en/activeDevices.json b/public/locales/en/activeDevices.json
new file mode 100644
index 0000000..917b53a
--- /dev/null
+++ b/public/locales/en/activeDevices.json
@@ -0,0 +1,9 @@
+{
+ "active": {
+ "activeDevices": "Active devices",
+ "activeDevicesCaption": "Watch and manage all your active devices",
+ "deletDevicesButton": "Remove rest of the devices",
+ "deleteDevice": "Remove device",
+ "currentDevice": "Current device"
+ }
+}
diff --git a/public/locales/en/security.json b/public/locales/en/security.json
new file mode 100644
index 0000000..920f3fe
--- /dev/null
+++ b/public/locales/en/security.json
@@ -0,0 +1,17 @@
+{
+ "securityForm": {
+ "password": "Password",
+ "determinePassword": "Log in to your Harmony account more easily by setting a strong password.",
+ "addPassword": "Add password",
+ "notDeterminedPassword": "You have not set a password for this account yet.",
+ "newPassword": "New password",
+ "confirmPassword": "Confirm password",
+ "confirm": "Confirm",
+ "hasNumber": "Contains number",
+ "hasMinLength": "at least 8 character",
+ "hasUpperAndLower": "Contains a lowercase and uppercase letter",
+ "hasSpecialChar": "Contains sign (!@#$%^&*)",
+ "notCompatibility": "Confirm password is not the same as password.",
+ "alertSuccess": "Password has successfully changed"
+ }
+}
diff --git a/public/locales/en/setting.json b/public/locales/en/setting.json
new file mode 100644
index 0000000..c5c78f4
--- /dev/null
+++ b/public/locales/en/setting.json
@@ -0,0 +1,18 @@
+{
+ "settings": {
+ "title": "Base settings",
+ "description": "Change your base settings",
+ "editButton": "Edit",
+ "rejectButton": "Reject",
+ "saveButton": "Save",
+ "theme": "Theme and color",
+ "light": "Light",
+ "dark": "Dark",
+ "language": "زبان/language",
+ "calendar": "Calendar and date format",
+ "solar": "Solar",
+ "lunar": "Lunar",
+ "christian": "Christian",
+ "iran": "Iran"
+ }
+}
diff --git a/public/locales/fa/activeDevices.json b/public/locales/fa/activeDevices.json
new file mode 100644
index 0000000..929b2dd
--- /dev/null
+++ b/public/locales/fa/activeDevices.json
@@ -0,0 +1,9 @@
+{
+ "active": {
+ "activeDevices": "نشست های فعال",
+ "activeDevicesCaption": "مشاهده و مدیریت تمام نشست های فعال شما",
+ "deletDevicesButton": "حذف بقیه نشست ها",
+ "deleteDevice": "حذف نشست",
+ "currentDevice": "دستگاه فعلی"
+ }
+}
diff --git a/public/locales/fa/security.json b/public/locales/fa/security.json
new file mode 100644
index 0000000..8ff49f8
--- /dev/null
+++ b/public/locales/fa/security.json
@@ -0,0 +1,22 @@
+{
+ "securityForm": {
+ "password": "رمز عبور",
+ "determinePassword": "با تعیین یک رمز عبور قوی راحت تر به اکانت هارمونی خود وارد شوید",
+ "addPassword": "افزودن رمز عبور",
+ "notDeterminedPassword": "هنوز رمز عبوری برای این حساب کاربری تعیین نکرده اید",
+ "newPassword": "رمز عبور جدید",
+ "confirmPassword": "تکرار رمز عبور",
+ "confirm": "تایید",
+ "hasNumber": "شامل عدد",
+ "hasMinLength": "حداقل 8 کاراکتر",
+ "hasUpperAndLower": "شامل یک حرف کوچک و بزرگ",
+ "hasSpecialChar": "شامل علامت (!@#$%^&*)",
+ "notCompatibility": "تکرار رمز عبور با رمز عبور یکسان نمی باشد",
+ "alertSuccess": "رمز عبور با موفقیت تعویض شد",
+ "lastChange": "آخرین تغییر چند ثانیه پیش",
+ "activePassword": "رمز عبور فعال است",
+ "recentLogins": "ورود های اخیر",
+ "description": "در این بخش از ورود های اخیر به اکانت هارمونی خود را مشاهده می کنید",
+ "currentDevice": "دستگاه فعلی"
+ }
+}
diff --git a/public/locales/fa/setting.json b/public/locales/fa/setting.json
new file mode 100644
index 0000000..1b07a7a
--- /dev/null
+++ b/public/locales/fa/setting.json
@@ -0,0 +1,18 @@
+{
+ "settings": {
+ "title": "تنظیمات پایه",
+ "description": "تنظیمات پایهای حساب خود را تغییر دهید",
+ "editButton": "ویرایش",
+ "rejectButton": "لغو",
+ "saveButton": "ذخیره",
+ "theme": "تم و رنگ",
+ "light": "روشن",
+ "dark": "تاریک",
+ "language": "زبان/language",
+ "calendar": "فرمت تقویم و تاریخ",
+ "solar": "شمسی",
+ "lunar": "قمری",
+ "christian": "میلادی",
+ "iran": "ایران"
+ }
+}
diff --git a/src/App.tsx b/src/App.tsx
index bf30764..b1c1097 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,25 +1,14 @@
-import {
- Alert,
- Box,
- CssBaseline,
- TextField,
- Typography,
- useColorScheme,
-} from '@mui/material';
+import { CssBaseline, useColorScheme } from '@mui/material';
import './App.css';
-import { useTranslation } from 'react-i18next';
import { LanguageManager } from './components/LanguageManager';
-import { UserForm } from './features/profile/components/UserForm';
+
function App() {
- const { t } = useTranslation();
-
return (
<>