diff --git a/app/layout.tsx b/app/layout.tsx
index 18b2814..00fdd96 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,5 +1,4 @@
-import { ClientProviders } from '@/app/providers/ClientProviders';
-import { ServerProviders } from '@/app/providers/ServerProviders';
+import { Providers } from '@/app/providers/Providers';
import '@/app/styles/index.scss';
import { Notification } from '@/entities/Notification';
import { ScrollUp } from '@/features/ScrollUp';
@@ -28,20 +27,18 @@ export default function LocaleLayout({ children }: LocaleLayoutProps) {
}>
-
-
-
- {/* */}
- {children}
- }
- />
-
-
-
-
-
+
+
+ {/* */}
+ {children}
+ }
+ />
+
+
+
+
diff --git a/next.config.mjs b/next.config.mjs
index 55f2448..4f39b90 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -9,6 +9,9 @@ const nextConfig = {
IS_DEV: JSON.stringify(isDev),
API: process.env.API,
},
+ compiler: {
+ styledComponents: true,
+ },
webpack: (config, options) => {
config.module.rules.push(...buildLoaders(isDev));
config.plugins.push(...buildPlugins(config, isDev));
diff --git a/package-lock.json b/package-lock.json
index 1f3ff74..5c2e8ce 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"react-dom": "^18.2.0",
"react-redux": "^9.1.0",
"react-responsive": "^9.0.2",
+ "sharp": "^0.33.3",
"swiper": "^11.0.7"
},
"devDependencies": {
@@ -2143,6 +2144,15 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.1.1.tgz",
+ "integrity": "sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emotion/is-prop-valid": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
@@ -2386,6 +2396,437 @@
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true
},
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz",
+ "integrity": "sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.3.tgz",
+ "integrity": "sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz",
+ "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "macos": ">=11",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz",
+ "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "macos": ">=10.13",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz",
+ "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.28",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz",
+ "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz",
+ "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.28",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz",
+ "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz",
+ "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "musl": ">=1.2.2",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz",
+ "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "musl": ">=1.2.2",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.3.tgz",
+ "integrity": "sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.28",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.3.tgz",
+ "integrity": "sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.3.tgz",
+ "integrity": "sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.28",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.3.tgz",
+ "integrity": "sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "glibc": ">=2.26",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.3.tgz",
+ "integrity": "sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "musl": ">=1.2.2",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.3.tgz",
+ "integrity": "sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "musl": ">=1.2.2",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.2"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.3.tgz",
+ "integrity": "sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.1.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.3.tgz",
+ "integrity": "sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.3.tgz",
+ "integrity": "sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0",
+ "npm": ">=9.6.5",
+ "pnpm": ">=7.1.0",
+ "yarn": ">=3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@internationalized/date": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.2.tgz",
@@ -8961,6 +9402,14 @@
"webgl-constants": "^1.1.1"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -16010,6 +16459,75 @@
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
"dev": true
},
+ "node_modules/sharp": {
+ "version": "0.33.3",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.3.tgz",
+ "integrity": "sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.0"
+ },
+ "engines": {
+ "libvips": ">=8.15.2",
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.3",
+ "@img/sharp-darwin-x64": "0.33.3",
+ "@img/sharp-libvips-darwin-arm64": "1.0.2",
+ "@img/sharp-libvips-darwin-x64": "1.0.2",
+ "@img/sharp-libvips-linux-arm": "1.0.2",
+ "@img/sharp-libvips-linux-arm64": "1.0.2",
+ "@img/sharp-libvips-linux-s390x": "1.0.2",
+ "@img/sharp-libvips-linux-x64": "1.0.2",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.2",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.2",
+ "@img/sharp-linux-arm": "0.33.3",
+ "@img/sharp-linux-arm64": "0.33.3",
+ "@img/sharp-linux-s390x": "0.33.3",
+ "@img/sharp-linux-x64": "0.33.3",
+ "@img/sharp-linuxmusl-arm64": "0.33.3",
+ "@img/sharp-linuxmusl-x64": "0.33.3",
+ "@img/sharp-wasm32": "0.33.3",
+ "@img/sharp-win32-ia32": "0.33.3",
+ "@img/sharp-win32-x64": "0.33.3"
+ }
+ },
+ "node_modules/sharp/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp/node_modules/semver": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
diff --git a/package.json b/package.json
index 4efb02f..7e512fe 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"react-dom": "^18.2.0",
"react-redux": "^9.1.0",
"react-responsive": "^9.0.2",
+ "sharp": "^0.33.3",
"swiper": "^11.0.7"
},
"devDependencies": {
diff --git a/src/app/providers/ClientProviders.tsx b/src/app/providers/ClientProviders.tsx
deleted file mode 100644
index 2e4c4bb..0000000
--- a/src/app/providers/ClientProviders.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-'use client';
-
-import { Theme } from '@/shared/types/theme';
-import { NextUIProvider } from '@nextui-org/react';
-import { ThemeProvider } from 'next-themes';
-import { ReactNode } from 'react';
-import { StoreProvider } from './StoreProvider';
-
-export function ClientProviders({ children }: { children: ReactNode }) {
- return (
-
-
- {children}
-
-
- );
-}
diff --git a/src/app/providers/Providers.tsx b/src/app/providers/Providers.tsx
new file mode 100644
index 0000000..859d5fc
--- /dev/null
+++ b/src/app/providers/Providers.tsx
@@ -0,0 +1,20 @@
+'use client';
+
+import { Theme } from '@/shared/types/theme';
+import { NextUIProvider } from '@nextui-org/react';
+import { ThemeProvider } from 'next-themes';
+import { ReactNode } from 'react';
+import { StoreProvider } from './StoreProvider';
+import StyledComponentsRegistry from './StyledComponentsRegistry/StyledComponentsRegistry';
+
+export function Providers({ children }: { children: ReactNode }) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/src/app/providers/ServerProviders.tsx b/src/app/providers/ServerProviders.tsx
deleted file mode 100644
index eb8af5c..0000000
--- a/src/app/providers/ServerProviders.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { ReactNode } from 'react';
-
-export function ServerProviders({ children }: { children: ReactNode }) {
- return <>{children}>;
-}
diff --git a/src/app/providers/StoreProvider/config/RootState.ts b/src/app/providers/StoreProvider/config/RootState.ts
index 9c5fc30..aa64a2a 100644
--- a/src/app/providers/StoreProvider/config/RootState.ts
+++ b/src/app/providers/StoreProvider/config/RootState.ts
@@ -27,7 +27,7 @@ export type RootStateKey = keyof RootState;
export interface ReducerManager {
getReducerMap: () => ReducersMapObject;
- reduce: (state: RootState, action: UnknownAction) => RootState;
+ reduce: (state: any, action: UnknownAction) => RootState;
add: (key: RootStateKey, reducer: Reducer) => void;
remove: (key: RootStateKey) => void;
}
diff --git a/src/app/providers/StoreProvider/config/reducerManager.ts b/src/app/providers/StoreProvider/config/reducerManager.ts
index 97040ae..7aeceea 100644
--- a/src/app/providers/StoreProvider/config/reducerManager.ts
+++ b/src/app/providers/StoreProvider/config/reducerManager.ts
@@ -1,8 +1,4 @@
-import type {
- Reducer,
- ReducersMapObject,
- UnknownAction,
-} from '@reduxjs/toolkit';
+import type { ReducersMapObject } from '@reduxjs/toolkit';
import { combineReducers } from '@reduxjs/toolkit';
import { ReducerManager, RootState, RootStateKey } from './RootState';
@@ -15,7 +11,7 @@ export function createReducerManager(
return {
getReducerMap: () => reducers,
- reduce: (state: RootState, action: UnknownAction) => {
+ reduce: (state, action) => {
if (keysToRemove.length > 0) {
state = { ...state };
for (let key of keysToRemove) {
@@ -23,17 +19,16 @@ export function createReducerManager(
}
keysToRemove = [];
}
- // @ts-ignore fix
return combinedReducer(state, action);
},
- add: (key: RootStateKey, reducer: Reducer) => {
+ add: (key, reducer) => {
if (!key || reducers[key]) {
return;
}
reducers[key] = reducer;
combinedReducer = combineReducers(reducers);
},
- remove: (key: RootStateKey) => {
+ remove: (key) => {
if (!key || !reducers[key]) {
return;
}
diff --git a/src/app/providers/StoreProvider/config/store.ts b/src/app/providers/StoreProvider/config/store.ts
index ae40d06..61f5f27 100644
--- a/src/app/providers/StoreProvider/config/store.ts
+++ b/src/app/providers/StoreProvider/config/store.ts
@@ -1,10 +1,9 @@
import { userReducer } from '@/entities/User';
import { settingsReducer } from '@/features/Settings';
import { $api } from '@/shared/api/api';
-import type {
- ReducerFromReducersMapObject,
- ReducersMapObject,
-} from '@reduxjs/toolkit';
+import { setLocalstorage } from '@/shared/lib/features';
+import { LocalstorageKeys } from '@/shared/types/localstorage';
+import type { ReducersMapObject } from '@reduxjs/toolkit';
import { configureStore } from '@reduxjs/toolkit';
import { RootState, ThunkExtraArg } from './RootState';
import { createReducerManager } from './reducerManager';
@@ -25,15 +24,18 @@ export function createReduxStore(
api: $api,
};
- const store = configureStore({
- reducer: reducerManager.reduce as ReducerFromReducersMapObject,
+ const store = configureStore({
+ reducer: reducerManager.reduce,
devTools: JSON.parse(process.env.IS_DEV),
preloadedState: initialState,
- // @ts-ignore fix
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ thunk: { extraArgument } }),
});
+ store.subscribe(() => {
+ setLocalstorage(LocalstorageKeys.SETTINGS, store.getState().settings);
+ });
+
// @ts-ignore
store.reducerManager = reducerManager;
diff --git a/src/app/providers/StoreProvider/ui/StoreProvider.tsx b/src/app/providers/StoreProvider/ui/StoreProvider.tsx
index 92da30a..a06976b 100644
--- a/src/app/providers/StoreProvider/ui/StoreProvider.tsx
+++ b/src/app/providers/StoreProvider/ui/StoreProvider.tsx
@@ -1,36 +1,31 @@
import { RootState } from '@/app/providers/StoreProvider/config/RootState';
import { createReduxStore } from '@/app/providers/StoreProvider/config/store';
-import { setLocalstorage } from '@/shared/lib/features';
+import { SettingsState } from '@/features/Settings';
+import { getLocalstorage } from '@/shared/lib/features';
import { LocalstorageKeys } from '@/shared/types/localstorage';
import type { ReducersMapObject } from '@reduxjs/toolkit';
-import { FC, ReactNode, useEffect } from 'react';
+import { FC, ReactNode } from 'react';
import { Provider } from 'react-redux';
interface StoreProviderProps {
children?: ReactNode;
- initialState?: Partial;
- asyncReducers?: Partial>;
+ // initialState?: DeepPartial;
+ asyncReducers?: DeepPartial>;
}
export const StoreProvider: FC = ({
children,
- initialState,
+ // initialState,
asyncReducers,
}) => {
+ const initialState: DeepPartial = {
+ settings: getLocalstorage(LocalstorageKeys.SETTINGS),
+ };
+
const store = createReduxStore(
initialState as RootState,
asyncReducers as ReducersMapObject,
);
- useEffect(() => {
- const unsubscribe = store.subscribe(() => {
- setLocalstorage(LocalstorageKeys.SETTINGS, store.getState().settings);
- });
-
- return () => {
- unsubscribe();
- };
- }, [store]);
-
return {children};
};
diff --git a/src/app/providers/StyledComponentsRegistry/StyledComponentsRegistry.tsx b/src/app/providers/StyledComponentsRegistry/StyledComponentsRegistry.tsx
new file mode 100644
index 0000000..6a64696
--- /dev/null
+++ b/src/app/providers/StyledComponentsRegistry/StyledComponentsRegistry.tsx
@@ -0,0 +1,27 @@
+'use client';
+
+import { useServerInsertedHTML } from 'next/navigation';
+import React, { useState } from 'react';
+import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
+
+export default function StyledComponentsRegistry({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
+
+ useServerInsertedHTML(() => {
+ const styles = styledComponentsStyleSheet.getStyleElement();
+ styledComponentsStyleSheet.instance.clearTag();
+ return <>{styles}>;
+ });
+
+ if (typeof window !== 'undefined') return <>{children}>;
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/entities/User/model/selectors/getUserAuthData/getUserAuthData.test.ts b/src/entities/User/model/selectors/getUserAuthData/getUserAuthData.test.ts
index a81e580..620ff8d 100644
--- a/src/entities/User/model/selectors/getUserAuthData/getUserAuthData.test.ts
+++ b/src/entities/User/model/selectors/getUserAuthData/getUserAuthData.test.ts
@@ -16,12 +16,6 @@ describe('getUserAuthData.test', () => {
user: initialState,
};
- expect(getUserAuthData(state as RootState)).toEqual(initialState);
- });
-
- test('should work with empty state', () => {
- const state: Partial = {};
-
- expect(getUserAuthData(state as RootState)).toEqual(undefined);
+ expect(getUserAuthData(state as RootState)).toEqual(initialState.authData);
});
});
diff --git a/src/features/Auth/model/service/loginByUsername/loginByUsername.test.ts b/src/features/Auth/model/service/loginByUsername/loginByUsername.test.ts
index 9eae428..66d513e 100644
--- a/src/features/Auth/model/service/loginByUsername/loginByUsername.test.ts
+++ b/src/features/Auth/model/service/loginByUsername/loginByUsername.test.ts
@@ -1,11 +1,7 @@
import { User, userActions } from '@/entities/User';
import { TestAsyncThunk } from '@/shared/lib/tests';
-import axios from 'axios';
import { loginByUsername } from './loginByUsername';
-jest.mock('axios');
-const mockedAxios = jest.mocked(axios);
-
describe('loginByUsername.test', () => {
test('success login', async () => {
const userValue: User = {
@@ -14,9 +10,8 @@ describe('loginByUsername.test', () => {
email: 'email@email.com',
};
- mockedAxios.post.mockReturnValue(Promise.resolve({ data: userValue }));
-
const thunk = new TestAsyncThunk(loginByUsername);
+ thunk.api.post.mockReturnValue(Promise.resolve({ data: userValue }));
const result = await thunk.callThunk({
password: 'pass',
username: 'MarkMelior',
@@ -26,23 +21,22 @@ describe('loginByUsername.test', () => {
userActions.setAuthData(userValue),
);
expect(thunk.dispatch).toHaveBeenCalledTimes(3);
- expect(mockedAxios.post).toHaveBeenCalled();
+ expect(thunk.api.post).toHaveBeenCalled();
expect(result.meta.requestStatus).toBe('fulfilled');
expect(result.payload).toEqual(userValue);
});
test('error login', async () => {
- mockedAxios.post.mockReturnValue(Promise.resolve({ status: 403 }));
-
const thunk = new TestAsyncThunk(loginByUsername);
+ thunk.api.post.mockReturnValue(Promise.resolve({ status: 403 }));
const result = await thunk.callThunk({
password: 'pass',
username: 'MarkMelior',
});
expect(thunk.dispatch).toHaveBeenCalledTimes(2);
- expect(mockedAxios.post).toHaveBeenCalled();
+ expect(thunk.api.post).toHaveBeenCalled();
expect(result.meta.requestStatus).toBe('rejected');
- expect(result.payload).toBe('error');
+ expect(result.payload).toBe('Вы ввели неверную почту или пароль');
});
});
diff --git a/src/features/Search/model/selector/getQuery/getQuery.test.ts b/src/features/Search/model/selector/getQuery/getQuery.test.ts
index 12839d0..a91a866 100644
--- a/src/features/Search/model/selector/getQuery/getQuery.test.ts
+++ b/src/features/Search/model/selector/getQuery/getQuery.test.ts
@@ -13,7 +13,7 @@ describe('getQuery.test', () => {
search: initialState,
};
- expect(getQuery(state as RootState)).toEqual(initialState);
+ expect(getQuery(state as RootState)).toEqual(initialState.query);
});
test('should work with empty state', () => {
diff --git a/src/features/Settings/model/selector/getSettingsCurrency/getSettingsCurrency.test.ts b/src/features/Settings/model/selector/getSettingsCurrency/getSettingsCurrency.test.ts
index 8825abc..01227ff 100644
--- a/src/features/Settings/model/selector/getSettingsCurrency/getSettingsCurrency.test.ts
+++ b/src/features/Settings/model/selector/getSettingsCurrency/getSettingsCurrency.test.ts
@@ -14,10 +14,4 @@ describe('getSettingsCurrency.test', () => {
expect(getSettingsCurrency(state as RootState)).toEqual('RUB');
});
-
- test('should work with empty state', () => {
- const state: Partial = {};
-
- expect(getSettingsCurrency(state as RootState)).toEqual(undefined);
- });
});
diff --git a/src/features/Settings/model/selector/getSettingsOptimization/getSettingsOptimization.test.ts b/src/features/Settings/model/selector/getSettingsOptimization/getSettingsOptimization.test.ts
index d7e0660..21e750d 100644
--- a/src/features/Settings/model/selector/getSettingsOptimization/getSettingsOptimization.test.ts
+++ b/src/features/Settings/model/selector/getSettingsOptimization/getSettingsOptimization.test.ts
@@ -14,10 +14,4 @@ describe('getSettingsOptimization.test', () => {
expect(getSettingsOptimization(state as RootState)).toEqual(true);
});
-
- test('should work with empty state', () => {
- const state: Partial = {};
-
- expect(getSettingsOptimization(state as RootState)).toEqual(undefined);
- });
});
diff --git a/src/features/Settings/model/selector/getSettingsSpace/getSettingsSpace.test.ts b/src/features/Settings/model/selector/getSettingsSpace/getSettingsSpace.test.ts
index a098720..5a0e30a 100644
--- a/src/features/Settings/model/selector/getSettingsSpace/getSettingsSpace.test.ts
+++ b/src/features/Settings/model/selector/getSettingsSpace/getSettingsSpace.test.ts
@@ -14,10 +14,4 @@ describe('getSettingsSpace.test', () => {
expect(getSettingsSpace(state as RootState)).toEqual(false);
});
-
- test('should work with empty state', () => {
- const state: Partial = {};
-
- expect(getSettingsSpace(state as RootState)).toEqual(undefined);
- });
});
diff --git a/src/features/Settings/model/slice/settingsSlice.ts b/src/features/Settings/model/slice/settingsSlice.ts
index 5c983ab..c694390 100644
--- a/src/features/Settings/model/slice/settingsSlice.ts
+++ b/src/features/Settings/model/slice/settingsSlice.ts
@@ -1,19 +1,12 @@
-import { getLocalstorage } from '@/shared/lib/features';
import { Currency } from '@/shared/types/localization';
-import { LocalstorageKeys } from '@/shared/types/localstorage';
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { SettingsState } from '../..';
export const settingsInitialState: SettingsState = {
- space:
- getLocalstorage(LocalstorageKeys.SETTINGS)?.space ?? false,
- optimization:
- getLocalstorage(LocalstorageKeys.SETTINGS)?.optimization ??
- false,
- currency:
- getLocalstorage(LocalstorageKeys.SETTINGS)?.currency ??
- 'RUB',
+ space: false,
+ optimization: false,
+ currency: 'RUB',
};
export const settingsSlice = createSlice({
diff --git a/src/shared/api/api.ts b/src/shared/api/api.ts
index dda9111..584ce43 100644
--- a/src/shared/api/api.ts
+++ b/src/shared/api/api.ts
@@ -1,9 +1,10 @@
import axios from 'axios';
+import { getLocalstorage } from '../lib/features';
import { LocalstorageKeys } from '../types/localstorage';
export const $api = axios.create({
baseURL: process.env.API,
headers: {
- authorization: localStorage.getItem(LocalstorageKeys.USER) || '',
+ authorization: getLocalstorage(LocalstorageKeys.USER),
},
});
diff --git a/src/shared/lib/features/localstorage/getLocalstorage.ts b/src/shared/lib/features/localstorage/getLocalstorage.ts
index dbae515..6f81504 100644
--- a/src/shared/lib/features/localstorage/getLocalstorage.ts
+++ b/src/shared/lib/features/localstorage/getLocalstorage.ts
@@ -3,7 +3,7 @@ import { LocalstorageKeys } from '@/shared/types/localstorage';
export const getLocalstorage = (
key: LocalstorageKeys,
): T | undefined => {
- if (typeof window !== 'undefined') return undefined;
+ if (typeof window === 'undefined') return undefined;
try {
const storedSettings = localStorage.getItem(key);
diff --git a/src/shared/lib/features/localstorage/setLocalstorage.ts b/src/shared/lib/features/localstorage/setLocalstorage.ts
index 0895ca1..afd7b48 100644
--- a/src/shared/lib/features/localstorage/setLocalstorage.ts
+++ b/src/shared/lib/features/localstorage/setLocalstorage.ts
@@ -3,7 +3,7 @@ import { LocalstorageKeys } from '@/shared/types/localstorage';
export const setLocalstorage = (
key: LocalstorageKeys,
value: T,
-) => {
+): void => {
try {
if (typeof window !== 'undefined') {
localStorage.setItem(key, JSON.stringify(value));
diff --git a/src/shared/lib/tests/TestAsyncThunk/TestAsyncThunk.ts b/src/shared/lib/tests/TestAsyncThunk/TestAsyncThunk.ts
index d35fcf5..fcc0430 100644
--- a/src/shared/lib/tests/TestAsyncThunk/TestAsyncThunk.ts
+++ b/src/shared/lib/tests/TestAsyncThunk/TestAsyncThunk.ts
@@ -1,24 +1,35 @@
import { RootState } from '@/app/providers/StoreProvider';
import type { AsyncThunkAction } from '@reduxjs/toolkit';
+import type { AxiosStatic } from 'axios';
+import axios from 'axios';
type ActionCreatorType = (
arg: Arg,
) => AsyncThunkAction;
+jest.mock('axios');
+const mockedAxios = jest.mocked(axios);
+
export class TestAsyncThunk {
getState: () => RootState;
dispatch: jest.MockedFn;
actionCreator: ActionCreatorType;
+ api: jest.MockedFunctionDeep;
+
constructor(actionCreator: ActionCreatorType) {
this.actionCreator = actionCreator;
this.dispatch = jest.fn();
this.getState = jest.fn();
+
+ this.api = mockedAxios;
}
async callThunk(arg: Arg) {
const action = this.actionCreator(arg);
- const result = await action(this.dispatch, this.getState, undefined);
+ const result = await action(this.dispatch, this.getState, {
+ api: this.api,
+ });
return result;
}
diff --git a/src/shared/ui/Button/Button.test.tsx b/src/shared/ui/Button/Button.test.tsx
index e750414..897a973 100644
--- a/src/shared/ui/Button/Button.test.tsx
+++ b/src/shared/ui/Button/Button.test.tsx
@@ -1,6 +1,11 @@
import { render, screen } from '@testing-library/react';
import { default as Button } from './Button';
+jest.mock('react-redux', () => ({
+ useDispatch: jest.fn(),
+ useSelector: jest.fn(),
+}));
+
describe('Button', () => {
test('Test render', () => {
render();
diff --git a/src/shared/ui/SpaceCanvas/SpaceCanvas.tsx b/src/shared/ui/SpaceCanvas/SpaceCanvas.tsx
index d68de60..668fb42 100644
--- a/src/shared/ui/SpaceCanvas/SpaceCanvas.tsx
+++ b/src/shared/ui/SpaceCanvas/SpaceCanvas.tsx
@@ -17,7 +17,7 @@ import cls from './SpaceCanvas.module.scss';
const StarBackground = memo((props: any) => {
const ref: any = useRef();
const [sphere] = useState(() =>
- random.inSphere(new Float32Array(5000), { radius: 1.2 }),
+ random.inSphere(new Float32Array(5001), { radius: 1.2 }),
);
useFrame((_, delta) => {
@@ -26,7 +26,7 @@ const StarBackground = memo((props: any) => {
});
return (
- // eslint-disable-next-line react/no-unknown-property
+ // eslint-disable-next-line
= memo(({ params }) => {
dispatch(fetchProfileData());
}, [dispatch]);
+ if (isLoading) {
+ return Загрузка идёт!
;
+ }
+
+ if (error) {
+ return Ошибка: {error}
;
+ }
+
return (