diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0f5ba90b0..853909327 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -2,7 +2,7 @@ name: Test, Lint, Build and Deploy on Github Pages
on:
push:
- branches: ["master", "main"]
+ branches: ['master', 'main']
# Позволяет запустить этот рабочий процесс вручную на вкладке Actions
workflow_dispatch:
@@ -45,17 +45,17 @@ jobs:
branch: gh-pages
folder: dist
- # # Собираем Storybook
- # - name: Build Storybook
- # run: npm run build-storybook
- #
- # # Публикуем Storybook на Github Pages
- # - name: Deploy Storybook to Github Pages
- # uses: JamesIves/github-pages-deploy-action@4.2.1
- # with:
- # branch: gh-pages
- # folder: storybook-static
- # commit-message: "Automatically publish Storybook"
+ # Собираем Storybook
+ # - name: Build Storybook
+ # run: npm run build-storybook
+
+ # # Публикуем Storybook на Github Pages
+ # - name: Deploy Storybook to Github Pages
+ # uses: JamesIves/github-pages-deploy-action@4.2.1
+ # with:
+ # branch: gh-pages
+ # folder: storybook-static
+ # commit-message: 'Automatically publish Storybook'
# Останавливаем выполнение строго при неудачных тестах
- name: Fail on failed tests
diff --git a/.storybook/main.ts b/.storybook/main.ts
index 3d1c9b2d5..953c50705 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -1,18 +1,20 @@
const config = {
- stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
+ // staticDirs: ['../src/assets'],
+ staticDirs: [{ from: '../src/assets', to: '../../assets' }],
addons: [
- "@storybook/addon-links",
- "@storybook/addon-essentials",
- "@storybook/addon-interactions",
- "@storybook/preset-scss",
- "@storybook/addon-mdx-gfm"
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@storybook/addon-interactions',
+ '@storybook/preset-scss',
+ '@storybook/addon-mdx-gfm',
],
framework: {
- name: "@storybook/react-webpack5",
+ name: '@storybook/react-webpack5',
options: {},
},
docs: {
- autodocs: "tag",
+ autodocs: 'tag',
},
};
export default config;
diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html
new file mode 100644
index 000000000..8b3c0a972
--- /dev/null
+++ b/.storybook/preview-body.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/.storybook/preview.ts b/.storybook/preview.ts
deleted file mode 100644
index 1c372b694..000000000
--- a/.storybook/preview.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Preview } from "@storybook/react";
-
-const preview: Preview = {
- parameters: {
- actions: { argTypesRegex: "^on[A-Z].*" },
- controls: {
- matchers: {
- color: /(background|color)$/i,
- date: /Date$/,
- },
- },
- },
-};
-
-export default preview;
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 000000000..cfc60e8fc
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,57 @@
+import type { Preview } from '@storybook/react';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import i18n from '../src/localization/settings';
+import React, { Suspense } from 'react';
+import { I18nextProvider } from 'react-i18next';
+
+const preview: Preview = {
+ parameters: {
+ actions: { argTypesRegex: '^on[A-Z].*' },
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/,
+ },
+ },
+ },
+};
+
+export default preview;
+
+
+// Wrap your stories in the I18nextProvider component
+const withI18next = (Story) => {
+ return (
+ // This catches the suspense from components not yet ready (still loading translations)
+ // Alternative: set useSuspense to false on i18next.options.react when initializing i18next
+ loading translations...}>
+
+
+
+
+ );
+};
+
+// export decorators for storybook to wrap your stories in
+export const decorators = [withI18next];
+
+
+/* Snipped for brevity */
+
+// Create a global variable called locale in storybook
+// and add a menu in the toolbar to change your locale
+export const globalTypes = {
+ locale: {
+ name: 'Locale',
+ description: 'Internationalization locale',
+ toolbar: {
+ icon: 'globe',
+ items: [
+ { value: 'en', title: 'English' },
+ { value: 'de', title: 'Deutsch' },
+ ],
+ showName: true,
+ },
+ },
+};
+
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000..ff984fe69
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "chrome",
+ "request": "launch",
+ "name": "Launch Chrome against localhost",
+ "url": "http://localhost:8080",
+ "webRoot": "${workspaceFolder}",
+ // "runtimeExecutable": "/Applications/Сhrome.app",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..e8df7cb4c
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "workbench.externalBrowser": "chrome"
+}
\ No newline at end of file
diff --git a/declarations.d.ts b/declarations.d.ts
index 8ce36c1e3..414826125 100644
--- a/declarations.d.ts
+++ b/declarations.d.ts
@@ -1,3 +1,4 @@
+///
declare module '*.sass';
declare module '*.scss';
declare module '*.css';
@@ -5,3 +6,4 @@ declare module '*.jpg';
declare module '*.jpeg';
declare module '*.png';
declare module '*.svg';
+declare module '*d.ts';
diff --git a/package-lock.json b/package-lock.json
index 5b1dfa392..e3819ae59 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,15 +9,30 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^6.6.0",
+ "@fortawesome/free-brands-svg-icons": "^6.6.0",
+ "@fortawesome/free-regular-svg-icons": "^6.6.0",
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
+ "@fortawesome/react-fontawesome": "^0.2.2",
"clsx": "^1.2.1",
+ "i18next": "^23.15.2",
+ "i18next-browser-languagedetector": "^8.0.0",
+ "i18next-http-backend": "^2.6.2",
+ "intersection-observer": "^0.12.2",
+ "module-alias": "^2.2.3",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.53.2",
+ "react-i18next": "^15.0.2",
+ "react-intersection-observer": "^9.13.1"
},
"devDependencies": {
"@babel/core": "^7.22.1",
"@babel/preset-env": "^7.22.4",
"@babel/preset-react": "^7.22.3",
"@babel/preset-typescript": "^7.21.5",
+ "@faker-js/faker": "^9.0.2",
+ "@reduxjs/toolkit": "^2.4.0",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-interactions": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
@@ -31,10 +46,13 @@
"@types/node": "^20.2.5",
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
+ "@types/redux-persist": "^4.3.1",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"babel-loader": "^9.1.2",
+ "bootstrap": "^5.3.3",
"clean-webpack-plugin": "^4.0.0",
+ "copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.8.1",
"eslint": "8.22.0",
"eslint-config-airbnb": "^19.0.4",
@@ -46,6 +64,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.8.0",
"fork-ts-checker-webpack-plugin": "^8.0.0",
+ "gh-pages": "^6.1.1",
"html-webpack-plugin": "^5.5.1",
"husky": "^8.0.0",
"jest": "^29.5.0",
@@ -53,6 +72,10 @@
"less-loader": "^11.1.2",
"mini-css-extract-plugin": "^2.7.6",
"prettier": "2.8.8",
+ "react-redux": "^9.1.2",
+ "react-router": "^7.0.1",
+ "react-router-dom": "^7.0.1",
+ "redux-persist": "^6.0.0",
"sass": "^1.71.1",
"sass-loader": "^13.3.1",
"storybook": "^7.6.17",
@@ -60,7 +83,7 @@
"ts-jest": "^29.1.0",
"typescript": "^5.1.3",
"webpack": "^5.85.0",
- "webpack-cli": "^5.1.3",
+ "webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.0"
}
},
@@ -2032,12 +2055,12 @@
"dev": true
},
"node_modules/@babel/runtime": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz",
- "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==",
- "dev": true,
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
+ "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==",
+ "license": "MIT",
"dependencies": {
- "regenerator-runtime": "^0.13.11"
+ "regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
@@ -2576,6 +2599,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@faker-js/faker": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.2.tgz",
+ "integrity": "sha512-nI/FP30ZGXb+UaR7yXawVTH40NVKXPIx0tA3GKjkKLjorqBoMAeq4iSEacl8mJmpVhOCDa0vYHwYDmOOcFMrYw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fakerjs"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=9.0.0"
+ }
+ },
"node_modules/@fal-works/esbuild-plugin-global-externals": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz",
@@ -2620,6 +2660,76 @@
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==",
"dev": true
},
+ "node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
+ "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-svg-core": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz",
+ "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==",
+ "license": "MIT",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-brands-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-regular-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-solid-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/react-fontawesome": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
+ "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "@fortawesome/fontawesome-svg-core": "~1 || ~6",
+ "react": ">=16.3"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.10.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
@@ -3654,6 +3764,18 @@
}
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -4317,12 +4439,50 @@
"@babel/runtime": "^7.13.10"
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.4.0.tgz",
+ "integrity": "sha512-wJZEuSKj14tvNfxiIiJws0tQN77/rDqucBq528ApebMIRHyWpCanJVQRxQ8WWZC19iCDKxDsGlbAir3F1layxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
"integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==",
"dev": true
},
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+ "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@sinonjs/commons": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
@@ -7520,6 +7680,13 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/cross-spawn": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz",
@@ -7851,13 +8018,13 @@
"dev": true
},
"node_modules/@types/react": {
- "version": "18.2.9",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
- "integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
+ "version": "18.3.12",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
+ "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/prop-types": "*",
- "@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
@@ -7870,6 +8037,17 @@
"@types/react": "*"
}
},
+ "node_modules/@types/redux-persist": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/redux-persist/-/redux-persist-4.3.1.tgz",
+ "integrity": "sha512-YkMnMUk+4//wPtiSTMfsxST/F9Gh9sPWX0LVxHuOidGjojHtMdpep2cYvQgfiDMnj34orXyZI+QJCQMZDlafKA==",
+ "deprecated": "This is a stub types definition for redux-persist (https://github.com/rt2zz/redux-persist). redux-persist provides its own type definitions, so you don't need @types/redux-persist installed!",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "redux-persist": "*"
+ }
+ },
"node_modules/@types/resolve": {
"version": "1.20.6",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
@@ -7882,12 +8060,6 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"dev": true
},
- "node_modules/@types/scheduler": {
- "version": "0.16.3",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
- "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
- "dev": true
- },
"node_modules/@types/semver": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
@@ -7950,6 +8122,13 @@
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==",
"dev": true
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
@@ -9448,6 +9627,26 @@
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
+ "node_modules/bootstrap": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/twbs"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ }
+ ],
+ "license": "MIT",
+ "peerDependencies": {
+ "@popperjs/core": "^2.11.8"
+ }
+ },
"node_modules/bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
@@ -10214,6 +10413,135 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
+ "node_modules/copy-webpack-plugin": {
+ "version": "12.0.2",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz",
+ "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.1",
+ "globby": "^14.0.0",
+ "normalize-path": "^3.0.0",
+ "schema-utils": "^4.2.0",
+ "serialize-javascript": "^6.0.2"
+ },
+ "engines": {
+ "node": ">= 18.12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ }
+ },
+ "node_modules/copy-webpack-plugin/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/copy-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/copy-webpack-plugin/node_modules/globby": {
+ "version": "14.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz",
+ "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^2.1.0",
+ "fast-glob": "^3.3.2",
+ "ignore": "^5.2.4",
+ "path-type": "^5.0.0",
+ "slash": "^5.1.0",
+ "unicorn-magic": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/copy-webpack-plugin/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/copy-webpack-plugin/node_modules/path-type": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz",
+ "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/copy-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 12.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/copy-webpack-plugin/node_modules/slash": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+ "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/core-js-compat": {
"version": "3.33.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.1.tgz",
@@ -10260,6 +10588,15 @@
"node": ">=10"
}
},
+ "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==",
+ "license": "MIT",
+ "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",
@@ -11021,6 +11358,13 @@
"integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==",
"dev": true
},
+ "node_modules/email-addresses": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
+ "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/emittery": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
@@ -12360,10 +12704,11 @@
"dev": true
},
"node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -12405,6 +12750,13 @@
"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/fastest-levenshtein": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
@@ -12511,6 +12863,34 @@
"node": ">=10"
}
},
+ "node_modules/filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/filenamify": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+ "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.1",
+ "trim-repeated": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -13147,6 +13527,101 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gh-pages": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.1.1.tgz",
+ "integrity": "sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.2.4",
+ "commander": "^11.0.0",
+ "email-addresses": "^5.0.0",
+ "filenamify": "^4.3.0",
+ "find-cache-dir": "^3.3.1",
+ "fs-extra": "^11.1.1",
+ "globby": "^6.1.0"
+ },
+ "bin": {
+ "gh-pages": "bin/gh-pages.js",
+ "gh-pages-clean": "bin/gh-pages-clean.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/gh-pages/node_modules/array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages/node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/gh-pages/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/gh-pages/node_modules/globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/giget": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/giget/-/giget-1.2.1.tgz",
@@ -13546,6 +14021,15 @@
"node": ">=12"
}
},
+ "node_modules/html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "license": "MIT",
+ "dependencies": {
+ "void-elements": "3.1.0"
+ }
+ },
"node_modules/html-tags": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
@@ -13726,6 +14210,47 @@
"url": "https://github.com/sponsors/typicode"
}
},
+ "node_modules/i18next": {
+ "version": "23.15.2",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.2.tgz",
+ "integrity": "sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://locize.com"
+ },
+ {
+ "type": "individual",
+ "url": "https://locize.com/i18next.html"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
+ "node_modules/i18next-browser-languagedetector": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
+ "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
+ "node_modules/i18next-http-backend": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.2.tgz",
+ "integrity": "sha512-Hp/kd8/VuoxIHmxsknJXjkTYYHzivAyAF15pzliKzk2TiXC25rZCEerb1pUFoxz4IVrG3fCvQSY51/Lu4ECV4A==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-fetch": "4.0.0"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -13793,6 +14318,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/immer": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
+ "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/immutable": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
@@ -13955,6 +14491,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/intersection-observer": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz",
+ "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==",
+ "license": "Apache-2.0"
+ },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -18333,6 +18875,12 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"dev": true
},
+ "node_modules/module-alias": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz",
+ "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==",
+ "license": "MIT"
+ },
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -18482,7 +19030,6 @@
"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==",
- "dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
@@ -18507,20 +19054,17 @@
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/node-fetch/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==",
- "dev": true
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/node-fetch/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==",
- "dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@@ -18763,7 +19307,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -19601,7 +20144,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -19611,8 +20153,7 @@
"node_modules/prop-types/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/proxy-addr": {
"version": "2.0.7",
@@ -19941,12 +20482,89 @@
"integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==",
"dev": true
},
+ "node_modules/react-hook-form": {
+ "version": "7.53.2",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.2.tgz",
+ "integrity": "sha512-YVel6fW5sOeedd1524pltpHX+jgU2u3DSDtXEaBORNdqiNrsX/nUI/iGXONegttg0mJVnfrIkiV0cmTU6Oo2xw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18 || ^19"
+ }
+ },
+ "node_modules/react-i18next": {
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz",
+ "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.0",
+ "html-parse-stringify": "^3.0.1"
+ },
+ "peerDependencies": {
+ "i18next": ">= 23.2.3",
+ "react": ">= 16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-intersection-observer": {
+ "version": "9.13.1",
+ "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz",
+ "integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
+ "node_modules/react-redux": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
+ "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.3",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25",
+ "react": "^18.0",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@@ -20003,6 +20621,58 @@
}
}
},
+ "node_modules/react-router": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.1.tgz",
+ "integrity": "sha512-WVAhv9oWCNsja5AkK6KLpXJDSJCQizOIyOd4vvB/+eHGbYx5vkhcmcmwWjQ9yqkRClogi+xjEg9fNEOd5EX/tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/cookie": "^0.6.0",
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0",
+ "turbo-stream": "2.4.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.0.1.tgz",
+ "integrity": "sha512-duBzwAAiIabhFPZfDjcYpJ+f08TMbPMETgq254GWne2NW1ZwRHhZLj7tpSp8KGb7JvZzlLcjGUnqLxpZQVEPng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.0.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-router/node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/react-style-singleton": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
@@ -20179,6 +20849,33 @@
"node": ">=0.10.0"
}
},
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/redux-persist": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": ">4.0.0"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -20198,10 +20895,10 @@
}
},
"node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
- "dev": true
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "license": "MIT"
},
"node_modules/regenerator-transform": {
"version": "0.15.2",
@@ -20382,6 +21079,13 @@
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
@@ -20742,10 +21446,11 @@
"dev": true
},
"node_modules/serialize-javascript": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
- "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -20843,6 +21548,13 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -21335,6 +22047,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/style-loader": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz",
@@ -21964,6 +22689,19 @@
"node": ">=12"
}
},
+ "node_modules/trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/trough": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
@@ -22128,6 +22866,13 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
+ "node_modules/turbo-stream": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
+ "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -22287,6 +23032,19 @@
"node": ">=4"
}
},
+ "node_modules/unicorn-magic": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+ "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/unified": {
"version": "10.1.2",
"resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
@@ -22560,6 +23318,16 @@
}
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
+ "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
@@ -22703,6 +23471,15 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -22816,6 +23593,7 @@
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^2.1.1",
@@ -24908,12 +25686,11 @@
"dev": true
},
"@babel/runtime": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz",
- "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==",
- "dev": true,
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
+ "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==",
"requires": {
- "regenerator-runtime": "^0.13.11"
+ "regenerator-runtime": "^0.14.0"
}
},
"@babel/template": {
@@ -25206,6 +25983,12 @@
}
}
},
+ "@faker-js/faker": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.2.tgz",
+ "integrity": "sha512-nI/FP30ZGXb+UaR7yXawVTH40NVKXPIx0tA3GKjkKLjorqBoMAeq4iSEacl8mJmpVhOCDa0vYHwYDmOOcFMrYw==",
+ "dev": true
+ },
"@fal-works/esbuild-plugin-global-externals": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz",
@@ -25246,6 +26029,51 @@
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==",
"dev": true
},
+ "@fortawesome/fontawesome-common-types": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
+ "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw=="
+ },
+ "@fortawesome/fontawesome-svg-core": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz",
+ "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==",
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ }
+ },
+ "@fortawesome/free-brands-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==",
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ }
+ },
+ "@fortawesome/free-regular-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==",
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ }
+ },
+ "@fortawesome/free-solid-svg-icons": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
+ "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==",
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.6.0"
+ }
+ },
+ "@fortawesome/react-fontawesome": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
+ "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
+ "requires": {
+ "prop-types": "^15.8.1"
+ }
+ },
"@humanwhocodes/config-array": {
"version": "0.10.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
@@ -26010,6 +26838,13 @@
"source-map": "^0.7.3"
}
},
+ "@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "dev": true,
+ "peer": true
+ },
"@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -26360,12 +27195,30 @@
"@babel/runtime": "^7.13.10"
}
},
+ "@reduxjs/toolkit": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.4.0.tgz",
+ "integrity": "sha512-wJZEuSKj14tvNfxiIiJws0tQN77/rDqucBq528ApebMIRHyWpCanJVQRxQ8WWZC19iCDKxDsGlbAir3F1layxA==",
+ "dev": true,
+ "requires": {
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ }
+ },
"@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
"integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==",
"dev": true
},
+ "@sindresorhus/merge-streams": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+ "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
+ "dev": true
+ },
"@sinonjs/commons": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz",
@@ -28752,6 +29605,12 @@
"@types/node": "*"
}
},
+ "@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+ "dev": true
+ },
"@types/cross-spawn": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz",
@@ -29076,13 +29935,12 @@
"dev": true
},
"@types/react": {
- "version": "18.2.9",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
- "integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
+ "version": "18.3.12",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
+ "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
"dev": true,
"requires": {
"@types/prop-types": "*",
- "@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
@@ -29095,6 +29953,15 @@
"@types/react": "*"
}
},
+ "@types/redux-persist": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/redux-persist/-/redux-persist-4.3.1.tgz",
+ "integrity": "sha512-YkMnMUk+4//wPtiSTMfsxST/F9Gh9sPWX0LVxHuOidGjojHtMdpep2cYvQgfiDMnj34orXyZI+QJCQMZDlafKA==",
+ "dev": true,
+ "requires": {
+ "redux-persist": "*"
+ }
+ },
"@types/resolve": {
"version": "1.20.6",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
@@ -29107,12 +29974,6 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"dev": true
},
- "@types/scheduler": {
- "version": "0.16.3",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
- "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
- "dev": true
- },
"@types/semver": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
@@ -29175,6 +30036,12 @@
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==",
"dev": true
},
+ "@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==",
+ "dev": true
+ },
"@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
@@ -30318,6 +31185,13 @@
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
+ "bootstrap": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "dev": true,
+ "requires": {}
+ },
"bplist-parser": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
@@ -30889,6 +31763,87 @@
"is-what": "^3.14.1"
}
},
+ "copy-webpack-plugin": {
+ "version": "12.0.2",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz",
+ "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==",
+ "dev": true,
+ "requires": {
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.1",
+ "globby": "^14.0.0",
+ "normalize-path": "^3.0.0",
+ "schema-utils": "^4.2.0",
+ "serialize-javascript": "^6.0.2"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.3"
+ }
+ },
+ "globby": {
+ "version": "14.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz",
+ "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/merge-streams": "^2.1.0",
+ "fast-glob": "^3.3.2",
+ "ignore": "^5.2.4",
+ "path-type": "^5.0.0",
+ "slash": "^5.1.0",
+ "unicorn-magic": "^0.1.0"
+ }
+ },
+ "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
+ },
+ "path-type": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz",
+ "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ }
+ },
+ "slash": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+ "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+ "dev": true
+ }
+ }
+ },
"core-js-compat": {
"version": "3.33.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.1.tgz",
@@ -30923,6 +31878,14 @@
"yaml": "^1.10.0"
}
},
+ "cross-fetch": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
+ "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
+ "requires": {
+ "node-fetch": "^2.6.12"
+ }
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -31513,6 +32476,12 @@
"integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==",
"dev": true
},
+ "email-addresses": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
+ "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
+ "dev": true
+ },
"emittery": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
@@ -32508,9 +33477,9 @@
"dev": true
},
"fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
@@ -32549,6 +33518,12 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
+ "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
+ },
"fastest-levenshtein": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
@@ -32645,6 +33620,23 @@
}
}
},
+ "filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
+ "dev": true
+ },
+ "filenamify": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+ "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+ "dev": true,
+ "requires": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.1",
+ "trim-repeated": "^1.0.0"
+ }
+ },
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -33105,6 +34097,71 @@
"get-intrinsic": "^1.1.1"
}
},
+ "gh-pages": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.1.1.tgz",
+ "integrity": "sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw==",
+ "dev": true,
+ "requires": {
+ "async": "^3.2.4",
+ "commander": "^11.0.0",
+ "email-addresses": "^5.0.0",
+ "filenamify": "^4.3.0",
+ "find-cache-dir": "^3.3.1",
+ "fs-extra": "^11.1.1",
+ "globby": "^6.1.0"
+ },
+ "dependencies": {
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+ "dev": true,
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+ "dev": true,
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ }
+ }
+ },
"giget": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/giget/-/giget-1.2.1.tgz",
@@ -33415,6 +34472,14 @@
"terser": "^5.10.0"
}
},
+ "html-parse-stringify": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
+ "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+ "requires": {
+ "void-elements": "3.1.0"
+ }
+ },
"html-tags": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
@@ -33536,6 +34601,30 @@
"integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
"dev": true
},
+ "i18next": {
+ "version": "23.15.2",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.2.tgz",
+ "integrity": "sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==",
+ "requires": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
+ "i18next-browser-languagedetector": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
+ "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
+ "requires": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
+ "i18next-http-backend": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.2.tgz",
+ "integrity": "sha512-Hp/kd8/VuoxIHmxsknJXjkTYYHzivAyAF15pzliKzk2TiXC25rZCEerb1pUFoxz4IVrG3fCvQSY51/Lu4ECV4A==",
+ "requires": {
+ "cross-fetch": "4.0.0"
+ }
+ },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -33572,6 +34661,12 @@
"optional": true,
"peer": true
},
+ "immer": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
+ "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
+ "dev": true
+ },
"immutable": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
@@ -33693,6 +34788,11 @@
"side-channel": "^1.0.4"
}
},
+ "intersection-observer": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz",
+ "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+ },
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -36799,6 +37899,11 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"dev": true
},
+ "module-alias": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz",
+ "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q=="
+ },
"mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -36917,7 +38022,6 @@
"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==",
- "dev": true,
"requires": {
"whatwg-url": "^5.0.0"
},
@@ -36925,20 +38029,17 @@
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"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==",
- "dev": true
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
@@ -37114,8 +38215,7 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
"object-inspect": {
"version": "1.12.3",
@@ -37715,7 +38815,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -37725,8 +38824,7 @@
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}
}
},
@@ -37986,12 +39084,43 @@
}
}
},
+ "react-hook-form": {
+ "version": "7.53.2",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.2.tgz",
+ "integrity": "sha512-YVel6fW5sOeedd1524pltpHX+jgU2u3DSDtXEaBORNdqiNrsX/nUI/iGXONegttg0mJVnfrIkiV0cmTU6Oo2xw==",
+ "requires": {}
+ },
+ "react-i18next": {
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz",
+ "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==",
+ "requires": {
+ "@babel/runtime": "^7.25.0",
+ "html-parse-stringify": "^3.0.1"
+ }
+ },
+ "react-intersection-observer": {
+ "version": "9.13.1",
+ "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz",
+ "integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==",
+ "requires": {}
+ },
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
+ "react-redux": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
+ "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
+ "dev": true,
+ "requires": {
+ "@types/use-sync-external-store": "^0.0.3",
+ "use-sync-external-store": "^1.0.0"
+ }
+ },
"react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@@ -38021,6 +39150,35 @@
"tslib": "^2.0.0"
}
},
+ "react-router": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.1.tgz",
+ "integrity": "sha512-WVAhv9oWCNsja5AkK6KLpXJDSJCQizOIyOd4vvB/+eHGbYx5vkhcmcmwWjQ9yqkRClogi+xjEg9fNEOd5EX/tw==",
+ "dev": true,
+ "requires": {
+ "@types/cookie": "^0.6.0",
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0",
+ "turbo-stream": "2.4.0"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "dev": true
+ }
+ }
+ },
+ "react-router-dom": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.0.1.tgz",
+ "integrity": "sha512-duBzwAAiIabhFPZfDjcYpJ+f08TMbPMETgq254GWne2NW1ZwRHhZLj7tpSp8KGb7JvZzlLcjGUnqLxpZQVEPng==",
+ "dev": true,
+ "requires": {
+ "react-router": "7.0.1"
+ }
+ },
"react-style-singleton": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
@@ -38149,6 +39307,26 @@
}
}
},
+ "redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "dev": true
+ },
+ "redux-persist": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "dev": true,
+ "requires": {}
+ },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -38165,10 +39343,9 @@
}
},
"regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
- "dev": true
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"regenerator-transform": {
"version": "0.15.2",
@@ -38306,6 +39483,12 @@
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
+ "reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "dev": true
+ },
"resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
@@ -38551,9 +39734,9 @@
}
},
"serialize-javascript": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
- "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
@@ -38639,6 +39822,12 @@
"send": "0.18.0"
}
},
+ "set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "dev": true
+ },
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -39034,6 +40223,15 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
+ "strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"style-loader": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz",
@@ -39512,6 +40710,15 @@
"punycode": "^2.1.1"
}
},
+ "trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"trough": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
@@ -39624,6 +40831,12 @@
}
}
},
+ "turbo-stream": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
+ "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
+ "dev": true
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -39737,6 +40950,12 @@
"integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
"dev": true
},
+ "unicorn-magic": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+ "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+ "dev": true
+ },
"unified": {
"version": "10.1.2",
"resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
@@ -39924,6 +41143,13 @@
"tslib": "^2.0.0"
}
},
+ "use-sync-external-store": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
+ "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
+ "dev": true,
+ "requires": {}
+ },
"util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
@@ -40036,6 +41262,11 @@
"unist-util-stringify-position": "^3.0.0"
}
},
+ "void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
+ },
"w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
diff --git a/package.json b/package.json
index 492664d1f..bfb38dc34 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,15 @@
{
"name": "react-start-template",
"version": "1.0.0",
+ "homepage": "https://yurabox2017.github.io",
"description": "Start repo with required configuration",
"main": "src/index.tsx",
"author": "Igor ",
"scripts": {
"start": "webpack serve --mode development",
"build": "webpack --mode production",
+ "predeploy": "npm run build",
+ "deploy": "gh-pages -d dist",
"test": "jest src",
"lint": "eslint src --fix",
"storybook": "storybook dev -p 6006",
@@ -18,6 +21,8 @@
"@babel/preset-env": "^7.22.4",
"@babel/preset-react": "^7.22.3",
"@babel/preset-typescript": "^7.21.5",
+ "@faker-js/faker": "^9.0.2",
+ "@reduxjs/toolkit": "^2.4.0",
"@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-interactions": "^7.6.17",
"@storybook/addon-links": "^7.6.17",
@@ -31,10 +36,13 @@
"@types/node": "^20.2.5",
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
+ "@types/redux-persist": "^4.3.1",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"babel-loader": "^9.1.2",
+ "bootstrap": "^5.3.3",
"clean-webpack-plugin": "^4.0.0",
+ "copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.8.1",
"eslint": "8.22.0",
"eslint-config-airbnb": "^19.0.4",
@@ -46,6 +54,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.8.0",
"fork-ts-checker-webpack-plugin": "^8.0.0",
+ "gh-pages": "^6.1.1",
"html-webpack-plugin": "^5.5.1",
"husky": "^8.0.0",
"jest": "^29.5.0",
@@ -53,6 +62,10 @@
"less-loader": "^11.1.2",
"mini-css-extract-plugin": "^2.7.6",
"prettier": "2.8.8",
+ "react-redux": "^9.1.2",
+ "react-router": "^7.0.1",
+ "react-router-dom": "^7.0.1",
+ "redux-persist": "^6.0.0",
"sass": "^1.71.1",
"sass-loader": "^13.3.1",
"storybook": "^7.6.17",
@@ -60,12 +73,25 @@
"ts-jest": "^29.1.0",
"typescript": "^5.1.3",
"webpack": "^5.85.0",
- "webpack-cli": "^5.1.3",
+ "webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.0"
},
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^6.6.0",
+ "@fortawesome/free-brands-svg-icons": "^6.6.0",
+ "@fortawesome/free-regular-svg-icons": "^6.6.0",
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
+ "@fortawesome/react-fontawesome": "^0.2.2",
"clsx": "^1.2.1",
+ "i18next": "^23.15.2",
+ "i18next-browser-languagedetector": "^8.0.0",
+ "i18next-http-backend": "^2.6.2",
+ "intersection-observer": "^0.12.2",
+ "module-alias": "^2.2.3",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.53.2",
+ "react-i18next": "^15.0.2",
+ "react-intersection-observer": "^9.13.1"
}
}
diff --git a/src/app/App.css b/src/app/App.css
index 78b8850cf..1d04523ef 100644
--- a/src/app/App.css
+++ b/src/app/App.css
@@ -1,38 +1,66 @@
.App {
- text-align: center;
+ text-align: center;
+ height: 100vh;
}
.App-logo {
- height: 40vmin;
- pointer-events: none;
+ height: 40vmin;
+ pointer-events: none;
+}
+
+.text-left {
+ text-align: left !important;
}
@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
+ .App-logo {
+ animation: App-logo-spin infinite 20s linear;
+ }
}
.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
+ background-color: #282c34;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-size: calc(10px + 2vmin);
+ color: white;
+}
+
+.bg-light {
+ background-color: #f0f0f0 !important;
+ color: #282c34 !important;
+}
+
+.bg-dark {
+ background-color: #282c34 !important;
+ color: white !important;
}
+.navbar.bg-dark {
+ border-bottom: 1px solid white;
+}
+.navbar.bg-light {
+ border-bottom: 1px solid black;
+}
+.navbar.bg-dark .nav-link {
+ color: white !important;
+}
+.navbar.bg-light .nav-link {
+ color: black !important;
+}
.App-link {
- color: #61dafb;
+ color: #61dafb;
}
@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
}
diff --git a/src/app/App.tsx b/src/app/App.tsx
index dcc0ff8ad..1f8fb73d2 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -1,17 +1,40 @@
-import React from 'react';
-import logo from './logo.svg';
+import React, { useEffect, useState } from 'react';
import './App.css';
+import { Theme, ThemeContext } from 'src/context/themeContext';
+import { LocalizationInitiator } from 'src/localization/LocalizationInitiator';
+import { I18nextProvider } from 'react-i18next';
+import i18n from 'src/localization/settings';
+import { CustomRoutes } from 'src/routes/routes';
function App() {
+ const [theme, setTheme] = useState(() => 'light');
+
+ const setHtmlAttribute = () => {
+ const html = document.querySelector('html');
+ if (html) html.setAttribute('data-bs-theme', theme);
+ };
+
+ useEffect(() => {
+ setHtmlAttribute();
+ }, [theme]);
+
+ const toggleTheme = () => {
+ setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
+ setHtmlAttribute();
+ };
+
return (
-
-
-
-
- Текст писать тут
-
-
-
+ <>
+
+
+
+
+
+ {/* */}
+
+
+
+ >
);
}
diff --git a/src/assets/businessman (1).png b/src/assets/businessman (1).png
new file mode 100644
index 000000000..0dc75d24e
Binary files /dev/null and b/src/assets/businessman (1).png differ
diff --git a/src/assets/businessman.png b/src/assets/businessman.png
new file mode 100644
index 000000000..96f68193c
Binary files /dev/null and b/src/assets/businessman.png differ
diff --git a/src/assets/cleaner.png b/src/assets/cleaner.png
new file mode 100644
index 000000000..3c0f06fe0
Binary files /dev/null and b/src/assets/cleaner.png differ
diff --git a/src/assets/free-icon-cleaning-9012135.png b/src/assets/free-icon-cleaning-9012135.png
new file mode 100644
index 000000000..de7edd177
Binary files /dev/null and b/src/assets/free-icon-cleaning-9012135.png differ
diff --git a/src/assets/free-icon-cleaning-9717764.png b/src/assets/free-icon-cleaning-9717764.png
new file mode 100644
index 000000000..18e0305e8
Binary files /dev/null and b/src/assets/free-icon-cleaning-9717764.png differ
diff --git a/src/assets/free-icon-household-7029117.png b/src/assets/free-icon-household-7029117.png
new file mode 100644
index 000000000..c27f94814
Binary files /dev/null and b/src/assets/free-icon-household-7029117.png differ
diff --git a/src/assets/logo-clean.png b/src/assets/logo-clean.png
new file mode 100644
index 000000000..100fe0a13
Binary files /dev/null and b/src/assets/logo-clean.png differ
diff --git a/src/assets/logo-image.png b/src/assets/logo-image.png
new file mode 100644
index 000000000..6fc41c902
Binary files /dev/null and b/src/assets/logo-image.png differ
diff --git a/src/assets/logo-image32.png b/src/assets/logo-image32.png
new file mode 100644
index 000000000..dcc566e73
Binary files /dev/null and b/src/assets/logo-image32.png differ
diff --git a/src/assets/logo-image64.png b/src/assets/logo-image64.png
new file mode 100644
index 000000000..0037316ad
Binary files /dev/null and b/src/assets/logo-image64.png differ
diff --git a/src/assets/mop and broom.png b/src/assets/mop and broom.png
new file mode 100644
index 000000000..721c39c79
Binary files /dev/null and b/src/assets/mop and broom.png differ
diff --git a/src/assets/yoga-mat-cleaning-kit.png b/src/assets/yoga-mat-cleaning-kit.png
new file mode 100644
index 000000000..a824d7a6d
Binary files /dev/null and b/src/assets/yoga-mat-cleaning-kit.png differ
diff --git a/src/context/themeContext.ts b/src/context/themeContext.ts
new file mode 100644
index 000000000..2feca76fb
--- /dev/null
+++ b/src/context/themeContext.ts
@@ -0,0 +1,10 @@
+import { createContext } from 'react';
+
+export type Theme = 'light' | 'dark';
+
+export interface ThemeContextType {
+ theme: Theme;
+ toggleTheme: () => void;
+}
+
+export const ThemeContext = createContext({} as ThemeContextType);
diff --git a/src/entities/interfaces/ICartButton.ts b/src/entities/interfaces/ICartButton.ts
new file mode 100644
index 000000000..b02dc073a
--- /dev/null
+++ b/src/entities/interfaces/ICartButton.ts
@@ -0,0 +1,8 @@
+import { ICartProduct } from './ICartProduct';
+
+export default interface ICartButton {
+ product: ICartProduct;
+ // addProduct: () => void;
+ // increment: () => void;
+ // decrement: () => void;
+}
diff --git a/src/entities/interfaces/ICartProduct.ts b/src/entities/interfaces/ICartProduct.ts
new file mode 100644
index 000000000..2b9fe814a
--- /dev/null
+++ b/src/entities/interfaces/ICartProduct.ts
@@ -0,0 +1,3 @@
+import IShortProduct from './IShortProduct';
+
+export interface ICartProduct extends IShortProduct {}
diff --git a/src/entities/interfaces/IFullProduct.ts b/src/entities/interfaces/IFullProduct.ts
new file mode 100644
index 000000000..d19182f2f
--- /dev/null
+++ b/src/entities/interfaces/IFullProduct.ts
@@ -0,0 +1,7 @@
+export default interface IFullProduct {
+ price: number;
+ images: string[];
+ category: string;
+ title: string;
+ description: string;
+}
diff --git a/src/entities/interfaces/IFuncProps.ts b/src/entities/interfaces/IFuncProps.ts
new file mode 100644
index 000000000..d7f72893f
--- /dev/null
+++ b/src/entities/interfaces/IFuncProps.ts
@@ -0,0 +1,6 @@
+import IFullProduct from './IFullProduct';
+import IShortProduct from './IShortProduct';
+
+export default interface FuncProps {
+ products: IShortProduct[];
+}
diff --git a/src/entities/interfaces/IModal.ts b/src/entities/interfaces/IModal.ts
new file mode 100644
index 000000000..77a26e687
--- /dev/null
+++ b/src/entities/interfaces/IModal.ts
@@ -0,0 +1,8 @@
+import React from 'react';
+
+export default interface IModal {
+ children?: React.ReactNode;
+ visible: boolean;
+ header: string;
+ onClose: () => void;
+}
diff --git a/src/entities/interfaces/IShortProduct.ts b/src/entities/interfaces/IShortProduct.ts
new file mode 100644
index 000000000..c29487937
--- /dev/null
+++ b/src/entities/interfaces/IShortProduct.ts
@@ -0,0 +1,8 @@
+export default interface IShortProduct {
+ id: number;
+ category: string;
+ title: string;
+ price: number;
+ description: string;
+ image: string;
+}
diff --git a/src/entities/interfaces/IUserProfile.ts b/src/entities/interfaces/IUserProfile.ts
new file mode 100644
index 000000000..024f38826
--- /dev/null
+++ b/src/entities/interfaces/IUserProfile.ts
@@ -0,0 +1,8 @@
+export interface IUserProfile {
+ id: number;
+ email: string;
+ lastName: string;
+ firstName: string;
+ phone: string;
+ isAdmin: boolean;
+}
diff --git a/src/features/LangSwitcher/LangSwitcher.sass b/src/features/LangSwitcher/LangSwitcher.sass
new file mode 100644
index 000000000..75208d4b2
--- /dev/null
+++ b/src/features/LangSwitcher/LangSwitcher.sass
@@ -0,0 +1,6 @@
+.root
+ border: 0
+ padding: 4px
+ background: none
+ outline: none
+ cursor: pointer
\ No newline at end of file
diff --git a/src/features/LangSwitcher/LangSwitcher.tsx b/src/features/LangSwitcher/LangSwitcher.tsx
new file mode 100644
index 000000000..bc8aaac1f
--- /dev/null
+++ b/src/features/LangSwitcher/LangSwitcher.tsx
@@ -0,0 +1,28 @@
+import React, { FC, useContext } from 'react';
+import cn from 'clsx';
+import { useTranslation } from 'react-i18next';
+
+import s from './LangSwitcher.sass';
+import { Locale } from 'src/localization/settings';
+import { ThemeContext } from 'src/context/themeContext';
+import { Link } from 'react-router';
+
+export type ThemeSwitcherProps = {
+ className?: string;
+};
+
+export const LangSwitcher: FC = ({ className }) => {
+ const { i18n } = useTranslation();
+ const theme = useContext(ThemeContext);
+
+ const lang = (i18n.language as Locale) === Locale.ru ? Locale.en : Locale.ru;
+ return (
+ i18n.changeLanguage(lang)}
+ >
+ {lang}
+
+ );
+};
diff --git a/src/features/store/cart.slice.ts b/src/features/store/cart.slice.ts
new file mode 100644
index 000000000..98134404b
--- /dev/null
+++ b/src/features/store/cart.slice.ts
@@ -0,0 +1,42 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { loadState } from './storage';
+import { ICartProduct } from 'src/entities/interfaces/ICartProduct';
+import type {PayloadAction} from "@reduxjs/toolkit"
+export const CART_PERSISTENT_STATE = 'cartData';
+
+export interface ICartState {
+ items: ICartProduct[];
+}
+
+const initialState: ICartState = loadState(CART_PERSISTENT_STATE) ?? {
+ items: [],
+};
+
+const cartSlice = createSlice({
+ name: 'cart',
+ initialState,
+ reducers: {
+ clear: (state) => {
+ state.items = [];
+ },
+ delete: (state, action: PayloadAction) => {
+ state.items = state.items.filter((i) => i.id !== action.payload);
+ },
+ add: (state, action: PayloadAction) => {
+ const existed = state.items.find((i) => i === action.payload);
+ // if (!existed) {
+ state.items.push(action.payload);
+ return;
+ // }
+ // state.items.map((i) => {
+ // if (i === action.payload) {
+ // i.count += 1;
+ // }
+ // return i;
+ // });
+ },
+ },
+});
+
+export default cartSlice.reducer;
+export const cartActions = cartSlice.actions;
diff --git a/src/features/store/product.slice.ts b/src/features/store/product.slice.ts
new file mode 100644
index 000000000..f587fb858
--- /dev/null
+++ b/src/features/store/product.slice.ts
@@ -0,0 +1,43 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { loadState } from './storage';
+import IShortProduct from 'src/entities/interfaces/IShortProduct';
+import type {PayloadAction} from "@reduxjs/toolkit"
+
+export const PRODUCT_PERSISTENT_STATE = 'productData';
+
+export interface IProductState {
+ items: IShortProduct[];
+}
+
+const initialState: IProductState = loadState(PRODUCT_PERSISTENT_STATE) ?? {
+ items: [],
+};
+
+const productSlice = createSlice({
+ name: 'product',
+ initialState,
+ reducers: {
+ clear: (state) => {
+ state.items = [];
+ },
+ delete: (state, action: PayloadAction) => {
+ state.items = state.items.filter((i) => i.id !== action.payload);
+ },
+ add: (state, action: PayloadAction) => {
+ const existed = state.items.find((i) => i === action.payload);
+ // if (!existed) {
+ state.items.push(action.payload);
+ return;
+ // }
+ // state.items.map((i) => {
+ // if (i === action.payload) {
+ // i.count += 1;
+ // }
+ // return i;
+ // });
+ },
+ },
+});
+
+export default productSlice.reducer;
+export const productActions = productSlice.actions;
diff --git a/src/features/store/storage.ts b/src/features/store/storage.ts
new file mode 100644
index 000000000..7ff3db3a3
--- /dev/null
+++ b/src/features/store/storage.ts
@@ -0,0 +1,17 @@
+export function loadState(key: string): T | undefined {
+ try {
+ const jsonState = localStorage.getItem(key);
+ if (!jsonState) {
+ return undefined;
+ }
+ return JSON.parse(jsonState);
+ } catch (e) {
+ console.error(e);
+ return undefined;
+ }
+}
+
+export function saveState(state: T, key: string) {
+ const stringState = JSON.stringify(state);
+ localStorage.setItem(key, stringState);
+}
diff --git a/src/features/store/store.ts b/src/features/store/store.ts
new file mode 100644
index 000000000..ef507a2ea
--- /dev/null
+++ b/src/features/store/store.ts
@@ -0,0 +1,37 @@
+import { combineReducers, configureStore } from '@reduxjs/toolkit';
+import storage from 'redux-persist/lib/storage';
+import userSlice, { JWT_PERSISTENT_STATE } from './user.slice';
+import cartSlice from './cart.slice';
+import productSlice from './product.slice';
+import persistReducer from 'redux-persist/es/persistReducer';
+import persistStore from 'redux-persist/es/persistStore';
+
+const persistConfig = {
+ key: 'root',
+ storage,
+ debug: true,
+};
+
+const rootReducer = combineReducers({ userData: userSlice, cartData: cartSlice, productData: productSlice });
+
+const persistedReducer = persistReducer(persistConfig, rootReducer);
+
+export const store = configureStore({
+ reducer: {
+ user: persistedReducer,
+ },
+ middleware: (getDefaultMiddleware) =>
+ getDefaultMiddleware({
+ serializableCheck: {
+ ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
+ },
+ }),
+});
+
+// store.subscribe(() => {
+// saveState({ userData: store.getState().user }, JWT_PERSISTENT_STATE);
+// });
+
+export type RootState = ReturnType;
+export type AppDispath = typeof store.dispatch;
+export const persistor = persistStore(store);
diff --git a/src/features/store/user.slice.ts b/src/features/store/user.slice.ts
new file mode 100644
index 000000000..b5a4f668a
--- /dev/null
+++ b/src/features/store/user.slice.ts
@@ -0,0 +1,37 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { loadState } from './storage';
+import { IUserProfile } from 'src/entities/interfaces/IUserProfile';
+import type {PayloadAction} from "@reduxjs/toolkit"
+
+export const JWT_PERSISTENT_STATE = 'userData';
+
+export interface IUserState {
+ jwt: string | null;
+ profile?: IUserProfile;
+}
+
+const initialState: IUserState = {
+ jwt: loadState(JWT_PERSISTENT_STATE)?.jwt ?? null,
+ profile: loadState(JWT_PERSISTENT_STATE)?.profile ?? null,
+};
+
+const userSlice = createSlice({
+ name: 'user',
+ initialState,
+ reducers: {
+ addJwt: (state, action: PayloadAction) => {
+ state.jwt = action.payload;
+ },
+ addProfile: (state, action: PayloadAction) => {
+ state.jwt = action.payload.jwt;
+ state.profile = action.payload.profile;
+ },
+ logout: (state) => {
+ state.jwt = null;
+ state.profile = null;
+ },
+ },
+});
+
+export default userSlice.reducer;
+export const userActions = userSlice.actions;
diff --git a/src/homeworks/ts1/1_base.test.js b/src/homeworks/ts1/1_base.test.js
index ee68dc16f..ff77416da 100644
--- a/src/homeworks/ts1/1_base.test.js
+++ b/src/homeworks/ts1/1_base.test.js
@@ -1,26 +1,26 @@
// Этот блок кода удалить и раскомментировать код ниже
-it('remove it', () => {
- expect(true).toBe(true);
-});
-
-// import { transformCustomers } from './1_base';
-//
-// describe('all', () => {
-// it('transformCustomers', () => {
-// const customers = [
-// { id: 1, name: 'John', age: 25, isSubscribed: true },
-// { id: 2, name: 'Mary', age: 40, isSubscribed: false },
-// { id: 3, name: 'Bob', age: 32, isSubscribed: true },
-// { id: 4, name: 'Alice', age: 22, isSubscribed: true },
-// { id: 5, name: 'David', age: 48, isSubscribed: false },
-// ];
-//
-// expect(transformCustomers(customers)).toEqual({
-// 1: { name: 'John', age: 25, isSubscribed: true },
-// 2: { name: 'Mary', age: 40, isSubscribed: false },
-// 3: { name: 'Bob', age: 32, isSubscribed: true },
-// 4: { name: 'Alice', age: 22, isSubscribed: true },
-// 5: { name: 'David', age: 48, isSubscribed: false },
-// });
-// });
+// it('remove it', () => {
+// expect(true).toBe(true);
// });
+
+import { transformCustomers } from './1_base';
+
+describe('all', () => {
+ it('transformCustomers', () => {
+ const customers = [
+ { id: 1, name: 'John', age: 25, isSubscribed: true },
+ { id: 2, name: 'Mary', age: 40, isSubscribed: false },
+ { id: 3, name: 'Bob', age: 32, isSubscribed: true },
+ { id: 4, name: 'Alice', age: 22, isSubscribed: true },
+ { id: 5, name: 'David', age: 48, isSubscribed: false },
+ ];
+
+ expect(transformCustomers(customers)).toEqual({
+ 1: { name: 'John', age: 25, isSubscribed: true },
+ 2: { name: 'Mary', age: 40, isSubscribed: false },
+ 3: { name: 'Bob', age: 32, isSubscribed: true },
+ 4: { name: 'Alice', age: 22, isSubscribed: true },
+ 5: { name: 'David', age: 48, isSubscribed: false },
+ });
+ });
+});
diff --git a/src/homeworks/ts1/1_base.js b/src/homeworks/ts1/1_base.ts
similarity index 53%
rename from src/homeworks/ts1/1_base.js
rename to src/homeworks/ts1/1_base.ts
index 611b3a92f..2bc11f275 100644
--- a/src/homeworks/ts1/1_base.js
+++ b/src/homeworks/ts1/1_base.ts
@@ -1,16 +1,16 @@
/**
* Нужно превратить файл в ts и указать типы аргументов и типы возвращаемого значения
* */
-export const removePlus = (string) => string.replace(/^\+/, '');
+export const removePlus = (string: string): string => string.replace(/^\+/, '');
-export const addPlus = (string) => `+${string}`;
+export const addPlus = (string: string): string => `+${string}`;
-export const removeFirstZeros = (value) => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2');
+export const removeFirstZeros = (value: string): string => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2');
-export const getBeautifulNumber = (value, separator = ' ') =>
+export const getBeautifulNumber = (value: number, separator = ' '): string =>
value?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator);
-export const round = (value, accuracy = 2) => {
+export const round = (value: number, accuracy = 2): number => {
const d = 10 ** accuracy;
return Math.round(value * d) / d;
};
@@ -18,7 +18,8 @@ export const round = (value, accuracy = 2) => {
const transformRegexp =
/(matrix\(-?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, )(-?\d+(\.\d+)?), (-?\d+(\.\d+)?)\)/;
-export const getTransformFromCss = (transformCssString) => {
+type coordinate = { x: number; y: number };
+export const getTransformFromCss = (transformCssString: string): coordinate => {
const data = transformCssString.match(transformRegexp);
if (!data) return { x: 0, y: 0 };
return {
@@ -27,20 +28,20 @@ export const getTransformFromCss = (transformCssString) => {
};
};
-export const getColorContrastValue = ([red, green, blue]) =>
+export const getColorContrastValue = ([red, green, blue]: [number, number, number]): number =>
// http://www.w3.org/TR/AERT#color-contrast
Math.round((red * 299 + green * 587 + blue * 114) / 1000);
-export const getContrastType = (contrastValue) => (contrastValue > 125 ? 'black' : 'white');
+export const getContrastType = (contrastValue: number): string => (contrastValue > 125 ? 'black' : 'white');
export const shortColorRegExp = /^#[0-9a-f]{3}$/i;
export const longColorRegExp = /^#[0-9a-f]{6}$/i;
-export const checkColor = (color) => {
+export const checkColor = (color: string): void | never => {
if (!longColorRegExp.test(color) && !shortColorRegExp.test(color)) throw new Error(`invalid hex color: ${color}`);
};
-export const hex2rgb = (color) => {
+export const hex2rgb = (color: string): [number, number, number] => {
checkColor(color);
if (shortColorRegExp.test(color)) {
const red = parseInt(color.substring(1, 2), 16);
@@ -54,12 +55,24 @@ export const hex2rgb = (color) => {
return [red, green, blue];
};
-export const getNumberedArray = (arr) => arr.map((value, number) => ({ value, number }));
-export const toStringArray = (arr) => arr.map(({ value, number }) => `${value}_${number}`);
+export const getNumberedArray = (arr: [T]): { value: T; number: number }[] =>
+ arr.map((value, number) => ({ value, number }));
+export const toStringArray = (arr: [{ value: T; number: number }]) =>
+ arr.map(({ value, number }) => `${value}_${number}`);
-export const transformCustomers = (customers) => {
+type Key = {
+ id: number;
+};
+type Customer = {
+ name: string;
+ age: number;
+ isSubscribed: boolean;
+};
+type CustomerKey = Key & Customer;
+
+export const transformCustomers = (customers: CustomerKey[]) => {
return customers.reduce((acc, customer) => {
acc[customer.id] = { name: customer.name, age: customer.age, isSubscribed: customer.isSubscribed };
return acc;
- }, {});
+ }, {} as Customer[]);
};
diff --git a/src/homeworks/ts1/2_repair.ts b/src/homeworks/ts1/2_repair.ts
index 19e98c068..86ead12eb 100644
--- a/src/homeworks/ts1/2_repair.ts
+++ b/src/homeworks/ts1/2_repair.ts
@@ -2,46 +2,50 @@
* Здесь код с ошибками типов. Нужно их устранить
* */
-// // Мы это не проходили, но по тексту ошибки можно понять, как это починить
-// export const getFakeApi = async (): void => {
-// const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json());
-// console.log(result);
-// };
-//
-// // Мы это не проходили, но по тексту ошибки можно понять, как это починить
-// export class SomeClass {
-// constructor() {
-// this.set = new Set([1]);
-// this.channel = new BroadcastChannel('test-broadcast-channel');
-// }
-// }
-//
-// export type Data = {
-// type: 'Money' | 'Percent';
-// value: DataValue;
-// };
-//
-// export type DataValue = Money | Percent;
-//
-// export type Money = {
-// currency: string;
-// amount: number;
-// };
-//
-// export type Percent = {
-// percent: number;
-// };
-//
-// // Здесь, возможно, нужно использовать as, возможно в switch передавать немного по-другому
-// const getDataAmount = (data: Data): number => {
-// switch (data.type) {
-// case 'Money':
-// return data.value.amount;
-//
-// default: {
-// // eslint-disable-next-line @typescript-eslint/no-unused-vars
-// const unhandled: never = data; // здесь, возможно, нужно использовать нечто другое. :never должен остаться
-// throw new Error(`unknown type: ${data.type}`);
-// }
-// }
-// };
+// Мы это не проходили, но по тексту ошибки можно понять, как это починить
+export const getFakeApi = async (): Promise => {
+ const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json());
+ console.log(result);
+};
+
+// Мы это не проходили, но по тексту ошибки можно понять, как это починить
+export class SomeClass {
+ set: Set;
+ channel: BroadcastChannel;
+
+ constructor() {
+ this.set = new Set([1]);
+ this.channel = new BroadcastChannel('test-broadcast-channel');
+ }
+}
+
+export type Data = {
+ type: 'Money' | 'Percent';
+ value: DataValue;
+};
+
+export type DataValue = Money | Percent;
+
+export type Money = {
+ currency: string;
+ amount: number;
+};
+
+export type Percent = {
+ percent: number;
+};
+
+// Здесь, возможно, нужно использовать as, возможно в switch передавать немного по-другому
+const getDataAmount = (data: Data): number => {
+ switch (data.type) {
+ case 'Money':
+ return (data.value as Money).amount;
+ case 'Percent':
+ return (data.value as Percent).percent;
+ default: {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const unhandled: never | Data = data; // здесь, возможно, нужно использовать нечто другое. :never должен остаться
+ throw new Error(`unknown type: ${data.type}`);
+ }
+ }
+};
diff --git a/src/homeworks/ts1/3_write.test.js b/src/homeworks/ts1/3_write.test.js
index 5b5173063..5a50badc4 100644
--- a/src/homeworks/ts1/3_write.test.js
+++ b/src/homeworks/ts1/3_write.test.js
@@ -1,35 +1,35 @@
// Этот блок кода удалить и раскомментировать код ниже
-it('remove it', () => {
- expect(true).toBe(true);
-});
-
-// import { createRandomOperation, createRandomProduct } from './3_write';
-//
-// describe('all', () => {
-// it('operation', () => {
-// const createdAt = '2023-06-06T12:06:56.957Z';
-// const operation = createRandomOperation(createdAt);
-// expect(operation).toHaveProperty('createdAt', createdAt);
-// expect(operation).toHaveProperty('id');
-// expect(operation).toHaveProperty('name');
-// expect(operation).toHaveProperty('desc');
-// expect(operation).toHaveProperty('createdAt');
-// expect(operation).toHaveProperty('amount');
-// expect(operation).toHaveProperty('category');
-// expect(operation).toHaveProperty('type');
-// });
-//
-// it('product', () => {
-// const createdAt = '2023-06-06T12:06:56.957Z';
-// const product = createRandomProduct(createdAt);
-// expect(product).toHaveProperty('createdAt', createdAt);
-// expect(product).toHaveProperty('id');
-// expect(product).toHaveProperty('name');
-// expect(product).toHaveProperty('photo');
-// expect(product).toHaveProperty('desc');
-// expect(product).toHaveProperty('createdAt');
-// expect(product).toHaveProperty('oldPrice');
-// expect(product).toHaveProperty('price');
-// expect(product).toHaveProperty('category');
-// });
+// it('remove it', () => {
+// expect(true).toBe(true);
// });
+
+import { createRandomOperation, createRandomProduct } from './3_write';
+
+describe('all', () => {
+ it('operation', () => {
+ const createdAt = '2023-06-06T12:06:56.957Z';
+ const operation = createRandomOperation(createdAt);
+ expect(operation).toHaveProperty('createdAt', createdAt);
+ expect(operation).toHaveProperty('id');
+ expect(operation).toHaveProperty('name');
+ expect(operation).toHaveProperty('desc');
+ expect(operation).toHaveProperty('createdAt');
+ expect(operation).toHaveProperty('amount');
+ expect(operation).toHaveProperty('category');
+ expect(operation).toHaveProperty('type');
+ });
+
+ it('product', () => {
+ const createdAt = '2023-06-06T12:06:56.957Z';
+ const product = createRandomProduct(createdAt);
+ expect(product).toHaveProperty('createdAt', createdAt);
+ expect(product).toHaveProperty('id');
+ expect(product).toHaveProperty('name');
+ expect(product).toHaveProperty('photo');
+ expect(product).toHaveProperty('desc');
+ expect(product).toHaveProperty('createdAt');
+ expect(product).toHaveProperty('oldPrice');
+ expect(product).toHaveProperty('price');
+ expect(product).toHaveProperty('category');
+ });
+});
diff --git a/src/homeworks/ts1/3_write.ts b/src/homeworks/ts1/3_write.ts
index 15f9dcdf2..f237ef636 100644
--- a/src/homeworks/ts1/3_write.ts
+++ b/src/homeworks/ts1/3_write.ts
@@ -1,3 +1,4 @@
+import { faker } from '@faker-js/faker';
/**
* Функции написанные здесь пригодятся на последующих уроках
* С помощью этих функций мы будем добавлять элементы в список для проверки динамической загрузки
@@ -42,15 +43,75 @@
* - category (Категория)
* - type ('Profit')
* */
+export type Category = {
+ id: number;
+ name: string;
+ photo?: string;
+};
+export type Product = {
+ id: number;
+ name: string;
+ photo: string;
+ desc?: string;
+ createdAt: string;
+ oldPrice?: number;
+ price: number;
+ category: Category;
+};
+
+export type Cost = {
+ id: string;
+ name: string;
+ desc?: string;
+ createdAt: string;
+ amount: number;
+ category: Category;
+ type: Cost;
+};
+
+export type Profit = {
+ id: string;
+ name: string;
+ desc?: string;
+ createdAt: string;
+ amount: number;
+ category: Category;
+ type: Profit;
+};
/**
* Создает случайный продукт (Product).
* Принимает дату создания (строка)
* */
-// export const createRandomProduct = (createdAt: string) => {};
+export const createRandomProduct = (createdAt: string): Product => ({
+ id: faker.number.int({ max: 5 }),
+ name: faker.commerce.product(),
+ photo: faker.image.avatar(),
+ desc: faker.commerce.productDescription(),
+ createdAt: createdAt,
+ oldPrice: +faker.commerce.price({ min: 1000, max: 5000 }),
+ price: +faker.commerce.price({ min: 1000, max: 5000 }),
+ category: {
+ id: faker.number.int(),
+ name: faker.company.name(),
+ photo: faker.image.avatar(),
+ },
+});
/**
* Создает случайную операцию (Operation).
* Принимает дату создания (строка)
* */
-// export const createRandomOperation = (createdAt: string) => {};
+export const createRandomOperation = (createdAt: string): Cost | Profit => ({
+ id: faker.string.sample(),
+ createdAt: createdAt,
+ name: faker.person.fullName(),
+ desc: 'desc',
+ amount: faker.number.int(),
+ category: {
+ id: faker.number.int(),
+ name: faker.company.name(),
+ photo: faker.image.avatar(),
+ },
+ type: this,
+});
diff --git a/src/homeworks/ts1/accountService/AccountService.test.ts b/src/homeworks/ts1/accountService/AccountService.test.ts
new file mode 100644
index 000000000..0b779c193
--- /dev/null
+++ b/src/homeworks/ts1/accountService/AccountService.test.ts
@@ -0,0 +1,53 @@
+import { AccountService } from './AccountService';
+import { productDiscount, userDiscount } from './accountServiceEnum';
+
+describe('AccountService', () => {
+ let accountService: AccountService;
+
+ beforeEach(() => {
+ accountService = new AccountService();
+ });
+
+ it('Set user discount', () => {
+ accountService.setUserDiscount(userDiscount.Premium, 30);
+ accountService.setUserDiscount(userDiscount.Standard, 20);
+
+ const discountPremium = accountService.getDiscount(productDiscount.Car, userDiscount.Premium);
+ const discountStandard = accountService.getDiscount(productDiscount.Car, userDiscount.Standard);
+
+ expect(discountPremium).toBe(30);
+ expect(discountStandard).toBe(20);
+ });
+
+ it('Set product and user discount', () => {
+ accountService.setUserDiscount(userDiscount.Premium, 30);
+ accountService.setUserDiscount(userDiscount.Standard, 20);
+ accountService.setUserDiscount(userDiscount.Gold, 30);
+
+ accountService.setProductDiscount(productDiscount.Car, userDiscount.Premium, 10);
+ accountService.setProductDiscount(productDiscount.Car, userDiscount.Standard, 5);
+
+ const discountPremium = accountService.getDiscount(productDiscount.Car, userDiscount.Premium);
+ const discountStandard = accountService.getDiscount(productDiscount.Car, userDiscount.Standard);
+ const discountFree = accountService.getDiscount(productDiscount.Car, userDiscount.Free);
+ const discountGold = accountService.getDiscount(productDiscount.Car, userDiscount.Gold);
+
+ expect(discountPremium).toBe(40);
+ expect(discountStandard).toBe(25);
+ expect(discountGold).toBe(30);
+ expect(discountFree).toBe(0);
+
+ });
+
+ it('Set user negative discount', () => {
+ expect(() => accountService.setUserDiscount(userDiscount.Premium, -15)).toThrow(
+ 'Скидка не может быть меньше нуля!'
+ );
+ });
+
+ it('Set product negative discount', () => {
+ expect(() => accountService.setProductDiscount(productDiscount.Food, userDiscount.Premium, -10)).toThrow(
+ 'Скидка не может быть меньше нуля!'
+ );
+ });
+});
diff --git a/src/homeworks/ts1/accountService/AccountService.ts b/src/homeworks/ts1/accountService/AccountService.ts
new file mode 100644
index 000000000..8dac1f00f
--- /dev/null
+++ b/src/homeworks/ts1/accountService/AccountService.ts
@@ -0,0 +1,35 @@
+import { productDiscount, userDiscount } from './accountServiceEnum';
+
+export type UserType = userDiscount;
+export type ProductType = productDiscount;
+
+export class AccountService {
+ private userDiscounts: Map = new Map();
+ private productDiscounts: Map> = new Map();
+
+ setUserDiscount(user: UserType, discount: number) {
+ if (discount < 0) throw new Error('Скидка не может быть меньше нуля!');
+
+ this.userDiscounts.set(user, discount);
+ }
+
+ setProductDiscount(productType: ProductType, userType: UserType, discount: number) {
+ if (discount < 0) {
+ throw new Error('Скидка не может быть меньше нуля!');
+ }
+
+ if (!this.productDiscounts.has(productType)) {
+ this.productDiscounts.set(productType, new Map());
+ }
+
+ const mapProducts = this.productDiscounts.get(productType);
+ mapProducts.set(userType, discount);
+ }
+
+ getDiscount(productType: ProductType, userType: UserType): number {
+ const userDiscount = this.userDiscounts.get(userType) ?? 0;
+ const productDiscount = this.productDiscounts.get(productType)?.get(userType) ?? 0;
+
+ return userDiscount + productDiscount;
+ }
+}
diff --git a/src/homeworks/ts1/accountService/accountServiceEnum.ts b/src/homeworks/ts1/accountService/accountServiceEnum.ts
new file mode 100644
index 000000000..c2180be0a
--- /dev/null
+++ b/src/homeworks/ts1/accountService/accountServiceEnum.ts
@@ -0,0 +1,12 @@
+export enum userDiscount {
+ Standard = 'Standard',
+ Premium = 'Premium',
+ Gold = 'Gold',
+ Free = 'Free',
+}
+
+export enum productDiscount {
+ Car = 'Car',
+ Toy = 'Toy',
+ Food = 'Food',
+}
diff --git a/src/app/index.css b/src/index.css
similarity index 100%
rename from src/app/index.css
rename to src/index.css
diff --git a/src/index.html b/src/index.html
index c8a8e9634..372160e9f 100644
--- a/src/index.html
+++ b/src/index.html
@@ -7,5 +7,6 @@
+