diff --git a/.gitignore b/.gitignore
index 7259800..19e26e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,7 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
-#Ignored
+# Ignored
node_modules
dist
dist-ssr
@@ -24,4 +24,4 @@ dist-ssr
*.njsproj
*.sln
*.sw?
-.VSCodeCounter
\ No newline at end of file
+.VSCodeCounter
diff --git a/README.md b/README.md
index 24ab563..b38b5bf 100644
--- a/README.md
+++ b/README.md
@@ -1,89 +1,56 @@
# University Frontend
-
-This project serves as the frontend for a University management system, designed to provide an intuitive interface for managing student data, course registrations, and other functionalities. Built with React and TypeScript, it focuses on delivering a responsive and user-friendly experience with modern frontend technologies.
+This project offers frontend for a **University Management System**, offering an intuitive interface for managing student data, course registrations, and administrative functionalities. Built with **React** and **TypeScript**, it prioritizes responsiveness, scalability, and user experience with modern frontend technologies.
## Features
-- **React with TypeScript**: Utilizes React for building dynamic user interfaces and TypeScript for strong typing and improved developer experience.
-- **Component-Based Architecture**: Implements reusable and modular components for maintainability and scalability.
-- **State Management**: Manages application state effectively using [state management library, e.g., Redux, Context API].
-- **API Integration**: Connects seamlessly with the backend API to handle data fetching and state synchronization.
-- **Responsive Design**: Ensures a consistent user experience across different devices and screen sizes.
+- **React with TypeScript**: Combines React's dynamic UI capabilities with TypeScript's type safety for a robust developer experience.
+- **Modular Architecture**: Utilizes a component-based architecture for enhanced maintainability and scalability.
+- **State Management**: Effectively handles application state using [Redux/Context API/etc.].
+- **Seamless API Integration**: Connects effortlessly with the backend to manage data fetching and synchronization.
+- **Responsive Design**: Delivers a consistent and adaptive user experience across various devices and screen sizes.
## Getting Started
### Prerequisites
-- Node.js (version >=18.0.0 or higher recommended)
-- npm (version >=8.0.0 or higher)
+- **Node.js**: Version 18.0.0 or higher
+- **npm**: Version 8.0.0 or higher
### Installation
-1. **Clone the repository:**
-
+1. **Clone the repository**:
```bash
git clone https://github.com/Swiatlon/University-FN
```
-2. **Navigate to the project directory:**
-
+2. **Navigate to the project directory**:
```bash
cd University-FN
```
-3. **Install NPM packages:**
-
+3. **Install dependencies**:
```bash
npm install
```
### Running the Application
-- **Development mode with live reloads:**
-
- ```bash
- npm run dev
- ```
-
-- **Build the application for production:**
-
- ```bash
- npm run build
- ```
-
- The production build will be located in the `build` directory.
-
-## Contributing
-
-We welcome contributions to the University-FN frontend project! If you have suggestions, improvements, or bug fixes, please follow these steps:
-
-1. **Fork the repository**
-2. **Create a new branch:**
-
+- **Development Mode**:
```bash
- git checkout -b feature/your-feature-name
+ npm run dev
```
+ This starts the application with live reloads for development.
-3. **Commit your changes:**
-
+- **Production Build**:
```bash
- git commit -m 'Add new feature'
+ npm run build
```
-
-4. **Push to the branch:**
-
- ```bash
- git push origin feature/your-feature-name
- ```
-
-5. **Submit a pull request**
-
-For detailed guidelines, please refer to our [CONTRIBUTING.md](CONTRIBUTING.md) file.
+ The optimized production build will be available in the `build` directory.
## License
-This project is open-source under the MIT license. See the [LICENSE](LICENSE) file for details.
+This project is licensed under the **MIT License**. For more information, refer to the [LICENSE](LICENSE) file.
## Contact
-For any questions or feedback, please reach out to [your email address] or create an issue on [GitHub Issues](https://github.com/Swiatlon/University-FN/issues).
+For inquiries or feedback, please contact [your email address] or open an issue on [GitHub Issues](https://github.com/Swiatlon/University-FN/issues).
diff --git a/.eslintrc.cjs b/eslint.config.js
similarity index 78%
rename from .eslintrc.cjs
rename to eslint.config.js
index fb93854..311c306 100644
--- a/.eslintrc.cjs
+++ b/eslint.config.js
@@ -1,44 +1,33 @@
-module.exports = {
- root: true,
- env: {
- browser: true,
- es2020: true,
- node: true,
- },
- extends: [
- 'eslint:all',
- 'plugin:@typescript-eslint/all',
- 'plugin:react/all',
- 'plugin:jsx-a11y/strict',
- 'plugin:security/recommended-legacy',
- 'plugin:sonarjs/recommended-legacy',
- 'plugin:import/errors',
- 'plugin:import/warnings',
- 'plugin:import/typescript',
- 'plugin:prettier/recommended',
- ],
- parser: '@typescript-eslint/parser',
- parserOptions: {
- project: './tsconfig.json',
- tsconfigRootDir: __dirname,
- ecmaVersion: 2020,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
+import eslint from '@eslint/js';
+import eslintCommentsPlugin from 'eslint-plugin-eslint-comments';
+import importPlugin from 'eslint-plugin-import';
+import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
+import prettierPlugin from 'eslint-plugin-prettier';
+import reactPlugin from 'eslint-plugin-react';
+import reactHooksPlugin from 'eslint-plugin-react-hooks';
+import securityPlugin from 'eslint-plugin-security';
+import sonarjsPlugin from 'eslint-plugin-sonarjs';
+import unusedImportsPlugin from 'eslint-plugin-unused-imports';
+import tseslint from 'typescript-eslint';
+
+export default tseslint.config(eslint.configs.recommended, tseslint.configs.strict, tseslint.configs.stylistic, {
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ tsconfigRootDir: './tsconfig.json',
},
},
- plugins: [
- 'react',
- '@typescript-eslint',
- 'react-hooks',
- 'jsx-a11y',
- 'security',
- 'sonarjs',
- 'unused-imports',
- 'eslint-comments',
- 'react-refresh',
- 'prettier',
- ],
+ plugins: {
+ react: reactPlugin,
+ 'jsx-a11y': jsxA11yPlugin,
+ security: securityPlugin,
+ sonarjs: sonarjsPlugin,
+ 'unused-imports': unusedImportsPlugin,
+ 'eslint-comments': eslintCommentsPlugin,
+ 'react-hooks': reactHooksPlugin,
+ prettier: prettierPlugin,
+ import: importPlugin,
+ },
rules: {
'import/order': [
'error',
@@ -88,9 +77,10 @@ module.exports = {
},
},
],
- "react/no-multi-comp": "off",
- "no-multiple-empty-lines": ["error", { max: 1 }],
- "max-lines": ["error", { "max": 500, "skipBlankLines": true }],
+ '@typescript-eslint/no-empty-object-type': 'off',
+ 'react/no-multi-comp': 'off',
+ 'no-multiple-empty-lines': ['error', { max: 1 }],
+ 'max-lines': ['error', { max: 500, skipBlankLines: true }],
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': 'off',
@@ -132,11 +122,9 @@ module.exports = {
'one-var': ['off'],
'sort-imports': 'off',
'sort-keys': 'off',
- '@typescript-eslint/type-annotation-spacing': 'error',
'@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'explicit' }],
'@typescript-eslint/no-for-in-array': 'error',
'@typescript-eslint/no-misused-promises': 'off',
- '@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/promise-function-async': 'error',
'@typescript-eslint/require-await': 'error',
'react/require-default-props': 'off',
@@ -173,5 +161,5 @@ module.exports = {
version: 'detect',
},
},
- ignorePatterns: ['node_modules/', 'dist/', 'vite.config.ts'],
-};
+ ignores: ['node_modules/', 'dist/', 'vite.config.ts'],
+});
diff --git a/package-lock.json b/package-lock.json
index 22c2121..6cd93c5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,10 +8,6 @@
"name": "client",
"version": "1.2.0 - Alfa",
"dependencies": {
- "@date-io/dayjs": "^3.0.0",
- "@devexpress/dx-react-core": "^4.0.6",
- "@devexpress/dx-react-grid": "^4.0.6",
- "@devexpress/dx-react-grid-material-ui": "^4.0.8",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@fullcalendar/core": "^6.1.15",
@@ -24,7 +20,6 @@
"@mui/icons-material": "^5.15.15",
"@mui/material": "^5.16.7",
"@mui/x-date-pickers": "^6.20.2",
- "@mui/x-tree-view": "^7.23.0",
"@reduxjs/toolkit": "^2.2.5",
"ag-grid-community": "^32.0.0",
"ag-grid-react": "^32.0.0",
@@ -32,17 +27,12 @@
"date-fns": "^2.30.0",
"dayjs": "^1.11.12",
"file-saver": "^2.0.5",
- "framer-motion": "^10.18.0",
"i18next": "^23.11.3",
- "i18next-http-backend": "^2.5.1",
- "localforage": "^1.10.0",
"lodash": "^4.17.21",
- "match-sorter": "^6.3.4",
"notistack": "^3.0.1",
"qs": "^6.12.3",
"randomcolor": "^0.6.2",
"react": "^18.3.1",
- "react-color": "^2.19.3",
"react-datepicker": "^7.3.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.2",
@@ -51,12 +41,12 @@
"react-router-dom": "^6.22.3",
"recharts": "^2.13.3",
"sass": "^1.74.1",
- "sort-by": "^1.2.0",
"uuid": "^9.0.1",
"xlsx": "^0.18.5",
"yup": "^1.4.0"
},
"devDependencies": {
+ "@eslint/js": "^9.16.0",
"@types/file-saver": "^2.0.7",
"@types/lodash": "^4.17.7",
"@types/qs": "^6.9.15",
@@ -68,9 +58,8 @@
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"@vitejs/plugin-react": "^4.2.1",
- "eslint": "^8.57.0",
+ "eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
- "eslint-formatter-table": "^7.32.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
@@ -81,9 +70,9 @@
"eslint-plugin-security": "^3.0.0",
"eslint-plugin-sonarjs": "^1.0.3",
"eslint-plugin-unused-imports": "^3.1.0",
- "husky": "^8.0.3",
"prettier": "^3.2.5",
- "typescript": "^5.4.5",
+ "typescript": "^5.7.2",
+ "typescript-eslint": "^8.17.0",
"vite": "^4.5.3",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.3.2"
@@ -456,84 +445,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@date-io/core": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@date-io/core/-/core-3.0.0.tgz",
- "integrity": "sha512-S3j+IAQVBYNkQzchVVhX40eBkGDreBpScy9RXwTS5j2+k07+62pMVPisQ44Gq76Rqy5AOG/EZXCwBpY/jbemvA=="
- },
- "node_modules/@date-io/dayjs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-3.0.0.tgz",
- "integrity": "sha512-vy7DSwoQiPA2L0stRqW3le7lcEBMjoMMEmbpCNkyoX3xXizKInFvhbnOBmCyusIQ7tL/WsNC4X5bVgdNWX0JLA==",
- "dependencies": {
- "@date-io/core": "^3.0.0"
- },
- "peerDependencies": {
- "dayjs": "^1.8.17"
- },
- "peerDependenciesMeta": {
- "dayjs": {
- "optional": true
- }
- }
- },
- "node_modules/@devexpress/dx-core": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@devexpress/dx-core/-/dx-core-4.0.8.tgz",
- "integrity": "sha512-H5RXg4WtBfJMD/2PzakdsB0KooycTsUzJGQ1mLedsVa9HEwJDggXRhL11/oZGb03pXdxdHcCzWMQyGj0pzu1OA=="
- },
- "node_modules/@devexpress/dx-grid-core": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@devexpress/dx-grid-core/-/dx-grid-core-4.0.8.tgz",
- "integrity": "sha512-JtoX7ec7OU6xqEt2uYBRVVslaA9f9EkzQoxUTth4SZQbqvzsiQlVRQ801TJAduYwzaWuMwhlAwjY0UuJMftG3w==",
- "peerDependencies": {
- "@devexpress/dx-core": "4.0.8"
- }
- },
- "node_modules/@devexpress/dx-react-core": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@devexpress/dx-react-core/-/dx-react-core-4.0.8.tgz",
- "integrity": "sha512-+wlAnh73y1LCHhPOd9z05jV1qvzZQJIq6b4ByMbHArlhVpKEgiqE1lIF6n0Ex3q5vHqR11Djh63PUWng2m76GQ==",
- "dependencies": {
- "@devexpress/dx-core": "4.0.8",
- "prop-types": "^15.7.2"
- },
- "peerDependencies": {
- "react": ">=17.0.2",
- "react-dom": ">=17.0.2"
- }
- },
- "node_modules/@devexpress/dx-react-grid": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@devexpress/dx-react-grid/-/dx-react-grid-4.0.8.tgz",
- "integrity": "sha512-ezCAH+nRrbCJtoFUnaVmhc4uC7i7hsVg4okEol+zZRoprHZPGYjd7nAMFv09u3JvGlMF6jnW62mUdWx2z1Prtg==",
- "dependencies": {
- "@devexpress/dx-grid-core": "4.0.8"
- },
- "peerDependencies": {
- "@devexpress/dx-core": "4.0.8",
- "@devexpress/dx-react-core": "4.0.8",
- "react": ">=17.0.2",
- "react-dom": ">=17.0.2"
- }
- },
- "node_modules/@devexpress/dx-react-grid-material-ui": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/@devexpress/dx-react-grid-material-ui/-/dx-react-grid-material-ui-4.0.8.tgz",
- "integrity": "sha512-c2aUhWXZCc/D7leCf6+d6ar8Kkrxok5xRf8XzVAJ8Y/hgRR7fOEozZL7gks0RaVPwCBrWUUL7tOL8a+uRDGM5Q==",
- "dependencies": {
- "clsx": "^1.0.4",
- "prop-types": "^15.7.2"
- },
- "peerDependencies": {
- "@devexpress/dx-grid-core": "4.0.8",
- "@devexpress/dx-react-core": "4.0.8",
- "@devexpress/dx-react-grid": "4.0.8",
- "@mui/icons-material": ">=5.0.0",
- "@mui/material": ">=5.0.0",
- "react": ">=17.0.2"
- }
- },
"node_modules/@emotion/babel-plugin": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
@@ -1104,12 +1015,13 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "version": "9.16.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz",
+ "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@floating-ui/core": {
@@ -1223,13 +1135,14 @@
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.2",
+ "@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
@@ -1242,6 +1155,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -1252,6 +1166,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1277,16 +1192,8 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead",
- "dev": true
- },
- "node_modules/@icons/material": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
- "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
- "license": "MIT",
- "peerDependencies": {
- "react": "*"
- }
+ "dev": true,
+ "license": "BSD-3-Clause"
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
@@ -1684,73 +1591,6 @@
"node": ">=6"
}
},
- "node_modules/@mui/x-internals": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.23.0.tgz",
- "integrity": "sha512-bPclKpqUiJYIHqmTxSzMVZi6MH51cQsn5U+8jskaTlo3J4QiMeCYJn/gn7YbeR9GOZFp8hetyHjoQoVHKRXCig==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.25.7",
- "@mui/utils": "^5.16.6 || ^6.0.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- }
- },
- "node_modules/@mui/x-tree-view": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-7.23.0.tgz",
- "integrity": "sha512-67e+FCVMD2A5IaNettHFLUg09j+mMOWlN9f0Uw+LGePA9vLCAMFBdPZIFa18J9F3hTurNLrFzjVA0O4QfHlvrQ==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.25.7",
- "@mui/utils": "^5.16.6 || ^6.0.0",
- "@mui/x-internals": "7.23.0",
- "@types/react-transition-group": "^4.4.11",
- "clsx": "^2.1.1",
- "prop-types": "^15.8.1",
- "react-transition-group": "^4.4.5"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@emotion/react": "^11.9.0",
- "@emotion/styled": "^11.8.1",
- "@mui/material": "^5.15.14 || ^6.0.0",
- "@mui/system": "^5.15.14 || ^6.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/react": {
- "optional": true
- },
- "@emotion/styled": {
- "optional": true
- }
- }
- },
- "node_modules/@mui/x-tree-view/node_modules/clsx": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
- "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2826,16 +2666,6 @@
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
"dev": true
},
- "node_modules/astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -3151,14 +2981,6 @@
"node": ">=0.8"
}
},
- "node_modules/cross-fetch": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
- "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
- "dependencies": {
- "node-fetch": "^2.6.12"
- }
- },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -3736,16 +3558,18 @@
}
},
"node_modules/eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
@@ -3802,96 +3626,6 @@
"eslint": ">=7.0.0"
}
},
- "node_modules/eslint-formatter-table": {
- "version": "7.32.1",
- "resolved": "https://registry.npmjs.org/eslint-formatter-table/-/eslint-formatter-table-7.32.1.tgz",
- "integrity": "sha512-JYC49hAJMNjLfbgXVeQHU6ngP0M8ThgXCHLGrncYB+R/RHEhRPnLxHjolTJdb7RdQ8zcCt2F7Mrt6Ou3PwMOHw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "^4.0.0",
- "table": "^6.0.9"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/eslint-formatter-table/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/eslint-formatter-table/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/eslint-formatter-table/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/eslint-formatter-table/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/eslint-formatter-table/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint-formatter-table/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -4326,6 +4060,16 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/eslint/node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
"node_modules/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -4565,13 +4309,6 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
- "node_modules/fast-uri": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
- "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
"node_modules/fastq": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
@@ -4669,44 +4406,6 @@
"node": ">=0.8"
}
},
- "node_modules/framer-motion": {
- "version": "10.18.0",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz",
- "integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==",
- "dependencies": {
- "tslib": "^2.4.0"
- },
- "optionalDependencies": {
- "@emotion/is-prop-valid": "^0.8.2"
- },
- "peerDependencies": {
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
- },
- "peerDependenciesMeta": {
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": {
- "version": "0.8.8",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
- "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "optional": true,
- "dependencies": {
- "@emotion/memoize": "0.7.4"
- }
- },
- "node_modules/framer-motion/node_modules/@emotion/memoize": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
- "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
- "optional": true
- },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -5032,21 +4731,6 @@
"void-elements": "3.1.0"
}
},
- "node_modules/husky": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
- "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
- "dev": true,
- "bin": {
- "husky": "lib/bin.js"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/typicode"
- }
- },
"node_modules/i18next": {
"version": "23.11.5",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz",
@@ -5069,14 +4753,6 @@
"@babel/runtime": "^7.23.2"
}
},
- "node_modules/i18next-http-backend": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz",
- "integrity": "sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw==",
- "dependencies": {
- "cross-fetch": "4.0.0"
- }
- },
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -5086,11 +4762,6 @@
"node": ">= 4"
}
},
- "node_modules/immediate": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
- "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
- },
"node_modules/immer": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
@@ -5317,16 +4988,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-generator-function": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@@ -5680,27 +5341,11 @@
"node": ">= 0.8.0"
}
},
- "node_modules/lie": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
- "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
- "dependencies": {
- "immediate": "~3.0.5"
- }
- },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
- "node_modules/localforage": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
- "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
- "dependencies": {
- "lie": "3.1.1"
- }
- },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -5722,25 +5367,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
- "node_modules/lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
- "license": "MIT"
- },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
- "node_modules/lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5770,21 +5402,6 @@
"yallist": "^3.0.2"
}
},
- "node_modules/match-sorter": {
- "version": "6.3.4",
- "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz",
- "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==",
- "dependencies": {
- "@babel/runtime": "^7.23.8",
- "remove-accents": "0.5.0"
- }
- },
- "node_modules/material-colors": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
- "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==",
- "license": "ISC"
- },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5870,25 +5487,6 @@
"tslib": "^2.0.3"
}
},
- "node_modules/node-fetch": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
- "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
"node_modules/node-releases": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
@@ -5949,14 +5547,6 @@
"node": ">= 0.4"
}
},
- "node_modules/object-path": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.6.0.tgz",
- "integrity": "sha512-fxrwsCFi3/p+LeLOAwo/wyRMODZxdGBtUlWRzsEpsUVrisZbEfZ21arxLGfaWfcnqb8oHPNihIb4XPE8CQPN5A==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/object.assign": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
@@ -6357,24 +5947,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/react-color": {
- "version": "2.19.3",
- "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
- "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
- "license": "MIT",
- "dependencies": {
- "@icons/material": "^0.2.4",
- "lodash": "^4.17.15",
- "lodash-es": "^4.17.15",
- "material-colors": "^1.2.1",
- "prop-types": "^15.5.10",
- "reactcss": "^1.2.0",
- "tinycolor2": "^1.4.1"
- },
- "peerDependencies": {
- "react": "*"
- }
- },
"node_modules/react-datepicker": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.3.0.tgz",
@@ -6565,15 +6137,6 @@
"react-dom": ">=16.6.0"
}
},
- "node_modules/reactcss": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
- "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
- "license": "MIT",
- "dependencies": {
- "lodash": "^4.0.1"
- }
- },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -6692,21 +6255,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/remove-accents": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
- "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="
- },
- "node_modules/require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/reselect": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
@@ -6959,60 +6507,6 @@
"node": ">=8"
}
},
- "node_modules/slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/slice-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/slice-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/snake-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
@@ -7023,14 +6517,6 @@
"tslib": "^2.0.3"
}
},
- "node_modules/sort-by": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/sort-by/-/sort-by-1.2.0.tgz",
- "integrity": "sha512-aRyW65r3xMnf4nxJRluCg0H/woJpksU1dQxRtXYzau30sNBOmf5HACpDd9MZDhKh7ALQ5FgSOfMPwZEtUmMqcg==",
- "dependencies": {
- "object-path": "0.6.0"
- }
- },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -7059,28 +6545,6 @@
"node": ">=0.8"
}
},
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/string.prototype.matchall": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
@@ -7243,47 +6707,6 @@
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
},
- "node_modules/table": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
- "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/table/node_modules/ajv": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
- "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.3",
- "fast-uri": "^3.0.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/table/node_modules/json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -7301,12 +6724,6 @@
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
"license": "MIT"
},
- "node_modules/tinycolor2": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
- "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
- "license": "MIT"
- },
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -7331,11 +6748,6 @@
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
},
- "node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
- },
"node_modules/ts-api-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -7395,7 +6807,8 @@
"node_modules/tslib": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
- "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
+ "dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -7495,10 +6908,11 @@
}
},
"node_modules/typescript": {
- "version": "5.4.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
- "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
+ "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7507,6 +6921,244 @@
"node": ">=14.17"
}
},
+ "node_modules/typescript-eslint": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.17.0.tgz",
+ "integrity": "sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.17.0",
+ "@typescript-eslint/parser": "8.17.0",
+ "@typescript-eslint/utils": "8.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz",
+ "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/type-utils": "8.17.0",
+ "@typescript-eslint/utils": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.3.1",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
+ "eslint": "^8.57.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz",
+ "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/typescript-estree": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz",
+ "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz",
+ "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "8.17.0",
+ "@typescript-eslint/utils": "8.17.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz",
+ "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz",
+ "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/visitor-keys": "8.17.0",
+ "debug": "^4.3.4",
+ "fast-glob": "^3.3.2",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz",
+ "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "8.17.0",
+ "@typescript-eslint/types": "8.17.0",
+ "@typescript-eslint/typescript-estree": "8.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz",
+ "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.17.0",
+ "eslint-visitor-keys": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+ "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -7699,20 +7351,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
- },
- "node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index d3d7cf2..38c0eaa 100644
--- a/package.json
+++ b/package.json
@@ -13,10 +13,6 @@
"preview": "vite preview --port 5173"
},
"dependencies": {
- "@date-io/dayjs": "^3.0.0",
- "@devexpress/dx-react-core": "^4.0.6",
- "@devexpress/dx-react-grid": "^4.0.6",
- "@devexpress/dx-react-grid-material-ui": "^4.0.8",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@fullcalendar/core": "^6.1.15",
@@ -29,7 +25,6 @@
"@mui/icons-material": "^5.15.15",
"@mui/material": "^5.16.7",
"@mui/x-date-pickers": "^6.20.2",
- "@mui/x-tree-view": "^7.23.0",
"@reduxjs/toolkit": "^2.2.5",
"ag-grid-community": "^32.0.0",
"ag-grid-react": "^32.0.0",
@@ -37,17 +32,12 @@
"date-fns": "^2.30.0",
"dayjs": "^1.11.12",
"file-saver": "^2.0.5",
- "framer-motion": "^10.18.0",
"i18next": "^23.11.3",
- "i18next-http-backend": "^2.5.1",
- "localforage": "^1.10.0",
"lodash": "^4.17.21",
- "match-sorter": "^6.3.4",
"notistack": "^3.0.1",
"qs": "^6.12.3",
"randomcolor": "^0.6.2",
"react": "^18.3.1",
- "react-color": "^2.19.3",
"react-datepicker": "^7.3.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.2",
@@ -56,12 +46,12 @@
"react-router-dom": "^6.22.3",
"recharts": "^2.13.3",
"sass": "^1.74.1",
- "sort-by": "^1.2.0",
"uuid": "^9.0.1",
"xlsx": "^0.18.5",
"yup": "^1.4.0"
},
"devDependencies": {
+ "@eslint/js": "^9.16.0",
"@types/file-saver": "^2.0.7",
"@types/lodash": "^4.17.7",
"@types/qs": "^6.9.15",
@@ -73,9 +63,8 @@
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"@vitejs/plugin-react": "^4.2.1",
- "eslint": "^8.57.0",
+ "eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
- "eslint-formatter-table": "^7.32.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
@@ -86,9 +75,9 @@
"eslint-plugin-security": "^3.0.0",
"eslint-plugin-sonarjs": "^1.0.3",
"eslint-plugin-unused-imports": "^3.1.0",
- "husky": "^8.0.3",
"prettier": "^3.2.5",
- "typescript": "^5.4.5",
+ "typescript": "^5.7.2",
+ "typescript-eslint": "^8.17.0",
"vite": "^4.5.3",
"vite-plugin-svgr": "^4.2.0",
"vite-tsconfig-paths": "^4.3.2"
diff --git a/src/App.tsx b/src/App.tsx
deleted file mode 100644
index 27341e1..0000000
--- a/src/App.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Outlet } from 'react-router-dom';
-
-function App() {
- return ;
-}
-
-export default App;
diff --git a/src/assets/styles/themeStyle.scss b/src/assets/styles/themeStyle.scss
deleted file mode 100644
index b6629fd..0000000
--- a/src/assets/styles/themeStyle.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-//Accesibility
-.hide {
- display: none;
-}
-.show {
- display: unset;
-}
-
-//Size ...etc
-.fullWidth {
- width: 100%;
-}
-
-//Postion
-.moveToRight {
- margin-left: auto;
-}
-.moveToLeft {
- margin-left: auto;
-}
diff --git a/src/components/viewsComponents/personalData/IconComponent.tsx b/src/components/shared/Icon/IconComponent.tsx
similarity index 82%
rename from src/components/viewsComponents/personalData/IconComponent.tsx
rename to src/components/shared/Icon/IconComponent.tsx
index 39e8cce..862b08f 100644
--- a/src/components/viewsComponents/personalData/IconComponent.tsx
+++ b/src/components/shared/Icon/IconComponent.tsx
@@ -8,7 +8,7 @@ interface IIconComponentProps extends SvgIconProps {
name: MuiIconsNameType;
}
-const iconComponents: { [K in MuiIconsNameType]: React.ComponentType } = Icons;
+const iconComponents: Record> = Icons;
export function IconComponent({ name, ...props }: IIconComponentProps): React.ReactElement {
const SpecificIcon = iconComponents[name];
diff --git a/src/components/shared/appBar/AppBar.scss b/src/components/shared/appBar/AppBar.scss
deleted file mode 100644
index 5b438fa..0000000
--- a/src/components/shared/appBar/AppBar.scss
+++ /dev/null
@@ -1,37 +0,0 @@
-.AppBarBox {
- display: flex;
- align-items: center;
- align-content: center;
- height: 100%;
- margin-right: 4rem;
- margin-left: 4rem;
-
- @media (max-width: 600px) {
- text-wrap: nowrap;
- margin-right: 1rem;
- margin-left: 1rem;
- }
-}
-
-.AppBarHamburger {
- cursor: pointer;
- margin-right: 24px;
-
- @media (max-width: 600px) {
- margin-right: 16px;
- }
-}
-
-.ConfigAppBar {
- display: flex;
- margin-left: auto;
- button {
- min-width: min-content !important;
- }
-}
-
-@media (min-width: 910px) {
- .AppBarHamburger {
- display: none;
- }
-}
diff --git a/src/components/shared/appBar/AppBar.tsx b/src/components/shared/appBar/AppBar.tsx
index 796d221..49ceff1 100644
--- a/src/components/shared/appBar/AppBar.tsx
+++ b/src/components/shared/appBar/AppBar.tsx
@@ -1,47 +1,27 @@
-import { useEffect } from 'react';
-import { useDispatch } from 'react-redux';
import MenuIcon from '@mui/icons-material/Menu';
-import { Box, Typography, useMediaQuery } from '@mui/material';
+import { Box, Typography } from '@mui/material';
+import { useTypedDispatch } from 'hooks/useStore.Hooks';
import { useTypedMatches } from 'hooks/useTypedMatches.Hook';
-import { toggleDrawer, setDrawerState } from 'redux/stateSlices/view/View.State.Slice';
-import './AppBar.scss';
+import { toggleDrawer } from 'redux/stateSlices/view/View.State.Slice';
import AppBarConfig from './elements/AppBarConfig';
-
-const mobileBreakpoint = '(max-width:910px)';
+import './styles/AppBar.scss';
function AppBar() {
- const dispatch = useDispatch();
+ const dispatch = useTypedDispatch();
const matches = useTypedMatches();
- const currentMatch = matches.find(match => match.handle);
+ const currentMatch = matches.find(match => match.handle);
const pageTitle = currentMatch?.handle?.navigation?.text;
- const isMobile = useMediaQuery(mobileBreakpoint);
-
- useEffect(() => {
- const shouldDrawerBeOpen = !isMobile;
- dispatch(setDrawerState(shouldDrawerBeOpen));
- }, [isMobile, dispatch]);
const handleToggleDrawer = () => {
dispatch(toggleDrawer());
};
return (
-
-
-
- {pageTitle}
-
-
+
+
+ {pageTitle}
+
);
}
diff --git a/src/components/shared/appBar/constants/constants.tsx b/src/components/shared/appBar/constants/constants.tsx
new file mode 100644
index 0000000..dbabea0
--- /dev/null
+++ b/src/components/shared/appBar/constants/constants.tsx
@@ -0,0 +1,23 @@
+import { ErrorOutline, WarningAmber } from '@mui/icons-material';
+
+export enum TimerStatesEnum {
+ Critical = 'critical',
+ Warning = 'warning',
+ Normal = 'normal',
+}
+
+export interface ITimerStylesKeys {
+ color: string;
+ icon?: JSX.Element;
+}
+
+export const timerStylesByState: Record = {
+ [TimerStatesEnum.Critical]: { color: '#f70000', icon: },
+ [TimerStatesEnum.Warning]: { color: '#ff9800', icon: },
+ [TimerStatesEnum.Normal]: { color: 'black' },
+};
+
+export const timeThresholds = [
+ { minutes: 5, state: TimerStatesEnum.Critical },
+ { minutes: 10, state: TimerStatesEnum.Warning },
+];
diff --git a/src/components/shared/appBar/elements/AppBarConfig.tsx b/src/components/shared/appBar/elements/AppBarConfig.tsx
index 93baa27..79dbe23 100644
--- a/src/components/shared/appBar/elements/AppBarConfig.tsx
+++ b/src/components/shared/appBar/elements/AppBarConfig.tsx
@@ -1,38 +1,9 @@
-import { useTranslation } from 'react-i18next';
import { Box } from '@mui/material';
-import EnglandCircle from 'assets/icons/EnglandCircle.svg?react';
-import PolandCircle from 'assets/icons/PolandCircle.svg?react';
import AppBarTimer from './AppBarTimer';
-export function useLanguageMenuItems() {
- const { t, i18n } = useTranslation();
-
- const changeLanguage = (language: string) => {
- i18n.changeLanguage(language);
- };
-
- return [
- {
- label: t('polish'),
- onClick: () => {
- changeLanguage('pl');
- },
- icon: ,
- },
- {
- label: t('english'),
- onClick: () => {
- changeLanguage('en');
- },
- icon: ,
- },
- ];
-}
-
function AppBarConfig() {
return (
- {/* } hideLabelOnMobile /> */}
);
diff --git a/src/components/shared/appBar/elements/AppBarTimer.tsx b/src/components/shared/appBar/elements/AppBarTimer.tsx
index 32488bb..e06f505 100644
--- a/src/components/shared/appBar/elements/AppBarTimer.tsx
+++ b/src/components/shared/appBar/elements/AppBarTimer.tsx
@@ -1,77 +1,29 @@
-import { useLayoutEffect, useMemo, useState } from 'react';
-import { useSelector } from 'react-redux';
-import { ErrorOutline, WarningAmber } from '@mui/icons-material';
+import { useEffect } from 'react';
import { Box, Typography, useMediaQuery } from '@mui/material';
-import { parseISO, isAfter, intervalToDuration } from 'date-fns';
-import _ from 'lodash';
+import { isAfter, parseISO } from 'date-fns';
+import { useAppBarTimer } from 'hooks/useAppBarTimer';
+import { useTypedSelector } from 'hooks/useStore.Hooks';
import { useSendLogoutMutation } from 'redux/apiSlices/auth/Auth.Api.Slice';
import { selectTokenExpirationTime } from 'redux/stateSlices/auth/Auth.State.Slice';
+import { timerStylesByState } from '../constants/constants';
import AppBarExtSessionIcon from './AppBarExtSessionIcon';
-export enum TimerStatesEnum {
- Critical = 'critical',
- Warning = 'warning',
- Normal = 'normal',
-}
-
-interface ITimeThresholds {
- minutes: number;
- state: TimerStatesEnum;
-}
-
-interface ITimerStylesKeys {
- color: string;
- icon?: JSX.Element;
-}
-
-const timerStylesByState: Record = {
- [TimerStatesEnum.Critical]: { color: '#f70000', icon: },
- [TimerStatesEnum.Warning]: { color: '#ff9800', icon: },
- [TimerStatesEnum.Normal]: { color: 'black' },
-};
-
-const timeThresholds: ITimeThresholds[] = [
- { minutes: 5, state: TimerStatesEnum.Critical },
- { minutes: 10, state: TimerStatesEnum.Warning },
-];
-
function AppBarTimer() {
- const [sendLogout] = useSendLogoutMutation();
- const tokenExpirationTime = useSelector(selectTokenExpirationTime);
- const [timeLeft, setTimeLeft] = useState('');
- const [timerState, setTimerState] = useState(TimerStatesEnum.Normal);
+ const tokenExpirationTime = useTypedSelector(selectTokenExpirationTime);
const isMobile = useMediaQuery('(max-width:600px)');
+ const { timeLeft, timerState } = useAppBarTimer();
+ const { color, icon } = timerStylesByState[timerState];
+ const [sendLogout] = useSendLogoutMutation();
- useLayoutEffect(() => {
- const updateTimer = async () => {
- const now = new Date();
- const expirationDate = parseISO(tokenExpirationTime ?? '');
-
- if (isAfter(now, expirationDate)) {
- clearInterval(timerId);
- await sendLogout();
- return;
- }
-
- const { minutes = 0, seconds = 0 } = intervalToDuration({ start: now, end: expirationDate });
- const matchingThreshold = _.find(timeThresholds, threshold => minutes < threshold.minutes);
- const formattedTime = `${_.padStart(minutes.toString(), 2, '0')}:${_.padStart(seconds.toString(), 2, '0')}`;
-
- setTimeLeft(formattedTime);
- setTimerState(matchingThreshold?.state ?? TimerStatesEnum.Normal);
- };
-
- const timerId = setInterval(updateTimer, 1000);
-
- return () => {
- clearInterval(timerId);
- };
- }, [tokenExpirationTime]);
-
- const { color, icon } = useMemo(() => timerStylesByState[timerState], [timerState]);
+ useEffect(() => {
+ if (!tokenExpirationTime || isAfter(new Date(), parseISO(tokenExpirationTime))) {
+ sendLogout();
+ return;
+ }
+ }, [timeLeft]);
return (
-
+
{icon}
{!isMobile && 'Timer:'} {timeLeft}
diff --git a/src/components/shared/appBar/styles/AppBar.scss b/src/components/shared/appBar/styles/AppBar.scss
new file mode 100644
index 0000000..bb97bdc
--- /dev/null
+++ b/src/components/shared/appBar/styles/AppBar.scss
@@ -0,0 +1,36 @@
+.AppBarBox {
+ height: 80px;
+ background: white;
+ padding: 0rem 4rem;
+ display: flex;
+ align-items: center;
+ align-content: center;
+ position: sticky;
+ top: 0;
+ z-index: 2;
+
+ @media (max-width: 600px) {
+ padding: 0rem 1rem;
+ }
+
+ .ConfigAppBar {
+ display: flex;
+ margin-left: auto;
+
+ button {
+ min-width: min-content !important;
+ }
+ }
+
+ .AppBarHamburger {
+ margin-right: 16px;
+ cursor: pointer;
+
+ @media (min-width: 910px) {
+ display: none;
+ }
+ }
+}
+
+
+
diff --git a/src/components/shared/appBar/utils/Timer.Utils.tsx b/src/components/shared/appBar/utils/Timer.Utils.tsx
new file mode 100644
index 0000000..0a7221c
--- /dev/null
+++ b/src/components/shared/appBar/utils/Timer.Utils.tsx
@@ -0,0 +1,20 @@
+import { intervalToDuration } from 'date-fns';
+import _ from 'lodash';
+import { TimerStatesEnum, timeThresholds } from '../constants/constants';
+
+interface ICaluclateTimeLeft {
+ minutes: number;
+ seconds: number;
+ formattedTime: string;
+}
+
+export const calculateTimeLeft = (expirationDate: Date): ICaluclateTimeLeft => {
+ const now = new Date();
+ const { minutes = 0, seconds = 0 } = intervalToDuration({ start: now, end: expirationDate });
+ const formattedTime = `${_.padStart(minutes.toString(), 2, '0')}:${_.padStart(seconds.toString(), 2, '0')}`;
+ return { minutes, seconds, formattedTime };
+};
+
+export const getTimerState = (minutes: number): TimerStatesEnum => {
+ return _.find(timeThresholds, threshold => minutes < threshold.minutes)?.state ?? TimerStatesEnum.Normal;
+};
diff --git a/src/components/shared/centeredLoader/CenteredLoader.tsx b/src/components/shared/centeredLoader/CenteredLoader.tsx
index 5f4e373..a6d0279 100644
--- a/src/components/shared/centeredLoader/CenteredLoader.tsx
+++ b/src/components/shared/centeredLoader/CenteredLoader.tsx
@@ -1,6 +1,6 @@
import { CircularProgress, Box } from '@mui/material';
-function CenteredLoader() {
+const CenteredLoader = () => {
return (
);
-}
+};
export default CenteredLoader;
diff --git a/src/components/shared/dataGrid/elements/pagination/PageSizeSelect.tsx b/src/components/shared/dataGrid/elements/pagination/PageSizeSelect.tsx
index 674482a..7af1fc1 100644
--- a/src/components/shared/dataGrid/elements/pagination/PageSizeSelect.tsx
+++ b/src/components/shared/dataGrid/elements/pagination/PageSizeSelect.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { Select, MenuItem, type SelectChangeEvent } from '@mui/material';
-import { beautifyNumbers } from 'routes/utils/Decorators';
+import { beautifyNumbers } from 'utils/general/Decorators';
interface IPageSizeSelectProps {
value: number;
diff --git a/src/components/shared/dataGrid/elements/pagination/PaginationOptions.tsx b/src/components/shared/dataGrid/elements/pagination/PaginationOptions.tsx
index fed9e11..4e412cb 100644
--- a/src/components/shared/dataGrid/elements/pagination/PaginationOptions.tsx
+++ b/src/components/shared/dataGrid/elements/pagination/PaginationOptions.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { Box, Typography, type SelectChangeEvent } from '@mui/material';
-import { beautifyNumbers } from 'routes/utils/Decorators';
+import { beautifyNumbers } from 'utils/general/Decorators';
import PageSizeSelect from './PageSizeSelect';
interface IPaginationOptionsProps {
diff --git a/src/routes/shared/error/ErrorPage.tsx b/src/components/shared/errorPage/ErrorPage.tsx
similarity index 75%
rename from src/routes/shared/error/ErrorPage.tsx
rename to src/components/shared/errorPage/ErrorPage.tsx
index aac979f..4f15901 100644
--- a/src/routes/shared/error/ErrorPage.tsx
+++ b/src/components/shared/errorPage/ErrorPage.tsx
@@ -4,22 +4,17 @@ import { useNavigate, useRouteError } from 'react-router-dom';
import { enqueueSnackbar } from 'notistack';
import { selectCurrentToken } from 'redux/stateSlices/auth/Auth.State.Slice';
-function ErrorPage() {
- const isAuthenticated = useSelector(selectCurrentToken);
+const ErrorPage = () => {
const navigate = useNavigate();
const error = useRouteError();
+ const isAuthenticated = useSelector(selectCurrentToken);
useEffect(() => {
- if (isAuthenticated) {
- navigate('postAuth/dashboard');
- } else {
- navigate('/login');
- }
-
+ navigate(isAuthenticated ? 'postAuth/dashboard' : '/login');
enqueueSnackbar(`Something went wrong. Logs were sent to Admin`, { variant: 'error' });
- }, [isAuthenticated, navigate, error]);
+ }, [isAuthenticated, error]);
return null;
-}
+};
export default ErrorPage;
diff --git a/src/components/shared/navigation/Navigation.tsx b/src/components/shared/navigation/Navigation.tsx
index ac75f46..45a1d23 100644
--- a/src/components/shared/navigation/Navigation.tsx
+++ b/src/components/shared/navigation/Navigation.tsx
@@ -1,12 +1,11 @@
-import { useState, useCallback } from 'react';
-import { useDispatch } from 'react-redux';
+import { useState, useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import MenuIcon from '@mui/icons-material/Menu';
import { Box, Divider, List, Collapse } from '@mui/material';
import useMediaQuery from '@mui/material/useMediaQuery';
-import { useTypedSelector } from 'hooks/useStore.Hooks';
+import { useTypedDispatch, useTypedSelector } from 'hooks/useStore.Hooks';
import { selectCurrentToken, selectUserRoles } from 'redux/stateSlices/auth/Auth.State.Slice';
-import { selectIsDrawerOpen, toggleDrawer } from 'redux/stateSlices/view/View.State.Slice';
+import { selectIsDrawerOpen, setDrawerState, toggleDrawer } from 'redux/stateSlices/view/View.State.Slice';
import Logo from 'assets/images/Logo.png';
import UserProfile from './elements/headerItems/UserProfile';
import MenuItemComponent from './elements/menuItems/MenuItem';
@@ -14,7 +13,7 @@ import { Drawer } from './Styled';
import type { INavigationProps, OpenMenuItemsStateType } from './types/types';
function Navigation({ menuItems }: INavigationProps) {
- const dispatch = useDispatch();
+ const dispatch = useTypedDispatch();
const navigate = useNavigate();
const isMenuFullWidth = useMediaQuery('(max-width:910px)');
@@ -43,6 +42,10 @@ function Navigation({ menuItems }: INavigationProps) {
setOpenMenuItems(prevState => ({ ...prevState, [id]: !prevState[id] }));
}, []);
+ useEffect(() => {
+ dispatch(setDrawerState(!isMenuFullWidth));
+ }, [isMenuFullWidth, dispatch]);
+
return (
diff --git a/src/components/shared/todoListDrawer/TodoListDrawer.tsx b/src/components/shared/todoListDrawer/TodoListDrawer.tsx
index de75bbd..2dcb957 100644
--- a/src/components/shared/todoListDrawer/TodoListDrawer.tsx
+++ b/src/components/shared/todoListDrawer/TodoListDrawer.tsx
@@ -7,13 +7,11 @@ import { useGetStudentTodosQuery } from 'redux/apiSlices/students/Students.Api.S
import TaskCard from './elements/TaskCard';
import TodoCreateDialog from './elements/TodoCreateDialog';
-interface ITodoListDrawerProps {
- maxDrawerWidth: number;
-}
-
-const TodoListDrawer = ({ maxDrawerWidth }: ITodoListDrawerProps) => {
+const TodoListDrawer = () => {
const studentId = useSelector(selectId)!;
+ const isMobile = useMediaQuery('(max-width: 600px)');
const isEnoughSpaceForDrawer = useMediaQuery('(min-width: 1400px)');
+ const maxDrawerWidth = isMobile ? 280 : 450;
const [openDrawer, setOpenDrawer] = useState(isEnoughSpaceForDrawer);
const [openDialog, setOpenDialog] = useState(false);
const { data: tasks } = useGetStudentTodosQuery({ studentId }, { skip: !studentId });
diff --git a/src/components/viewsComponents/courses/Courses.tsx b/src/components/viewsComponents/courses/Courses.tsx
index 1354df9..adfd17e 100644
--- a/src/components/viewsComponents/courses/Courses.tsx
+++ b/src/components/viewsComponents/courses/Courses.tsx
@@ -25,46 +25,6 @@ function Courses() {
return ;
}
- const renderModules = (modules: IStudentCoursesModule[], level = 0) =>
- modules.map(module => (
-
-
-
- ({
- id: subject.id,
- name: subject.name,
- grade: subject.grade,
- }))}
- columnDefs={gradesColumns}
- />
-
-
- ));
-
- const renderDegreePath = (degreePath: IStudentCoursesDegreePath, level = 0) => (
-
-
- {renderModules(degreePath.modules, level + 1)}
-
- );
-
- const renderCourseSubjects = (subjects: IStudentCourseSubject[]) => (
-
-
-
- ({
- id: subject.id,
- name: subject.name,
- grade: subject.grade,
- }))}
- columnDefs={gradesColumns}
- />
-
-
- );
-
return (
{data ? (
@@ -81,3 +41,43 @@ function Courses() {
}
export default Courses;
+
+const renderModules = (modules: IStudentCoursesModule[], level = 0) =>
+ modules.map(module => (
+
+
+
+ ({
+ id: subject.id,
+ name: subject.name,
+ grade: subject.grade,
+ }))}
+ columnDefs={gradesColumns}
+ />
+
+
+ ));
+
+const renderDegreePath = (degreePath: IStudentCoursesDegreePath, level = 0) => (
+
+
+ {renderModules(degreePath.modules, level + 1)}
+
+);
+
+const renderCourseSubjects = (subjects: IStudentCourseSubject[]) => (
+
+
+
+ ({
+ id: subject.id,
+ name: subject.name,
+ grade: subject.grade,
+ }))}
+ columnDefs={gradesColumns}
+ />
+
+
+);
diff --git a/src/components/viewsComponents/courses/elements/AccordionSummaryWrapper.tsx b/src/components/viewsComponents/courses/elements/AccordionSummaryWrapper.tsx
index 1897d70..09885b1 100644
--- a/src/components/viewsComponents/courses/elements/AccordionSummaryWrapper.tsx
+++ b/src/components/viewsComponents/courses/elements/AccordionSummaryWrapper.tsx
@@ -12,7 +12,6 @@ interface AccordionSummaryWrapperProps {
const AccordionSummaryWrapper: React.FC = ({ level, title }) => {
const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
-
const marginLeft = isSmallScreen ? level * 1.2 : level * 4;
return (
diff --git a/src/components/viewsComponents/dashboard/Dashboard.scss b/src/components/viewsComponents/dashboard/Dashboard.scss
deleted file mode 100644
index 0b1c799..0000000
--- a/src/components/viewsComponents/dashboard/Dashboard.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.DashboardBasicInfoBox {
- display: grid;
- grid-template-columns: -webkit-min-content auto;
- grid-template-columns: min-content auto;
- gap: 16px;
- margin-bottom: 16px;
-}
diff --git a/src/components/viewsComponents/dashboard/Dashboard.tsx b/src/components/viewsComponents/dashboard/Dashboard.tsx
index 75c9223..7f1666a 100644
--- a/src/components/viewsComponents/dashboard/Dashboard.tsx
+++ b/src/components/viewsComponents/dashboard/Dashboard.tsx
@@ -1,5 +1,5 @@
import { useSelector } from 'react-redux';
-import { Box, useMediaQuery } from '@mui/material';
+import { Box } from '@mui/material';
import CenteredLoader from 'components/shared/centeredLoader/CenteredLoader';
import TodoListDrawer from 'components/shared/todoListDrawer/TodoListDrawer';
import { useGetStudentGradesQuery } from 'redux/apiSlices/academics/Grades.Api.Slice';
@@ -8,46 +8,34 @@ import Announcements from './elements/Announcements';
import ClosestEvents from './elements/ClosestEvents';
import GradesSection from './elements/GradesSection';
import type { IGetStudentGradesQueryParams } from 'contract/slices/academics/Grades.Interfaces';
-import './Dashboard.scss';
+import './styles/Dashboard.scss';
function Dashboard() {
- const isMobile = useMediaQuery('(max-width: 500px)');
- const maxDrawerWidth = isMobile ? 280 : 450;
-
- const { data: userData, isFetching: isFetchingUserData } = useGetLoggedAccountBasicDataQuery();
-
const studentId = useSelector(selectId);
const initialQueryParams: IGetStudentGradesQueryParams = { studentId: studentId! };
- const { data: grades, isFetching: isFetchingGrades } = useGetStudentGradesQuery(initialQueryParams, {
+ const { data: userData, isFetching: isFetchingUserData } = useGetLoggedAccountBasicDataQuery();
+ const { data: grades = [], isFetching: isFetchingGrades } = useGetStudentGradesQuery(initialQueryParams, {
skip: !studentId,
});
- const isFetching = isFetchingUserData || isFetchingGrades;
-
- if (isFetching || !userData) {
+ if (isFetchingUserData || isFetchingGrades) {
return ;
}
- return (
-
-
-
-
-
-
+ if (!userData) {
+ return;
+ }
-
+ return (
+ <>
+
+
+
-
-
-
+ {/* Need refactor */}
+
+
+ >
);
}
diff --git a/src/components/viewsComponents/dashboard/elements/ClosestEvents.tsx b/src/components/viewsComponents/dashboard/elements/ClosestEvents.tsx
index fe02b2f..564b449 100644
--- a/src/components/viewsComponents/dashboard/elements/ClosestEvents.tsx
+++ b/src/components/viewsComponents/dashboard/elements/ClosestEvents.tsx
@@ -1,10 +1,10 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import EventIcon from '@mui/icons-material/Event';
import { Typography, List, ListItem, Paper, Box } from '@mui/material';
import { staticEvents } from 'routes/postAuth/events/EventsData';
-const ClosestEvents: React.FC = () => {
+const ClosestEvents = () => {
const now = new Date();
const navigate = useNavigate();
diff --git a/src/components/viewsComponents/dashboard/elements/CustomGradesDonutTooltip.tsx b/src/components/viewsComponents/dashboard/elements/CustomGradesDonutTooltip.tsx
new file mode 100644
index 0000000..45b8c8d
--- /dev/null
+++ b/src/components/viewsComponents/dashboard/elements/CustomGradesDonutTooltip.tsx
@@ -0,0 +1,44 @@
+import { Box } from '@mui/material';
+
+interface CustomTooltipProps {
+ active?: boolean;
+ payload?: {
+ payload: {
+ grade: string;
+ count: number;
+ fill: string;
+ };
+ }[];
+}
+
+const CustomGradesDonutTooltip: React.FC = ({ active, payload }) => {
+ if (active && payload?.length && payload[0]) {
+ const { grade, fill } = payload[0].payload;
+
+ return (
+
+
+ {grade}
+
+
+ );
+ }
+
+ return null;
+};
+
+export default CustomGradesDonutTooltip;
diff --git a/src/components/viewsComponents/dashboard/elements/GradesDonutChart.tsx b/src/components/viewsComponents/dashboard/elements/GradesDonutChart.tsx
index 453bfda..f8d5177 100644
--- a/src/components/viewsComponents/dashboard/elements/GradesDonutChart.tsx
+++ b/src/components/viewsComponents/dashboard/elements/GradesDonutChart.tsx
@@ -1,53 +1,16 @@
import React from 'react';
-import { Box } from '@mui/material';
import { PieChart, Pie, Cell, Tooltip } from 'recharts';
+import CustomGradesDonutTooltip from './CustomGradesDonutTooltip';
interface GradesDonutChartProps {
- groupedData: { grade: string; count: number; fill: string }[];
- averageGrade: string;
-}
-
-interface CustomTooltipProps {
- active?: boolean;
- payload?: {
- payload: {
- grade: string;
- count: number;
- fill: string;
- };
+ groupedData: {
+ grade: string;
+ count: number;
+ fill: string;
}[];
+ averageGrade: string;
}
-const CustomTooltip: React.FC = ({ active, payload }) => {
- if (active && payload?.length && payload[0]) {
- const { grade, fill } = payload[0].payload;
-
- return (
-
-
- {grade}
-
-
- );
- }
-
- return null;
-};
-
const GradesDonutChart: React.FC = ({ groupedData, averageGrade }) => {
return (
@@ -79,7 +42,7 @@ const GradesDonutChart: React.FC = ({ groupedData, averag
Your Current GPA
- } />
+ } />
);
};
diff --git a/src/components/viewsComponents/dashboard/elements/GradesSection.tsx b/src/components/viewsComponents/dashboard/elements/GradesSection.tsx
index 80b7822..0917821 100644
--- a/src/components/viewsComponents/dashboard/elements/GradesSection.tsx
+++ b/src/components/viewsComponents/dashboard/elements/GradesSection.tsx
@@ -1,21 +1,19 @@
import { useNavigate } from 'react-router-dom';
-import { Typography, Paper, Box, Button, useMediaQuery } from '@mui/material';
-import { calculateAverageGrade } from 'components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes';
+import { Typography, Paper, Box, Button } from '@mui/material';
+import { calculateAverageGrade } from 'components/viewsComponents/grades/utils/Helpers';
import _ from 'lodash';
import GradesDonutChart from './GradesDonutChart';
import type { IGrade } from 'contract/interfaces/academics/Academics';
import type { IGetLoggedAccountBasicDataTransformedReponse } from 'contract/slices/loggedAccount/LoggedAccount';
interface GradesSectionProps {
- grades?: IGrade[];
+ grades: IGrade[];
userData: IGetLoggedAccountBasicDataTransformedReponse;
}
-const GradesSection: React.FC = ({ grades, userData }) => {
+const GradesSection: React.FC = ({ grades, userData: { name, surname } }) => {
const navigate = useNavigate();
- const isMobile = useMediaQuery('(max-width:800px)');
-
- const averageGrade = calculateAverageGrade(grades ?? []);
+ const averageGrade = calculateAverageGrade(grades);
const gradeGroups = _.groupBy(grades, 'grade');
const groupedData = [
{ grade: '2', count: gradeGroups[2]?.length ?? 0, fill: '#c40101' },
@@ -25,27 +23,10 @@ const GradesSection: React.FC = ({ grades, userData }) => {
];
return (
-
-
+
+
- Hi, {`${userData.name} ${userData.surname}!`}
+ Hi, {`${name} ${surname}!`}
Check your performance stats
to make sure you are on track
with your academic goals!
@@ -53,9 +34,7 @@ const GradesSection: React.FC = ({ grades, userData }) => {
diff --git a/src/components/viewsComponents/dashboard/styles/Dashboard.scss b/src/components/viewsComponents/dashboard/styles/Dashboard.scss
new file mode 100644
index 0000000..695dcdf
--- /dev/null
+++ b/src/components/viewsComponents/dashboard/styles/Dashboard.scss
@@ -0,0 +1,34 @@
+.DashboardBasicInfoBox {
+ display: grid;
+ grid-template-columns: -webkit-min-content auto;
+ grid-template-columns: min-content auto;
+ gap: 16px;
+ margin-bottom: 16px;
+}
+
+.GradesSectionContainer {
+ width: fit-content;
+ padding: 32px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ flex-basis: 550px;
+ flex-grow: 1;
+
+ .InfoBox {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ min-width: 200px;
+ }
+
+
+ @media (max-width: 900px) {
+ flex-basis: 350px;
+ flex-grow: 0;
+ padding: 16px;
+ }
+}
+
+
+
diff --git a/src/components/viewsComponents/events/eventShowDialog/EventShowDialog.tsx b/src/components/viewsComponents/events/eventShowDialog/EventShowDialog.tsx
index 4885fb0..3b4a894 100644
--- a/src/components/viewsComponents/events/eventShowDialog/EventShowDialog.tsx
+++ b/src/components/viewsComponents/events/eventShowDialog/EventShowDialog.tsx
@@ -1,6 +1,6 @@
import type { ReactElement } from 'react';
import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Box, Divider } from '@mui/material';
-import { formatFullDateTime } from 'routes/utils/Date.Utils';
+import { formatFullDateTime } from 'utils/general/Date.Utils';
import type { IEventShowDialog } from 'types/events/Events.Interfaces';
const EventShowDialog = ({ onClose, event }: IEventShowDialog): ReactElement => {
diff --git a/src/components/viewsComponents/grades/Grades.tsx b/src/components/viewsComponents/grades/Grades.tsx
index 1ce891a..f815130 100644
--- a/src/components/viewsComponents/grades/Grades.tsx
+++ b/src/components/viewsComponents/grades/Grades.tsx
@@ -11,7 +11,7 @@ const Grades = () => {
const studentId = useSelector(selectId);
const initialQueryParams: IGetStudentGradesQueryParams = { studentId: studentId! };
- const { data: grades, isFetching } = useGetStudentGradesQuery(initialQueryParams, { skip: !studentId });
+ const { data: grades = [], isFetching } = useGetStudentGradesQuery(initialQueryParams, { skip: !studentId });
if (isFetching) {
return ;
@@ -20,8 +20,8 @@ const Grades = () => {
return (
<>
-
-
+
+
>
);
};
diff --git a/src/components/viewsComponents/grades/constants/Cards.tsx b/src/components/viewsComponents/grades/constants/Cards.tsx
new file mode 100644
index 0000000..32b8986
--- /dev/null
+++ b/src/components/viewsComponents/grades/constants/Cards.tsx
@@ -0,0 +1,77 @@
+import { EqualizerRounded, ErrorOutline, CheckCircleOutline, Warning, InfoOutlined } from '@mui/icons-material';
+import { GradeValueEnum } from 'contract/enums/Enums';
+import _ from 'lodash';
+import { calculateAverageGrade, calculatePercentage } from '../utils/Helpers';
+import type { IGrade } from 'contract/interfaces/academics/Academics';
+
+interface IGradeCard {
+ id: number;
+ icon: JSX.Element;
+ title: string;
+ text: string;
+ color: string;
+ hideWhen?: boolean;
+}
+
+export const useGradesCards = (grades: IGrade[]): IGradeCard[] => {
+ const gradesCount = grades.length;
+ const highestGradesCount = _.filter(grades, { grade: GradeValueEnum.Excellent }).length;
+ const underPerformingGradesCount = _.filter(grades, { grade: GradeValueEnum.Fair }).length;
+ const notPassedGradesCount = _.filter(grades, { grade: GradeValueEnum.Poor }).length;
+
+ return [
+ {
+ id: 5,
+ icon: ,
+ title: calculateAverageGrade(grades),
+ text: 'Average from your grades',
+ color: '#bbdefb',
+ },
+ {
+ id: 1,
+ icon: ,
+ title: calculatePercentage(notPassedGradesCount, gradesCount),
+ text: 'Not passed subjects',
+ color: '#ffc1b5',
+ hideWhen: notPassedGradesCount === 0,
+ },
+ {
+ id: 6,
+ icon: ,
+ title: '100%',
+ text: 'All subjects passed',
+ color: '#a5e8a7',
+ hideWhen: notPassedGradesCount > 0,
+ },
+ {
+ id: 2,
+ icon: ,
+ title: highestGradesCount.toString(),
+ text: 'Amount of highest rate grade',
+ color: '#a5e8a7',
+ },
+ {
+ id: 3,
+ icon: ,
+ title: calculatePercentage(underPerformingGradesCount, gradesCount),
+ text: 'Underperforming grades',
+ color: '#ffecb3',
+ hideWhen: underPerformingGradesCount === 0,
+ },
+ {
+ id: 7,
+ icon: ,
+ title: '0%',
+ text: 'No underperforming grades',
+ color: '#a5e8a7',
+ hideWhen: underPerformingGradesCount > 0,
+ },
+ {
+ id: 4,
+ icon: ,
+ title: gradesCount.toString(),
+ text: 'Total subjects you are enrolled in',
+ color: '#bbdefb',
+ },
+ ].filter(card => !card.hideWhen);
+};
diff --git a/src/components/viewsComponents/grades/elements/gradesDataGrid/Columns.tsx b/src/components/viewsComponents/grades/constants/Columns.tsx
similarity index 70%
rename from src/components/viewsComponents/grades/elements/gradesDataGrid/Columns.tsx
rename to src/components/viewsComponents/grades/constants/Columns.tsx
index c9d8a94..a873f91 100644
--- a/src/components/viewsComponents/grades/elements/gradesDataGrid/Columns.tsx
+++ b/src/components/viewsComponents/grades/constants/Columns.tsx
@@ -5,16 +5,21 @@ import { GradeValueEnum } from 'contract/enums/Enums';
import type { ColDef } from 'ag-grid-community';
import type { IGrade } from 'contract/interfaces/academics/Academics';
-const PassedChipRenderer = ({ value }: { value: 'Passed' | 'Not passed' | null }) => {
+enum PassStatusEnum {
+ Passed = 'Passed',
+ NotPassed = 'Not Passed',
+}
+
+const PassedChipRenderer = ({ value }: { value: PassStatusEnum | null }) => {
if (value === null) {
- return <> >;
+ return null;
}
- if (value === 'Passed') {
- return } />;
+ if (value === PassStatusEnum.Passed) {
+ return } />;
}
- return } />;
+ return } />;
};
interface IExtendedColumns extends IGrade {
@@ -59,7 +64,7 @@ export const gradesColumns: ColDef[] = [
return null;
}
- return grade > GradeValueEnum.Poor ? 'Passed' : 'Not passed';
+ return grade > GradeValueEnum.Poor ? PassStatusEnum.Passed : PassStatusEnum.NotPassed;
},
cellRenderer: PassedChipRenderer,
},
diff --git a/src/components/viewsComponents/grades/elements/gradesChartCustomTooltip/GradesChartCustomTooltip.tsx b/src/components/viewsComponents/grades/elements/gradesChartCustomTooltip/GradesChartCustomTooltip.tsx
new file mode 100644
index 0000000..ea5fdf0
--- /dev/null
+++ b/src/components/viewsComponents/grades/elements/gradesChartCustomTooltip/GradesChartCustomTooltip.tsx
@@ -0,0 +1,32 @@
+import { Box, Typography } from '@mui/material';
+
+interface ICustomTooltipProps {
+ active?: boolean;
+ payload?: { payload: { grade: number; count: number } }[];
+}
+
+const GradesChartCustomTooltip: React.FC = ({ active, payload }) => {
+ if (active && payload?.[0]) {
+ const { grade, count } = payload[0].payload;
+
+ return (
+
+
+ Grade: {grade}
+
+ Amount: {count}
+
+ );
+ }
+
+ return null;
+};
+
+export default GradesChartCustomTooltip;
diff --git a/src/components/viewsComponents/grades/elements/gradesDataGrid/GradesDataGrid.tsx b/src/components/viewsComponents/grades/elements/gradesDataGrid/GradesDataGrid.tsx
index 68f60b7..45f144a 100644
--- a/src/components/viewsComponents/grades/elements/gradesDataGrid/GradesDataGrid.tsx
+++ b/src/components/viewsComponents/grades/elements/gradesDataGrid/GradesDataGrid.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import DataGrid, { SearchBarVariantEnum } from 'components/shared/dataGrid/DataGrid';
-import { gradesColumns } from './Columns';
+import { gradesColumns } from '../../constants/Columns';
import type { IGrade } from 'contract/interfaces/academics/Academics';
interface IGradesDataGridProps {
diff --git a/src/components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes.tsx b/src/components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes.tsx
index e8752a5..60f5a24 100644
--- a/src/components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes.tsx
+++ b/src/components/viewsComponents/grades/elements/gradesInformationBoxes/GradesInformationBoxes.tsx
@@ -1,76 +1,14 @@
-import { ErrorOutline, CheckCircleOutline, Warning, InfoOutlined, EqualizerRounded } from '@mui/icons-material';
import { Box } from '@mui/material';
import SummaryCard from 'components/shared/summaryCard/SummaryCard';
-import { GradeValueEnum } from 'contract/enums/Enums';
-import _ from 'lodash';
+import { useGradesCards } from '../../constants/Cards';
import type { IGrade } from 'contract/interfaces/academics/Academics';
interface IGradesInformationBoxes {
- grades?: IGrade[];
+ grades: IGrade[];
}
const GradesInformationBoxes = ({ grades }: IGradesInformationBoxes) => {
- const data = grades ?? [];
- const gradesCount = data.length;
- const highestGradesCount = _.filter(grades, { grade: GradeValueEnum.Excellent }).length;
- const underPerformingGradesCount = _.filter(grades, { grade: GradeValueEnum.Fair }).length;
- const notPassedGradesCount = _.filter(grades, { grade: GradeValueEnum.Poor }).length;
-
- const cards = [
- {
- id: 5,
- icon: ,
- title: calculateAverageGrade(data),
- text: 'Average from your grades',
- color: '#bbdefb',
- },
- {
- id: 1,
- icon: ,
- title: calculatePercentage(notPassedGradesCount, gradesCount),
- text: 'Not passed subjects',
- color: '#ffc1b5',
- hideWhen: notPassedGradesCount === 0,
- },
- {
- id: 6,
- icon: ,
- title: '100%',
- text: 'All subjects passed',
- color: '#a5e8a7',
- hideWhen: notPassedGradesCount > 0,
- },
- {
- id: 2,
- icon: ,
- title: highestGradesCount.toString(),
- text: 'Amount of highest rate grade',
- color: '#a5e8a7',
- },
- {
- id: 3,
- icon: ,
- title: calculatePercentage(underPerformingGradesCount, gradesCount),
- text: 'Underperforming grades',
- color: '#ffecb3',
- hideWhen: underPerformingGradesCount === 0,
- },
- {
- id: 7,
- icon: ,
- title: '0%',
- text: 'No underperforming grades',
- color: '#a5e8a7',
- hideWhen: underPerformingGradesCount > 0,
- },
- {
- id: 4,
- icon: ,
- title: gradesCount.toString(),
- text: 'Total subjects you are enrolled in',
- color: '#bbdefb',
- },
- ].filter(card => card.hideWhen === false || card.hideWhen === undefined);
+ const cards = useGradesCards(grades);
return (
{
width: '100%',
}}
>
- {cards.map(card => (
-
+ {cards.map(({ id, icon, title, text, color }) => (
+
))}
);
};
export default GradesInformationBoxes;
-
-export const calculateAverageGrade = (gradesList: IGrade[]): string => {
- if (gradesList.length === 0) {
- return '0.00';
- }
-
- const validGrades = _.map(gradesList, 'grade').filter(Number);
- const average = _.mean(validGrades);
-
- return average.toFixed(2);
-};
-
-const calculatePercentage = (count: number, gradesCount: number): string => {
- if (gradesCount === 0) {
- return '0%';
- }
-
- return `${Math.round((count / gradesCount) * 100)}%`;
-};
diff --git a/src/components/viewsComponents/grades/elements/gradesSummarizeChart/GradesSummarizeChart.tsx b/src/components/viewsComponents/grades/elements/gradesSummarizeChart/GradesSummarizeChart.tsx
index 2ea321c..1643194 100644
--- a/src/components/viewsComponents/grades/elements/gradesSummarizeChart/GradesSummarizeChart.tsx
+++ b/src/components/viewsComponents/grades/elements/gradesSummarizeChart/GradesSummarizeChart.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { Box, Typography } from '@mui/material';
import _ from 'lodash';
import { Bar, BarChart, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
+import GradesChartCustomTooltip from '../gradesChartCustomTooltip/GradesChartCustomTooltip';
import type { IGrade } from 'contract/interfaces/academics/Academics';
interface GradesSummarizeChartProps {
@@ -51,39 +52,11 @@ const GradesSummarizeChart: React.FC = ({ grades }) =
angle: -90,
}}
/>
- } cursor={{ fill: 'transparent' }} />
+ } cursor={{ fill: 'transparent' }} />
);
};
-interface ICustomTooltipProps {
- active?: boolean;
- payload?: { payload: { grade: number; count: number } }[];
-}
-
-const CustomTooltip: React.FC = ({ active, payload }) => {
- if (active && payload?.[0]) {
- const { grade, count } = payload[0].payload;
-
- return (
-
-
- Grade: {grade}
-
- Amount: {count}
-
- );
- }
- return null;
-};
-
export default GradesSummarizeChart;
diff --git a/src/components/viewsComponents/grades/utils/Helpers.tsx b/src/components/viewsComponents/grades/utils/Helpers.tsx
new file mode 100644
index 0000000..1b8efa8
--- /dev/null
+++ b/src/components/viewsComponents/grades/utils/Helpers.tsx
@@ -0,0 +1,21 @@
+import { IGrade } from 'contract/interfaces/academics/Academics';
+import _ from 'lodash';
+
+export const calculateAverageGrade = (gradesList: IGrade[]): string => {
+ if (gradesList.length === 0) {
+ return '0.00';
+ }
+
+ const validGrades = _.map(gradesList, 'grade').filter(Number);
+ const average = _.mean(validGrades);
+
+ return average.toFixed(2);
+};
+
+export const calculatePercentage = (count: number, gradesCount: number): string => {
+ if (gradesCount === 0) {
+ return '0%';
+ }
+
+ return `${Math.round((count / gradesCount) * 100)}%`;
+};
diff --git a/src/routes/preAuth/login/Login.tsx b/src/components/viewsComponents/login/Login.tsx
similarity index 70%
rename from src/routes/preAuth/login/Login.tsx
rename to src/components/viewsComponents/login/Login.tsx
index 75f6900..c1ff5db 100644
--- a/src/routes/preAuth/login/Login.tsx
+++ b/src/components/viewsComponents/login/Login.tsx
@@ -3,12 +3,11 @@ import { useTranslation } from 'react-i18next';
import { Box, Typography, Button, Paper } from '@mui/material';
import { yupResolver } from '@hookform/resolvers/yup';
import RHFTextField from 'components/shared/formComponents/textField/RHFTextField';
-import LoginAdditionalActions from 'components/viewsComponents/login/LoginAdditionalActions';
-import PasswordField from 'components/viewsComponents/login/PasswordField';
+import LoginAdditionalActions from 'components/viewsComponents/login/elements/LoginAdditionalActions';
+import PasswordField from 'components/viewsComponents/login/elements/PasswordField';
import { useLoginMutation } from 'redux/apiSlices/auth/Auth.Api.Slice';
import ExampleUserIcon from 'assets/icons/exampleUserIcon.png';
-import { loginValidationSchema } from './Login.Yup';
-import type { ILoginFields } from './types/Login.Types';
+import { loginValidationSchema } from './schema/Login.Yup';
import './styles/AuthPanel.scss';
const Login: React.FC = () => {
@@ -23,29 +22,25 @@ const Login: React.FC = () => {
rememberMe: false,
},
});
- const { handleSubmit } = methods;
-
const onSubmit: SubmitHandler = async data => {
- const sessionUUID = sessionStorage.getItem('sessionUUID')!;
const { login, password, rememberMe } = data;
await loginUser({
identifier: login,
password,
rememberMe,
- sessionID: sessionUUID,
});
};
return (
-
-
-
+
+
+
{t('Login Form')}
-
-
+
+
);
}
diff --git a/src/layouts/postAuth/constants/MenuItems.tsx b/src/layouts/postAuth/constants/MenuItems.tsx
new file mode 100644
index 0000000..d57db97
--- /dev/null
+++ b/src/layouts/postAuth/constants/MenuItems.tsx
@@ -0,0 +1,86 @@
+import { useTranslation } from 'react-i18next';
+import BookIcon from '@mui/icons-material/Book';
+import DashboardIcon from '@mui/icons-material/Dashboard';
+import DescriptionIcon from '@mui/icons-material/Description';
+import EventIcon from '@mui/icons-material/Event';
+import GradingIcon from '@mui/icons-material/Grading';
+import LogoutIcon from '@mui/icons-material/Logout';
+import PersonIcon from '@mui/icons-material/Person';
+import SchoolIcon from '@mui/icons-material/School';
+import SearchIcon from '@mui/icons-material/Search';
+import { RolesEnum } from 'contract/enums/Enums';
+import { v4 as uuidv4 } from 'uuid';
+
+export const useMenuItems = () => {
+ const { t } = useTranslation();
+
+ return [
+ {
+ id: uuidv4(),
+ text: t('dashboard'),
+ icon: ,
+ availableForRoles: [RolesEnum.STUDENT],
+ linkTo: 'dashboard',
+ },
+ {
+ id: uuidv4(),
+ text: t('profile'),
+ icon: ,
+ availableForRoles: [RolesEnum.STUDENT],
+ children: [
+ {
+ id: uuidv4(),
+ text: t('personal_data'),
+ icon: ,
+ linkTo: 'profile/personal-data',
+ },
+ ],
+ },
+ {
+ id: uuidv4(),
+ text: t('academics'),
+ icon: ,
+ availableForRoles: [RolesEnum.STUDENT],
+ children: [
+ {
+ id: uuidv4(),
+ text: t('courses'),
+ icon: ,
+ linkTo: 'academics/courses',
+ },
+ {
+ id: uuidv4(),
+ text: t('grades'),
+ icon: ,
+ linkTo: 'academics/grades',
+ },
+ ],
+ },
+ {
+ id: uuidv4(),
+ text: t('community'),
+ icon: ,
+ children: [
+ {
+ id: uuidv4(),
+ text: t('teachers'),
+ icon: ,
+ linkTo: 'community/teachers',
+ availableForRoles: [RolesEnum.STUDENT],
+ },
+ {
+ id: uuidv4(),
+ text: t('events'),
+ icon: ,
+ linkTo: 'community/events',
+ },
+ ],
+ },
+ {
+ id: uuidv4(),
+ text: t('logout'),
+ icon: ,
+ linkTo: 'logout',
+ },
+ ];
+};
diff --git a/src/layouts/postAuth/PostAuthLayout.scss b/src/layouts/postAuth/styles/PostAuthLayout.scss
similarity index 81%
rename from src/layouts/postAuth/PostAuthLayout.scss
rename to src/layouts/postAuth/styles/PostAuthLayout.scss
index 09cfc2e..aa5f882 100644
--- a/src/layouts/postAuth/PostAuthLayout.scss
+++ b/src/layouts/postAuth/styles/PostAuthLayout.scss
@@ -1,5 +1,5 @@
.ContentContainer {
- height: calc(100% - 120px);;
+ height: calc(100% - 120px);
position: relative;
margin: 24px;
diff --git a/src/layouts/preAuth/PreAuthLayout.tsx b/src/layouts/preAuth/PreAuthLayout.tsx
index eba7250..03fc038 100644
--- a/src/layouts/preAuth/PreAuthLayout.tsx
+++ b/src/layouts/preAuth/PreAuthLayout.tsx
@@ -1,21 +1,19 @@
-import { useSelector } from 'react-redux';
import { Navigate, Outlet } from 'react-router-dom';
-import { Container, Content } from 'layouts/Styled';
+import { Box } from '@mui/material';
+import { useTypedSelector } from 'hooks/useStore.Hooks';
import { selectCurrentToken } from 'redux/stateSlices/auth/Auth.State.Slice';
function PreAuthLayout() {
- const isAuthenticated = useSelector(selectCurrentToken);
+ const isAuthenticated = useTypedSelector(selectCurrentToken);
if (isAuthenticated) {
return ;
}
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/main.tsx b/src/main.tsx
index baaebe0..386da5f 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -5,12 +5,11 @@ import { RouterProvider } from 'react-router-dom';
import CssBaseline from '@mui/material/CssBaseline';
import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles';
import SnackbarConfig from 'configs/SnackbarConfig';
-import { DialogProvider } from 'contexts/dialogs/Dialogs.Context';
+import { DialogProvider } from 'contexts/dialogs/Dialogs.Provider';
import ReactDOM from 'react-dom/client';
import { store } from 'redux/config/Store';
import { router } from 'routes/Router';
-import theme from './theme/theme';
-import './assets/styles/themeStyle.scss';
+import theme from 'theme/theme';
import './assets/styles/app.scss';
import './i18n/index';
diff --git a/src/middlewares/persistLogin/PersistLogin.Middleware.tsx b/src/middlewares/persistLogin/PersistLogin.Middleware.tsx
index 78a7053..fc075a8 100644
--- a/src/middlewares/persistLogin/PersistLogin.Middleware.tsx
+++ b/src/middlewares/persistLogin/PersistLogin.Middleware.tsx
@@ -1,40 +1,14 @@
-import { useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { Outlet, useNavigate } from 'react-router-dom';
+import { Outlet } from 'react-router-dom';
import FullScreenLoader from 'components/shared/fullScreenLoader/FullScreenLoader';
-import { useEffectOnce } from 'hooks/useExtendedUseEffect';
-import { useRefreshMutation } from 'redux/apiSlices/auth/Auth.Api.Slice';
-import { selectCurrentToken, logOut, setCredentials } from 'redux/stateSlices/auth/Auth.State.Slice';
+import { useTypedSelector } from 'hooks/useStore.Hooks';
+import { useVerifySession } from 'hooks/useVerifyingSession';
+import { selectCurrentToken } from 'redux/stateSlices/auth/Auth.State.Slice';
function PersistLoginMiddleware() {
- const navigate = useNavigate();
- const dispatch = useDispatch();
- const [refresh, { isLoading }] = useRefreshMutation();
- const token = useSelector(selectCurrentToken) ?? localStorage.getItem('accessToken');
- const [checkingSession, setCheckingSession] = useState(true);
+ const token = useTypedSelector(selectCurrentToken) ?? localStorage.getItem('accessToken');
+ const { isLoading } = useVerifySession(token);
- useEffectOnce(() => {
- const verifyToken = async () => {
- try {
- const result = await refresh().unwrap();
- dispatch(setCredentials({ accessToken: result.accessToken }));
- } catch (err) {
- dispatch(logOut());
- navigate('/login');
- } finally {
- setCheckingSession(false);
- }
- };
-
- if (!token) {
- setCheckingSession(false);
- return;
- }
-
- verifyToken();
- });
-
- if (isLoading || checkingSession) {
+ if (isLoading) {
return ;
}
diff --git a/src/middlewares/protectedRoutes/ProtectedRoutes.Middleware.tsx b/src/middlewares/protectedRoutes/ProtectedRoutes.Middleware.tsx
index 7cbb011..d6e3113 100644
--- a/src/middlewares/protectedRoutes/ProtectedRoutes.Middleware.tsx
+++ b/src/middlewares/protectedRoutes/ProtectedRoutes.Middleware.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import { useSelector } from 'react-redux';
import { Navigate, Outlet } from 'react-router-dom';
+import { useTypedSelector } from 'hooks/useStore.Hooks';
import { useTypedMatches } from 'hooks/useTypedMatches.Hook';
import { selectCurrentToken, selectUserRoles } from 'redux/stateSlices/auth/Auth.State.Slice';
@@ -8,8 +8,8 @@ const ProtectedRoutesMiddleware: React.FC = () => {
const matches = useTypedMatches();
const currentMatch = matches.find(match => match.handle);
- const userRoles = useSelector(selectUserRoles);
- const isAuthenticated = useSelector(selectCurrentToken);
+ const userRoles = useTypedSelector(selectUserRoles);
+ const isAuthenticated = useTypedSelector(selectCurrentToken);
const notAllowedRoles = currentMatch?.handle?.permissions?.availableForRoles;
if (!isAuthenticated) {
diff --git a/src/middlewares/session/Session.Middleware.tsx b/src/middlewares/session/Session.Middleware.tsx
deleted file mode 100644
index b6668cf..0000000
--- a/src/middlewares/session/Session.Middleware.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Outlet } from 'react-router-dom';
-import { useEffectOnce } from 'hooks/useExtendedUseEffect';
-import { v4 as uuidv4 } from 'uuid';
-
-function SessionMiddleware() {
- useEffectOnce(() => {
- let sessionUUID = sessionStorage.getItem('sessionUUID');
-
- if (!sessionUUID) {
- sessionUUID = uuidv4();
- sessionStorage.setItem('sessionUUID', sessionUUID);
- }
- });
-
- return ;
-}
-
-export default SessionMiddleware;
diff --git a/src/redux/apiSlices/academics/Grades.Api.Slice.ts b/src/redux/apiSlices/academics/Grades.Api.Slice.ts
index c41a0c9..2a2186e 100644
--- a/src/redux/apiSlices/academics/Grades.Api.Slice.ts
+++ b/src/redux/apiSlices/academics/Grades.Api.Slice.ts
@@ -8,7 +8,7 @@ export const gradesSlice = Api.injectEndpoints({
query: ({ studentId }) => ({
url: `/grades/${studentId}`,
}),
- transformResponse: (response?: IGrade[]) => response ?? [],
+ transformResponse: (response?: IGrade[]) => (Array.isArray(response) ? response : []),
}),
}),
});
diff --git a/src/redux/apiSlices/community/Community.Api.Slice.ts b/src/redux/apiSlices/community/Community.Api.Slice.ts
index 9fb93ca..3ddf488 100644
--- a/src/redux/apiSlices/community/Community.Api.Slice.ts
+++ b/src/redux/apiSlices/community/Community.Api.Slice.ts
@@ -1,5 +1,5 @@
import Api from 'redux/config/Api';
-import { formatTime } from 'routes/utils/Date.Utils';
+import { formatTime } from 'utils/general/Date.Utils';
import { extendedOnQueryStartedWithNotifications } from 'utils/slices/ExtendedOnQueryStarted';
import type {
IGetAllTeachersResponse,
diff --git a/src/redux/stateSlices/auth/Auth.State.Slice.ts b/src/redux/stateSlices/auth/Auth.State.Slice.ts
index cc5536d..3fd8aef 100644
--- a/src/redux/stateSlices/auth/Auth.State.Slice.ts
+++ b/src/redux/stateSlices/auth/Auth.State.Slice.ts
@@ -1,7 +1,6 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
import { parseJwt } from 'utils/slices/JWT.Utils';
import type { RolesEnum } from 'contract/enums/Enums';
-import type { RootStateType } from 'redux/config/Store';
interface IAuthState {
token: string | null;
@@ -49,13 +48,14 @@ const authSlice = createSlice({
state.userRoles = [];
},
},
+ selectors: {
+ selectCurrentToken: state => state.token,
+ selectTokenExpirationTime: state => state.expDate,
+ selectUserRoles: state => state.userRoles,
+ selectAccountId: state => state.accountId,
+ },
});
-
-export const selectCurrentToken = (state: RootStateType) => state.authSlice.token;
-export const selectTokenExpirationTime = (state: RootStateType) => state.authSlice.expDate;
-export const selectUserRoles = (state: RootStateType) => state.authSlice.userRoles;
-export const selectAccountId = (state: RootStateType) => state.authSlice.accountId;
-
+export const { selectCurrentToken, selectTokenExpirationTime, selectUserRoles, selectAccountId } = authSlice.selectors;
export const { setCredentials, logOut } = authSlice.actions;
export default authSlice.reducer;
diff --git a/src/routes/Router.tsx b/src/routes/Router.tsx
index 033557b..f7b46a1 100644
--- a/src/routes/Router.tsx
+++ b/src/routes/Router.tsx
@@ -1,9 +1,9 @@
-import { createBrowserRouter } from 'react-router-dom';
-import App from 'App';
+import { createBrowserRouter, Outlet } from 'react-router-dom';
import PostAuthLayout from 'layouts/postAuth/PostAuthLayout';
import PreAuthLayout from 'layouts/preAuth/PreAuthLayout';
import PersistLoginMiddleware from 'middlewares/persistLogin/PersistLogin.Middleware';
import ProtectedRoutesMiddleware from 'middlewares/protectedRoutes/ProtectedRoutes.Middleware';
+import ErrorPage from '../components/shared/errorPage/ErrorPage';
import { academicsConfig } from './routesConfigs/AcademicsConfig';
import { communityConfig } from './routesConfigs/CommunityConfig';
import { dashboardConfig } from './routesConfigs/DashboardConfig';
@@ -12,12 +12,11 @@ import { indexPreAuthConfig } from './routesConfigs/IndexPreAuthConfig';
import { loginConfig } from './routesConfigs/LoginConfig';
import { logoutConfig } from './routesConfigs/LogoutConfig';
import { profileConfig } from './routesConfigs/ProfileConfig';
-import ErrorPage from './shared/error/ErrorPage';
export const router = createBrowserRouter([
{
path: '/',
- element: ,
+ element: ,
errorElement: ,
children: [
{
diff --git a/src/routes/postAuth/personalData/teacher/TeacherPersonalData.tsx b/src/routes/postAuth/personalData/teacher/TeacherPersonalData.tsx
deleted file mode 100644
index d098276..0000000
--- a/src/routes/postAuth/personalData/teacher/TeacherPersonalData.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-// TODO: WHEN TEACHER ROLE WILL BE USED UNNCOMENT CODE
-/*
- * import { useMemo } from 'react';
- * import { useTranslation } from 'react-i18next';
- * import { Box, Paper } from '@mui/material';
- * import CenteredLoader from 'components/shared/centeredLoader/CenteredLoader';
- * import BasicInfo from 'components/viewsComponents/personalData/BasicInfo';
- * import { PersonalDetails } from 'components/viewsComponents/personalData/PersonalDetails';
- * import { useGetAuthorizedStudentAllDataQuery } from 'redux/apiSlices/students/Students.Api.Slice';
- * import type { IDetailRowProps } from 'components/viewsComponents/personalData/DetailRow';
- * import '../styles/PersonalData.scss';
- */
-
-/*
- * export interface ISection {
- * title: string;
- * details: IDetailRowProps[];
- * }
- */
-
-function EmployeePersonalData() {
- return ;
- /*
- * const { t } = useTranslation();
- * const { data, isLoading } = useGetAuthorizedStudentAllDataQuery();
- */
-
- /*
- * const sections: ISection[] = useMemo(
- * () => [
- * {
- * title: t('personalDetails'),
- * details: [
- * { icon: 'AccountCircle', label: t('name'), value: data?.name },
- * { icon: 'AccountCircle', label: t('surname'), value: data?.surname },
- * {
- * icon: 'Cake',
- * label: t('dateOfBirth'),
- * value: data?.dateOfBirth ? new Date(data.dateOfBirth).toLocaleDateString() : undefined,
- * },
- * { icon: 'ContactMail', label: t('pesel'), value: data?.pesel },
- * { icon: 'Public', label: t('gender'), value: data?.gender },
- * { icon: 'Language', label: t('nationality'), value: data?.nationality },
- * ],
- * },
- * {
- * title: t('addressDetails'),
- * details: [
- * { icon: 'Public', label: t('country'), value: data?.address.country },
- * { icon: 'LocationCity', label: t('city'), value: data?.address.city },
- * { icon: 'MailOutline', label: t('postalCode'), value: data?.address.postalCode },
- * { icon: 'Home', label: t('street'), value: data?.address.street },
- * { icon: 'MapsHomeWork', label: t('buildingNumber'), value: data?.address.buildingNumber },
- * { icon: 'Home', label: t('apartmentNumber'), value: data?.address.apartmentNumber },
- * ],
- * },
- * {
- * title: t('additionalDetails'),
- * details: [
- * { icon: 'Email', label: t('contactEmail'), value: data?.contactEmail },
- * { icon: 'Phone', label: t('contactPhone'), value: data?.contactPhone },
- * {
- * icon: 'DateRange',
- * label: t('dateOfAdmission'),
- * value: data?.dateOfAdmission ? new Date(data.dateOfAdmission).toLocaleDateString() : undefined,
- * },
- * {
- * icon: 'HistoryEdu',
- * label: t('permissionForDataProcessing'),
- * value: data?.consent.permissionForDataProcessing ? 'Yes' : 'No',
- * },
- * {
- * icon: 'HistoryEdu',
- * label: t('permissionForPhoto'),
- * value: data?.consent.permissionForPhoto ? 'Yes' : 'No',
- * },
- * ],
- * },
- * ],
- * [t, data]
- * );
- */
-
- // if (isLoading) return ;
-
- /*
- * return (
- * <>
- *
- *
- * There will be something
- *
- *
- * >
- * );
- */
-}
-
-export default EmployeePersonalData;
diff --git a/src/routes/preAuth/login/types/Login.Types.ts b/src/routes/preAuth/login/types/Login.Types.ts
deleted file mode 100644
index 34ca972..0000000
--- a/src/routes/preAuth/login/types/Login.Types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ILoginFields {
- login: string;
- password: string;
- rememberMe: boolean;
-}
diff --git a/src/routes/routesConfigs/AcademicsConfig.tsx b/src/routes/routesConfigs/AcademicsConfig.tsx
index 163df12..39eaf38 100644
--- a/src/routes/routesConfigs/AcademicsConfig.tsx
+++ b/src/routes/routesConfigs/AcademicsConfig.tsx
@@ -1,6 +1,6 @@
+import Courses from 'components/viewsComponents/courses/Courses';
import Grades from 'components/viewsComponents/grades/Grades';
import { RolesEnum } from 'contract/enums/Enums';
-import Courses from 'components/viewsComponents/courses/Courses';
export const academicsConfig = {
path: 'Academics',
diff --git a/src/routes/routesConfigs/IndexPreAuthConfig.tsx b/src/routes/routesConfigs/IndexPreAuthConfig.tsx
index 546f07e..9848fb9 100644
--- a/src/routes/routesConfigs/IndexPreAuthConfig.tsx
+++ b/src/routes/routesConfigs/IndexPreAuthConfig.tsx
@@ -1,4 +1,4 @@
-import Login from 'routes/preAuth/login/Login';
+import Login from 'components/viewsComponents/login/Login';
export const indexPreAuthConfig = {
index: true,
diff --git a/src/routes/routesConfigs/LoginConfig.tsx b/src/routes/routesConfigs/LoginConfig.tsx
index cc62f2d..41a29dd 100644
--- a/src/routes/routesConfigs/LoginConfig.tsx
+++ b/src/routes/routesConfigs/LoginConfig.tsx
@@ -1,4 +1,4 @@
-import Login from 'routes/preAuth/login/Login';
+import Login from 'components/viewsComponents/login/Login';
export const loginConfig = {
path: 'login',
diff --git a/src/routes/routesConfigs/ProfileConfig.tsx b/src/routes/routesConfigs/ProfileConfig.tsx
index 376bdd7..30001a5 100644
--- a/src/routes/routesConfigs/ProfileConfig.tsx
+++ b/src/routes/routesConfigs/ProfileConfig.tsx
@@ -1,13 +1,5 @@
-import { useSelector } from 'react-redux';
import { RolesEnum } from 'contract/enums/Enums';
-import { selectUserRoles } from 'redux/stateSlices/auth/Auth.State.Slice';
-import { getRoleBasedComponent } from 'routes/utils/RouterUtils';
-
-const RoleBasedPersonalData: React.FC = () => {
- const roles = useSelector(selectUserRoles);
-
- return getRoleBasedComponent(roles);
-};
+import StudentPersonalData from 'routes/postAuth/personalData/student/StudentPersonalData';
export const profileConfig = {
path: 'profile',
@@ -22,7 +14,7 @@ export const profileConfig = {
children: [
{
path: 'personal-data',
- element: ,
+ element: ,
handle: {
navigation: {
text: 'Personal Data',
diff --git a/src/routes/utils/RouterUtils.tsx b/src/routes/utils/RouterUtils.tsx
deleted file mode 100644
index 566199b..0000000
--- a/src/routes/utils/RouterUtils.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { RolesEnum } from 'contract/enums/Enums';
-import StudentPersonalData from 'routes/postAuth/personalData/student/StudentPersonalData';
-import TeacherPersonalData from 'routes/postAuth/personalData/teacher/TeacherPersonalData';
-
-export const getRoleBasedComponent = (roles: string[]) => {
- if (roles.includes(RolesEnum.STUDENT)) {
- return ;
- }
-
- if (roles.includes(RolesEnum.TEACHER)) {
- return ;
- }
-
- return null;
-};
diff --git a/src/routes/utils/Date.Utils.ts b/src/utils/general/Date.Utils.ts
similarity index 100%
rename from src/routes/utils/Date.Utils.ts
rename to src/utils/general/Date.Utils.ts
diff --git a/src/routes/utils/Decorators.ts b/src/utils/general/Decorators.ts
similarity index 100%
rename from src/routes/utils/Decorators.ts
rename to src/utils/general/Decorators.ts
diff --git a/tsconfig.json b/tsconfig.json
index db272a6..a3c3812 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,13 +29,23 @@
"noPropertyAccessFromIndexSignature": true,
"baseUrl": "./src",
"paths": {
+ "assets/*": ["assets/*"],
"components/*": ["components/*"],
- "features/*": ["features/*"],
- "assets/*": ["assets/*"]
+ "configs/*": ["configs/*"],
+ "contexts/*": ["contexts/*"],
+ "contract/*": ["contract/*"],
+ "hooks/*": ["hooks/*"],
+ "i18n/*": ["i18n/*"],
+ "layouts/*": ["layouts/*"],
+ "middlewares/*": ["middlewares/*"],
+ "routes/*": ["routes/*"],
+ "theme/*": ["theme/*"],
+ "types/*": ["types/*"],
+ "utils/*": ["utils/*"]
}
},
- "include": ["src/**/*", "./custom.d.ts"],
- "exclude": ["node_modules", "dist"],
+ "include": ["src/**/*", "./custom.d.ts",],
+ "exclude": ["node_modules", "dist", "eslint.config.js"],
"references": [
{
"path": "./tsconfig.node.json"
diff --git a/vite.config.ts b/vite.config.ts
index fb3a2eb..4ab358e 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -7,9 +7,20 @@ export default defineConfig({
plugins: [react(), svgrPlugin({}), tsconfigPaths()],
resolve: {
alias: {
- components: '/src/components',
- features: '/src/features',
assets: '/src/assets',
+ components: '/src/components',
+ configs: '/src/configs',
+ contexts: '/src/contexts',
+ contract: '/src/contract',
+ hooks: '/src/hooks',
+ i18n: "/src/i18n",
+ layouts: '/src/layouts',
+ middlewares: "/src/middlewares",
+ routes: '/src/routes',
+ theme: '/src/theme',
+ types: '/src/types',
+ utils: "/src/utils"
+ // Redux ?!?!
},
},
});