From d74789a0d8ceacdd5e45e9080e7d31539f33b1ce Mon Sep 17 00:00:00 2001 From: itoshi Date: Fri, 6 Jun 2025 16:08:15 +0300 Subject: [PATCH] feat: Add more pages --- package-lock.json | 308 +++++++---- package.json | 2 + src/App.tsx | 1 + src/app/index.tsx | 1 - src/app/router/index.tsx | 77 ++- src/main.tsx | 3 +- src/pages/Article/ArticleListPage/index.tsx | 86 +++ src/pages/Article/index.ts | 1 + src/pages/Carrier/CarrierCreatePage/index.tsx | 202 +++++++ src/pages/Carrier/CarrierListPage/index.tsx | 101 ++++ .../Carrier/CarrierPreviewPage/index.tsx | 120 ++++ src/pages/Carrier/index.ts | 3 + src/pages/City/CityCreatePage/index.tsx | 166 ++++++ src/pages/City/CityListPage/index.tsx | 96 ++++ src/pages/City/CityPreviewPage/index.tsx | 76 +++ src/pages/City/index.ts | 3 + src/pages/Country/CountryCreatePage/index.tsx | 75 +++ src/pages/Country/CountryListPage/index.tsx | 86 +++ .../Country/CountryPreviewPage/index.tsx | 58 ++ src/pages/Country/index.ts | 3 + src/pages/CreateMediaPage/index.tsx | 126 ----- src/pages/Media/MediaCreatePage/index.tsx | 89 +++ .../MediaEditPage}/index.tsx | 2 +- src/pages/Media/MediaListPage/index.tsx | 110 ++++ .../MediaPreviewPage}/index.tsx | 4 +- src/pages/Media/index.ts | 3 + src/pages/MediaListPage/index.tsx | 88 --- src/pages/Route/RouteCreatePage/index.tsx | 86 +++ src/pages/Route/RouteListPage/index.tsx | 115 ++++ src/pages/Route/index.ts | 1 + src/pages/Sight/SightListPage/index.tsx | 96 ++++ src/pages/Sight/index.ts | 1 + .../Snapshot/SnapshotCreatePage/index.tsx | 69 +++ src/pages/Snapshot/SnapshotListPage/index.tsx | 127 +++++ .../Snapshot/SnapshotPreviewPage/index.tsx | 58 ++ src/pages/Snapshot/index.ts | 3 + src/pages/Station/StationCreatePage/index.tsx | 94 ++++ src/pages/Station/StationListPage/index.tsx | 117 ++++ src/pages/Station/index.ts | 1 + src/pages/User/UserListPage/index.tsx | 112 ++++ src/pages/User/UserPreviewPage/index.tsx | 74 +++ src/pages/User/index.ts | 2 + src/pages/Vehicle/VehicleCreatePage/index.tsx | 117 ++++ src/pages/Vehicle/VehicleListPage/index.tsx | 133 +++++ .../Vehicle/VehiclePreviewPage/index.tsx | 70 +++ src/pages/Vehicle/index.ts | 3 + src/pages/index.ts | 14 +- src/shared/config/constants.tsx | 76 ++- src/shared/store/ArticlesStore/index.tsx | 9 + src/shared/store/CarrierStore/index.tsx | 76 +++ src/shared/store/CityStore/index.tsx | 40 +- src/shared/store/CountryStore/index.ts | 49 ++ src/shared/store/MediaStore/index.tsx | 10 + src/shared/store/RouteStore/index.ts | 45 ++ src/shared/store/SightsStore/index.tsx | 5 + src/shared/store/SnapshotStore/index.ts | 36 +- src/shared/store/StationsStore/index.ts | 76 +++ src/shared/store/UserStore/index.ts | 44 ++ src/shared/store/VehicleStore/index.ts | 32 +- src/shared/store/index.ts | 5 + src/widgets/CreateButton/index.tsx | 25 + src/widgets/LanguageSwitcher/index.tsx | 3 +- src/widgets/MediaViewer/index.tsx | 11 +- src/widgets/SnapshotRestore/index.tsx | 34 ++ src/widgets/index.ts | 2 + tsconfig.tsbuildinfo | 2 +- yarn.lock | 515 ++++-------------- 67 files changed, 3491 insertions(+), 787 deletions(-) create mode 100644 src/App.tsx create mode 100644 src/pages/Article/ArticleListPage/index.tsx create mode 100644 src/pages/Article/index.ts create mode 100644 src/pages/Carrier/CarrierCreatePage/index.tsx create mode 100644 src/pages/Carrier/CarrierListPage/index.tsx create mode 100644 src/pages/Carrier/CarrierPreviewPage/index.tsx create mode 100644 src/pages/Carrier/index.ts create mode 100644 src/pages/City/CityCreatePage/index.tsx create mode 100644 src/pages/City/CityListPage/index.tsx create mode 100644 src/pages/City/CityPreviewPage/index.tsx create mode 100644 src/pages/City/index.ts create mode 100644 src/pages/Country/CountryCreatePage/index.tsx create mode 100644 src/pages/Country/CountryListPage/index.tsx create mode 100644 src/pages/Country/CountryPreviewPage/index.tsx create mode 100644 src/pages/Country/index.ts delete mode 100644 src/pages/CreateMediaPage/index.tsx create mode 100644 src/pages/Media/MediaCreatePage/index.tsx rename src/pages/{EditMediaPage => Media/MediaEditPage}/index.tsx (99%) create mode 100644 src/pages/Media/MediaListPage/index.tsx rename src/pages/{PreviewMediaPage => Media/MediaPreviewPage}/index.tsx (92%) create mode 100644 src/pages/Media/index.ts delete mode 100644 src/pages/MediaListPage/index.tsx create mode 100644 src/pages/Route/RouteCreatePage/index.tsx create mode 100644 src/pages/Route/RouteListPage/index.tsx create mode 100644 src/pages/Route/index.ts create mode 100644 src/pages/Sight/SightListPage/index.tsx create mode 100644 src/pages/Sight/index.ts create mode 100644 src/pages/Snapshot/SnapshotCreatePage/index.tsx create mode 100644 src/pages/Snapshot/SnapshotListPage/index.tsx create mode 100644 src/pages/Snapshot/SnapshotPreviewPage/index.tsx create mode 100644 src/pages/Snapshot/index.ts create mode 100644 src/pages/Station/StationCreatePage/index.tsx create mode 100644 src/pages/Station/StationListPage/index.tsx create mode 100644 src/pages/Station/index.ts create mode 100644 src/pages/User/UserListPage/index.tsx create mode 100644 src/pages/User/UserPreviewPage/index.tsx create mode 100644 src/pages/User/index.ts create mode 100644 src/pages/Vehicle/VehicleCreatePage/index.tsx create mode 100644 src/pages/Vehicle/VehicleListPage/index.tsx create mode 100644 src/pages/Vehicle/VehiclePreviewPage/index.tsx create mode 100644 src/pages/Vehicle/index.ts create mode 100644 src/shared/store/CarrierStore/index.tsx create mode 100644 src/shared/store/CountryStore/index.ts create mode 100644 src/shared/store/RouteStore/index.ts create mode 100644 src/shared/store/StationsStore/index.ts create mode 100644 src/shared/store/UserStore/index.ts create mode 100644 src/widgets/CreateButton/index.tsx create mode 100644 src/widgets/SnapshotRestore/index.tsx diff --git a/package-lock.json b/package-lock.json index c915d81..61d62be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", + "@hello-pangea/dnd": "^18.0.1", "@mui/material": "^7.1.0", + "@mui/x-data-grid": "^8.5.1", "@photo-sphere-viewer/core": "^5.13.2", "@react-three/drei": "^10.1.2", "@react-three/fiber": "^9.1.2", @@ -23,11 +25,12 @@ "ol": "^10.5.0", "path": "^0.12.7", "react": "^19.1.0", + "react-colorful": "^5.6.1", "react-dom": "^19.1.0", "react-dropzone": "^14.3.8", "react-markdown": "^10.1.0", "react-photo-sphere-viewer": "^6.2.3", - "react-router-dom": "^5.3.0", + "react-router-dom": "^7.6.1", "react-simplemde-editor": "^5.2.0", "react-toastify": "^11.0.5", "rehype-raw": "^7.0.0", @@ -40,7 +43,6 @@ "@types/node": "^22.15.24", "@types/react": "^19.1.2", "@types/react-dom": "^19.1.2", - "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.4.1", "eslint": "^9.25.0", "eslint-plugin-react-hooks": "^5.2.0", @@ -290,9 +292,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz", - "integrity": "sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -674,6 +676,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@hello-pangea/dnd": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz", + "integrity": "sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.26.7", + "css-box-model": "^1.2.1", + "raf-schd": "^4.0.3", + "react-redux": "^9.2.0", + "redux": "^5.0.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -985,9 +1004,9 @@ } }, "node_modules/@mui/types": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz", - "integrity": "sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.3.tgz", + "integrity": "sha512-2UCEiK29vtiZTeLdS2d4GndBKacVyxGvReznGXGr+CzW/YhjIX+OHUdCIczZjzcRAgKBGmE9zCIgoV9FleuyRQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1" @@ -1002,13 +1021,13 @@ } }, "node_modules/@mui/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-BkOt2q7MBYl7pweY2JWwfrlahhp+uGLR8S+EhiyRaofeRYUWL2YKbSGQvN4hgSN1i8poN0PaUiii1kEMrchvzg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.1", - "@mui/types": "^7.4.2", + "@mui/types": "^7.4.3", "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -1037,6 +1056,65 @@ "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "license": "MIT" }, + "node_modules/@mui/x-data-grid": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.5.1.tgz", + "integrity": "sha512-Ukodx8cOc/GR4+2zr4DRNBJJOlyeJNaxK4hggWv7VchDL7Jf70dLZO7oLXPhEFG05Yna81RatL/UFsRYIdWI1Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.4", + "@mui/utils": "^7.1.1", + "@mui/x-internals": "8.5.1", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.5.1.tgz", + "integrity": "sha512-7rAWK7SB6FxEIXKgsHsJjIzeeKOLxFJ16gePgZVWlvyew+xDb4P0fgjwW3ThcJjgvkUm0UhGGfLh/JP8l514IA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.4", + "@mui/utils": "^7.1.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1410,13 +1488,6 @@ "@types/unist": "*" } }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1507,29 +1578,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", @@ -1575,6 +1623,12 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@types/webxr": { "version": "0.5.22", "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz", @@ -2337,6 +2391,15 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -2394,6 +2457,15 @@ "node": ">= 8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "license": "MIT", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3432,20 +3504,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, "node_modules/hls.js": { "version": "1.6.5", "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.5.tgz", @@ -3671,12 +3729,6 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "license": "MIT" }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4973,15 +5025,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/path-to-regexp": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", - "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", - "license": "MIT", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5180,6 +5223,12 @@ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", "license": "ISC" }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", + "license": "MIT" + }, "node_modules/rbush": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz", @@ -5198,6 +5247,16 @@ "node": ">=0.10.0" } }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-dom": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", @@ -5300,6 +5359,29 @@ "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", "license": "MIT" }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -5311,41 +5393,41 @@ } }, "node_modules/react-router": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", - "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.2.tgz", + "integrity": "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/react-router-dom": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", - "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.2.tgz", + "integrity": "sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.3.4", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "react-router": "7.6.2" + }, + "engines": { + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=18", + "react-dom": ">=18" } }, "node_modules/react-simplemde-editor": { @@ -5406,6 +5488,12 @@ } } }, + "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==", + "license": "MIT" + }, "node_modules/rehype-raw": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", @@ -5463,6 +5551,12 @@ "node": ">=0.10.0" } }, + "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==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -5492,12 +5586,6 @@ "node": ">=4" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", - "license": "MIT" - }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", @@ -5597,6 +5685,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5833,12 +5927,6 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -6199,12 +6287,6 @@ "node": ">= 4" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", - "license": "MIT" - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", diff --git a/package.json b/package.json index 41f79bb..475763a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@emotion/styled": "^11.14.0", "@hello-pangea/dnd": "^18.0.1", "@mui/material": "^7.1.0", + "@mui/x-data-grid": "^8.5.1", "@photo-sphere-viewer/core": "^5.13.2", "@react-three/drei": "^10.1.2", "@react-three/fiber": "^9.1.2", @@ -26,6 +27,7 @@ "ol": "^10.5.0", "path": "^0.12.7", "react": "^19.1.0", + "react-colorful": "^5.6.1", "react-dom": "^19.1.0", "react-dropzone": "^14.3.8", "react-markdown": "^10.1.0", diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1 @@ + diff --git a/src/app/index.tsx b/src/app/index.tsx index 1b28884..5c274f7 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -8,7 +8,6 @@ import { ToastContainer } from "react-toastify"; export const App: React.FC = () => ( - ); diff --git a/src/app/router/index.tsx b/src/app/router/index.tsx index deaeae8..522c6d2 100644 --- a/src/app/router/index.tsx +++ b/src/app/router/index.tsx @@ -4,11 +4,31 @@ import { EditSightPage, LoginPage, MainPage, - SightPage, + SightListPage, MapPage, MediaListPage, - PreviewMediaPage, - EditMediaPage, + MediaPreviewPage, + MediaEditPage, + CountryListPage, + CityListPage, + RouteListPage, + UserListPage, + SnapshotListPage, + CarrierListPage, + StationListPage, + VehicleListPage, + ArticleListPage, + CityPreviewPage, + UserPreviewPage, + CountryPreviewPage, + SnapshotPreviewPage, + VehiclePreviewPage, + CarrierPreviewPage, + SnapshotCreatePage, + CountryCreatePage, + CityCreatePage, + // CarrierCreatePage, + VehicleCreatePage, } from "@pages"; import { authStore, createSightStore, editSightStore } from "@shared"; import { Layout } from "@widgets"; @@ -82,14 +102,59 @@ const router = createBrowserRouter([ ), children: [ { index: true, element: }, - { path: "sight", element: }, + + // Sight + { path: "sight", element: }, { path: "sight/create", element: }, { path: "sight/:id", element: }, + + // Device { path: "devices", element: }, + + // Map { path: "map", element: }, + + // Media { path: "media", element: }, - { path: "media/:id", element: }, - { path: "media/:id/edit", element: }, + { path: "media/:id", element: }, + { path: "media/:id/edit", element: }, + + // Country + { path: "country", element: }, + { path: "country/create", element: }, + { path: "country/:id", element: }, + // City + { path: "city", element: }, + { path: "city/create", element: }, + { path: "city/:id", element: }, + // Route + { path: "route", element: }, + + // User + { path: "user", element: }, + { path: "user/:id", element: }, + + // Snapshot + { path: "snapshot", element: }, + { path: "snapshot/create", element: }, + { path: "snapshot/:id", element: }, + + // Carrier + { path: "carrier", element: }, + // { path: "carrier/create", element: }, + { path: "carrier/:id", element: }, + + // Station + { path: "station", element: }, + + // Vehicle + { path: "vehicle", element: }, + { path: "vehicle/create", element: }, + { path: "vehicle/:id", element: }, + + // Article + { path: "article", element: }, + // { path: "media/create", element: }, ], }, diff --git a/src/main.tsx b/src/main.tsx index 4444990..f5b53db 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,6 +1,7 @@ import { createRoot } from "react-dom/client"; -import { App } from "./app"; + import "./index.css"; +import { App } from "./app/index"; const container = document.getElementById("root"); const root = createRoot(container!); diff --git a/src/pages/Article/ArticleListPage/index.tsx b/src/pages/Article/ArticleListPage/index.tsx new file mode 100644 index 0000000..da2b071 --- /dev/null +++ b/src/pages/Article/ArticleListPage/index.tsx @@ -0,0 +1,86 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { articlesStore, languageStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Trash2, FileText } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { DeleteModal, LanguageSwitcher } from "@widgets"; + +export const ArticleListPage = observer(() => { + const { articleList, getArticleList } = articlesStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getArticleList(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "heading", + headerName: "Название", + flex: 1, + }, + + { + field: "actions", + headerName: "Действия", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = articleList.map((article) => ({ + id: article.id, + heading: article.heading, + body: article.body, + })); + + return ( + <> + + +
+ +
+ + { + if (rowId) { + getArticleList(); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Article/index.ts b/src/pages/Article/index.ts new file mode 100644 index 0000000..b9a8432 --- /dev/null +++ b/src/pages/Article/index.ts @@ -0,0 +1 @@ +export * from "./ArticleListPage"; diff --git a/src/pages/Carrier/CarrierCreatePage/index.tsx b/src/pages/Carrier/CarrierCreatePage/index.tsx new file mode 100644 index 0000000..c9226e7 --- /dev/null +++ b/src/pages/Carrier/CarrierCreatePage/index.tsx @@ -0,0 +1,202 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, + Box, +} from "@mui/material"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Save } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import { carrierStore, cityStore, mediaStore } from "@shared"; +import { useState, useEffect } from "react"; +import { LanguageSwitcher, MediaViewer } from "@widgets"; +import { HexColorPicker } from "react-colorful"; + +export const CarrierCreatePage = observer(() => { + const navigate = useNavigate(); + const [fullName, setFullName] = useState(""); + const [shortName, setShortName] = useState(""); + const [cityId, setCityId] = useState(null); + const [primaryColor, setPrimaryColor] = useState("#000000"); + const [secondaryColor, setSecondaryColor] = useState("#ffffff"); + const [accentColor, setAccentColor] = useState("#ff0000"); + const [slogan, setSlogan] = useState(""); + const [selectedMediaId, setSelectedMediaId] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + cityStore.getCities(); + mediaStore.getMedia(); + }, []); + + const handleCreate = async () => { + try { + setIsLoading(true); + await carrierStore.createCarrier( + fullName, + shortName, + cityStore.cities.find((c) => c.id === cityId)?.name!, + cityId!, + primaryColor, + secondaryColor, + accentColor, + slogan, + selectedMediaId! + ); + toast.success("Перевозчик успешно создан"); + navigate("/carrier"); + } catch (error) { + toast.error("Ошибка при создании перевозчика"); + } finally { + setIsLoading(false); + } + }; + + return ( + + +
+ +
+ +
+ + Город + + + + setFullName(e.target.value)} + /> + + setShortName(e.target.value)} + /> + +
+
+ Основной цвет: + + +
+ +
+ Вторичный цвет: + + +
+ +
+ Акцентный цвет: + + +
+
+ + setSlogan(e.target.value)} + /> + +
+ + Логотип + + + {selectedMediaId && ( +
+ +
+ )} +
+ + +
+
+ ); +}); diff --git a/src/pages/Carrier/CarrierListPage/index.tsx b/src/pages/Carrier/CarrierListPage/index.tsx new file mode 100644 index 0000000..0a42800 --- /dev/null +++ b/src/pages/Carrier/CarrierListPage/index.tsx @@ -0,0 +1,101 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { carrierStore, languageStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { DeleteModal, LanguageSwitcher } from "@widgets"; + +export const CarrierListPage = observer(() => { + const { carriers, getCarriers, deleteCarrier } = carrierStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getCarriers(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "full_name", + headerName: "Полное имя", + + width: 300, + }, + { + field: "short_name", + headerName: "Короткое имя", + width: 200, + }, + { + field: "city", + headerName: "Город", + flex: 1, + }, + { + field: "actions", + headerName: "Действия", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = carriers.map((carrier) => ({ + id: carrier.id, + full_name: carrier.full_name, + short_name: carrier.short_name, + city: carrier.city, + })); + + return ( + <> + + +
+
+

Перевозчики

+ {/* */} +
+ +
+ + { + if (rowId) { + deleteCarrier(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Carrier/CarrierPreviewPage/index.tsx b/src/pages/Carrier/CarrierPreviewPage/index.tsx new file mode 100644 index 0000000..60c3028 --- /dev/null +++ b/src/pages/Carrier/CarrierPreviewPage/index.tsx @@ -0,0 +1,120 @@ +import { Paper } from "@mui/material"; +import { carrierStore, mediaStore } from "@shared"; +import { MediaViewer } from "@widgets"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const CarrierPreviewPage = observer(() => { + const { id } = useParams(); + const { getCarrier, carrier } = carrierStore; + const { oneMedia, getOneMedia } = mediaStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + const carrierResponse = await getCarrier(Number(id)); + await getOneMedia(carrierResponse?.logo as string); + })(); + }, [id]); + + return ( + + {carrier && ( + <> +
+ + {/*
+ + +
*/} +
+
+
+

Полное имя

+

{carrier?.full_name}

+
+ +
+

Полное имя

+

{carrier?.full_name}

+
+
+

Город

+

{carrier?.city}

+
+
+

Основной цвет

+
+ {carrier?.main_color} +
+
+
+

Цвет левого виджета

+
+ {carrier?.left_color} +
+
+
+

Цвет правого виджета

+
+ {carrier?.right_color} +
+
+
+

Краткое имя

+

{carrier?.short_name}

+
+
+

Логотип

+ + +
+
+ + )} +
+ ); +}); diff --git a/src/pages/Carrier/index.ts b/src/pages/Carrier/index.ts new file mode 100644 index 0000000..b660935 --- /dev/null +++ b/src/pages/Carrier/index.ts @@ -0,0 +1,3 @@ +export * from "./CarrierListPage"; +export * from "./CarrierPreviewPage"; +export * from "./CarrierCreatePage"; diff --git a/src/pages/City/CityCreatePage/index.tsx b/src/pages/City/CityCreatePage/index.tsx new file mode 100644 index 0000000..3da5d56 --- /dev/null +++ b/src/pages/City/CityCreatePage/index.tsx @@ -0,0 +1,166 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, + Box, +} from "@mui/material"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Save, ImagePlus } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import { cityStore, countryStore, mediaStore } from "@shared"; +import { useState, useEffect } from "react"; +import { LanguageSwitcher, MediaViewer } from "@widgets"; +import { SelectMediaDialog } from "@shared"; + +export const CityCreatePage = observer(() => { + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [countryCode, setCountryCode] = useState(""); + const [selectedMediaId, setSelectedMediaId] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isSelectMediaOpen, setIsSelectMediaOpen] = useState(false); + + useEffect(() => { + countryStore.getCountries(); + mediaStore.getMedia(); + }, []); + + const handleCreate = async () => { + try { + setIsLoading(true); + await cityStore.createCity( + name, + countryStore.countries.find((c) => c.code === countryCode)?.name!, + countryCode, + selectedMediaId! + ); + toast.success("Город успешно создан"); + navigate("/city"); + } catch (error) { + toast.error("Ошибка при создании города"); + } finally { + setIsLoading(false); + } + }; + + const handleMediaSelect = (media: { + id: string; + filename: string; + media_name?: string; + media_type: number; + }) => { + setSelectedMediaId(media.id); + }; + + const selectedMedia = selectedMediaId + ? mediaStore.media.find((m) => m.id === selectedMediaId) + : null; + + return ( + + +
+ +
+ +
+ setName(e.target.value)} + /> + + + Страна + + + +
+ +
+ + {selectedMedia && ( + + {selectedMedia.media_name || selectedMedia.filename} + + )} +
+ {selectedMedia && ( + + + + )} +
+ + +
+ + setIsSelectMediaOpen(false)} + onSelectMedia={handleMediaSelect} + mediaType={3} // Тип медиа для иконок + /> +
+ ); +}); diff --git a/src/pages/City/CityListPage/index.tsx b/src/pages/City/CityListPage/index.tsx new file mode 100644 index 0000000..f321e19 --- /dev/null +++ b/src/pages/City/CityListPage/index.tsx @@ -0,0 +1,96 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { cityStore, languageStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; + +export const CityListPage = observer(() => { + const { cities, getCities, deleteCity } = cityStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); + const { language } = languageStore; + + useEffect(() => { + getCities(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "country", + headerName: "Страна", + width: 150, + }, + { + field: "name", + headerName: "Название", + flex: 1, + }, + { + field: "actions", + headerName: "Действия", + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = cities.map((city) => ({ + id: city.id, + name: city.name, + country: city.country, + })); + + return ( + <> + + +
+
+

Города

+ +
+ +
+ + { + if (rowId) { + deleteCity(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/City/CityPreviewPage/index.tsx b/src/pages/City/CityPreviewPage/index.tsx new file mode 100644 index 0000000..517de5c --- /dev/null +++ b/src/pages/City/CityPreviewPage/index.tsx @@ -0,0 +1,76 @@ +import { Paper } from "@mui/material"; +import { cityStore, mediaStore } from "@shared"; +import { MediaViewer } from "@widgets"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const CityPreviewPage = observer(() => { + const { id } = useParams(); + const { getCity, city } = cityStore; + const { oneMedia, getOneMedia } = mediaStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + const cityResponse = await getCity(id as string); + await getOneMedia(cityResponse.arms as string); + })(); + }, [id]); + + return ( + +
+ + {/*
+ + +
*/} +
+
+
+

Название

+

{city?.name}

+
+ +
+

Страна

+

{city?.country}

+
+
+

Герб

+
+ +
+
+
+
+ ); +}); diff --git a/src/pages/City/index.ts b/src/pages/City/index.ts new file mode 100644 index 0000000..e22a2e5 --- /dev/null +++ b/src/pages/City/index.ts @@ -0,0 +1,3 @@ +export * from "./CityListPage"; +export * from "./CityPreviewPage"; +export * from "./CityCreatePage"; diff --git a/src/pages/Country/CountryCreatePage/index.tsx b/src/pages/Country/CountryCreatePage/index.tsx new file mode 100644 index 0000000..ac14ed1 --- /dev/null +++ b/src/pages/Country/CountryCreatePage/index.tsx @@ -0,0 +1,75 @@ +import { Button, Paper, TextField } from "@mui/material"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Save } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import { countryStore } from "@shared"; +import { useState } from "react"; +import { LanguageSwitcher } from "@widgets"; + +export const CountryCreatePage = observer(() => { + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [code, setCode] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const handleCreate = async () => { + try { + setIsLoading(true); + await countryStore.createCountry(code, name); + toast.success("Страна успешно создана"); + navigate("/country"); + } catch (error) { + toast.error("Ошибка при создании страны"); + } finally { + setIsLoading(false); + } + }; + + return ( + + +
+ +
+ +
+ setCode(e.target.value)} + /> + setName(e.target.value)} + /> + + +
+
+ ); +}); diff --git a/src/pages/Country/CountryListPage/index.tsx b/src/pages/Country/CountryListPage/index.tsx new file mode 100644 index 0000000..a25a718 --- /dev/null +++ b/src/pages/Country/CountryListPage/index.tsx @@ -0,0 +1,86 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { countryStore, languageStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; + +export const CountryListPage = observer(() => { + const { countries, getCountries } = countryStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getCountries(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "name", + headerName: "Название", + flex: 1, + }, + { + field: "actions", + headerName: "Действия", + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = countries.map((country) => ({ + id: country.code, + code: country.code, + name: country.name, + })); + + return ( + <> + + +
+
+

Страны

+ +
+ +
+ { + if (rowId) { + await countryStore.deleteCountry(rowId); + getCountries(); // Refresh the list after deletion + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Country/CountryPreviewPage/index.tsx b/src/pages/Country/CountryPreviewPage/index.tsx new file mode 100644 index 0000000..accea7f --- /dev/null +++ b/src/pages/Country/CountryPreviewPage/index.tsx @@ -0,0 +1,58 @@ +import { Paper } from "@mui/material"; +import { countryStore } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const CountryPreviewPage = observer(() => { + const { id } = useParams(); + const { getCountry, country } = countryStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + await getCountry(id as string); + })(); + }, [id]); + + return ( + +
+ + {/*
+ + +
*/} +
+ {country && ( +
+
+

Название

+

{country?.name}

+
+
+ )} +
+ ); +}); diff --git a/src/pages/Country/index.ts b/src/pages/Country/index.ts new file mode 100644 index 0000000..81a4c27 --- /dev/null +++ b/src/pages/Country/index.ts @@ -0,0 +1,3 @@ +export * from "./CountryListPage"; +export * from "./CountryPreviewPage"; +export * from "./CountryCreatePage"; diff --git a/src/pages/CreateMediaPage/index.tsx b/src/pages/CreateMediaPage/index.tsx deleted file mode 100644 index 31d3590..0000000 --- a/src/pages/CreateMediaPage/index.tsx +++ /dev/null @@ -1,126 +0,0 @@ -// import { Button, Paper, Typography, Box, Alert, Snackbar } from "@mui/material"; -// import { useNavigate } from "react-router-dom"; -// import { ArrowLeft, Upload } from "lucide-react"; -// import { observer } from "mobx-react-lite"; -// import { useState, DragEvent, useRef, useEffect } from "react"; -// import { editSightStore, UploadMediaDialog } from "@shared"; - -// export const CreateMediaPage = observer(() => { -// const navigate = useNavigate(); -// const [isDragging, setIsDragging] = useState(false); - -// const [error, setError] = useState(null); -// const [success, setSuccess] = useState(false); -// const fileInputRef = useRef(null); -// const [uploadDialogOpen, setUploadDialogOpen] = useState(false); - -// const handleDrop = (e: DragEvent) => { -// e.preventDefault(); -// e.stopPropagation(); -// setIsDragging(false); - -// const files = Array.from(e.dataTransfer.files); -// if (files.length > 0) { -// editSightStore.fileToUpload = files[0]; -// setUploadDialogOpen(true); -// } -// }; - -// const handleDragOver = (e: DragEvent) => { -// e.preventDefault(); -// setIsDragging(true); -// }; - -// const handleDragLeave = () => { -// setIsDragging(false); -// }; - -// const handleFileSelect = (e: React.ChangeEvent) => { -// const files = e.target.files; -// if (files && files.length > 0) { -// editSightStore.fileToUpload = files[0]; -// setUploadDialogOpen(true); -// } -// }; - -// const handleUploadSuccess = () => { -// setSuccess(true); -// setUploadDialogOpen(false); -// }; - -// return ( -//
-//
-// -// Загрузка медиафайла -//
- -// -// - -// -// -// -// Перетащите файл сюда или -// -// -// -// Поддерживаемые форматы: JPG, PNG, GIF, MP4, WebM, GLB, GLTF -// -// -// - -// setUploadDialogOpen(false)} -// afterUpload={handleUploadSuccess} -// /> - -// setSuccess(false)} -// > -// setSuccess(false)}> -// Медиафайл успешно загружен -// -// - -// setError(null)} -// > -// setError(null)}> -// {error} -// -// -//
-// ); -// }); diff --git a/src/pages/Media/MediaCreatePage/index.tsx b/src/pages/Media/MediaCreatePage/index.tsx new file mode 100644 index 0000000..c283a4a --- /dev/null +++ b/src/pages/Media/MediaCreatePage/index.tsx @@ -0,0 +1,89 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, +} from "@mui/material"; +import { mediaStore, MEDIA_TYPE_LABELS } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Loader2, Save } from "lucide-react"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; + +export const MediaCreatePage = observer(() => { + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [type, setType] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const handleCreate = async () => { + try { + setIsLoading(true); + await mediaStore.createMedia(name, type); + toast.success("Медиа успешно создано"); + navigate("/media"); + } catch (error) { + toast.error("Ошибка при создании медиа"); + } finally { + setIsLoading(false); + } + }; + + return ( + +
+ +
+

Создание медиа

+
+ setName(e.target.value)} + /> + + Тип + + + + +
+
+ ); +}); diff --git a/src/pages/EditMediaPage/index.tsx b/src/pages/Media/MediaEditPage/index.tsx similarity index 99% rename from src/pages/EditMediaPage/index.tsx rename to src/pages/Media/MediaEditPage/index.tsx index 56507a9..1633a24 100644 --- a/src/pages/EditMediaPage/index.tsx +++ b/src/pages/Media/MediaEditPage/index.tsx @@ -19,7 +19,7 @@ import { Save, ArrowLeft } from "lucide-react"; import { authInstance, mediaStore, MEDIA_TYPE_LABELS } from "@shared"; import { MediaViewer } from "@widgets"; -export const EditMediaPage = observer(() => { +export const MediaEditPage = observer(() => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [isLoading, setIsLoading] = useState(false); diff --git a/src/pages/Media/MediaListPage/index.tsx b/src/pages/Media/MediaListPage/index.tsx new file mode 100644 index 0000000..53a4137 --- /dev/null +++ b/src/pages/Media/MediaListPage/index.tsx @@ -0,0 +1,110 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, MEDIA_TYPE_LABELS, mediaStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; + +export const MediaListPage = observer(() => { + const { media, getMedia, deleteMedia } = mediaStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getMedia(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "media_name", + headerName: "Название", + flex: 1, + }, + { + field: "media_type", + headerName: "Тип", + width: 200, + flex: 1, + renderCell: (params: GridRenderCellParams) => { + return ( +

+ { + MEDIA_TYPE_LABELS[ + params.row.media_type as keyof typeof MEDIA_TYPE_LABELS + ] + } +

+ ); + }, + }, + { + field: "actions", + headerName: "Действия", + flex: 1, + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = media.map((media) => ({ + id: media.id, + media_name: media.media_name, + media_type: media.media_type, + })); + + return ( + <> + + +
+
+

Медиа

+ +
+ +
+ + { + if (rowId) { + deleteMedia(rowId.toString()); + getMedia(); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/PreviewMediaPage/index.tsx b/src/pages/Media/MediaPreviewPage/index.tsx similarity index 92% rename from src/pages/PreviewMediaPage/index.tsx rename to src/pages/Media/MediaPreviewPage/index.tsx index e9b2417..64e76a4 100644 --- a/src/pages/PreviewMediaPage/index.tsx +++ b/src/pages/Media/MediaPreviewPage/index.tsx @@ -1,12 +1,12 @@ import { mediaStore } from "@shared"; import { useEffect } from "react"; import { useParams } from "react-router-dom"; -import { MediaViewer } from "../../widgets/MediaViewer/index"; +import { MediaViewer } from "@widgets"; import { observer } from "mobx-react-lite"; import { Download } from "lucide-react"; import { Button } from "@mui/material"; -export const PreviewMediaPage = observer(() => { +export const MediaPreviewPage = observer(() => { const { id } = useParams(); const { oneMedia, getOneMedia } = mediaStore; diff --git a/src/pages/Media/index.ts b/src/pages/Media/index.ts new file mode 100644 index 0000000..a05c78a --- /dev/null +++ b/src/pages/Media/index.ts @@ -0,0 +1,3 @@ +export * from "./MediaEditPage"; +export * from "./MediaListPage"; +export * from "./MediaPreviewPage"; diff --git a/src/pages/MediaListPage/index.tsx b/src/pages/MediaListPage/index.tsx deleted file mode 100644 index 2e8d0ec..0000000 --- a/src/pages/MediaListPage/index.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { TableBody } from "@mui/material"; -import { TableRow, TableCell } from "@mui/material"; -import { Table, TableHead } from "@mui/material"; -import { mediaStore, MEDIA_TYPE_LABELS } from "@shared"; -import { useEffect, useState } from "react"; -import { observer } from "mobx-react-lite"; -import { Eye, Pencil, Trash2 } from "lucide-react"; -import { useNavigate } from "react-router-dom"; -import { DeleteModal } from "@widgets"; - -const rows = (media: any[]) => { - return media.map((row) => ({ - id: row.id, - media_name: row.media_name, - media_type: - MEDIA_TYPE_LABELS[row.media_type as keyof typeof MEDIA_TYPE_LABELS], - })); -}; - -export const MediaListPage = observer(() => { - const { media, getMedia, deleteMedia } = mediaStore; - const navigate = useNavigate(); - useEffect(() => { - getMedia(); - }, []); - - const currentRows = rows(media); - const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); - const [rowId, setRowId] = useState(null); - return ( - <> - - - - Название - Тип - Действия - - - - {currentRows.map((row) => ( - - {row.media_name} - {row.media_type} - -
- - - - - -
-
-
- ))} -
-
- { - if (rowId) { - await deleteMedia(rowId.toString()); - } - setIsDeleteModalOpen(false); - setRowId(null); - }} - onCancel={() => { - setIsDeleteModalOpen(false); - setRowId(null); - }} - /> - - ); -}); diff --git a/src/pages/Route/RouteCreatePage/index.tsx b/src/pages/Route/RouteCreatePage/index.tsx new file mode 100644 index 0000000..90b87a9 --- /dev/null +++ b/src/pages/Route/RouteCreatePage/index.tsx @@ -0,0 +1,86 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, +} from "@mui/material"; + +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Loader2, Save } from "lucide-react"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; + +export const RouteCreatePage = observer(() => { + const navigate = useNavigate(); + const [routeNumber, setRouteNumber] = useState(""); + const [direction, setDirection] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + return ( + +
+ +
+

Создание маршрута

+
+ setRouteNumber(e.target.value)} + /> + + Направление + + + + +
+
+ ); +}); diff --git a/src/pages/Route/RouteListPage/index.tsx b/src/pages/Route/RouteListPage/index.tsx new file mode 100644 index 0000000..dff4a49 --- /dev/null +++ b/src/pages/Route/RouteListPage/index.tsx @@ -0,0 +1,115 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, routeStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; + +export const RouteListPage = observer(() => { + const { routes, getRoutes, deleteRoute } = routeStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getRoutes(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "carrier", + headerName: "Перевозчик", + width: 250, + }, + { + field: "route_number", + headerName: "Номер маршрута", + flex: 1, + }, + { + field: "route_direction", + headerName: "Направление", + flex: 1, + renderCell: (params: GridRenderCellParams) => { + return ( +

+ {params.row.route_direction} +

+ ); + }, + }, + { + field: "actions", + headerName: "Действия", + width: 140, + align: "center", + headerAlign: "center", + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = routes.map((route) => ({ + id: route.id, + carrier: route.carrier, + route_number: route.route_number, + route_direction: route.route_direction ? "Прямой" : "Обратный", + })); + + return ( + <> + + +
+
+

Маршруты

+ +
+ +
+ + { + if (rowId) { + deleteRoute(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Route/index.ts b/src/pages/Route/index.ts new file mode 100644 index 0000000..97c495c --- /dev/null +++ b/src/pages/Route/index.ts @@ -0,0 +1 @@ +export * from "./RouteListPage"; \ No newline at end of file diff --git a/src/pages/Sight/SightListPage/index.tsx b/src/pages/Sight/SightListPage/index.tsx new file mode 100644 index 0000000..adf635b --- /dev/null +++ b/src/pages/Sight/SightListPage/index.tsx @@ -0,0 +1,96 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, sightsStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Pencil, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { DeleteModal, LanguageSwitcher } from "@widgets"; + +export const SightListPage = observer(() => { + const { sights, getSights, deleteListSight } = sightsStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getSights(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "name", + headerName: "Имя", + flex: 1, + }, + { + field: "city", + headerName: "Город", + flex: 1, + }, + + { + field: "actions", + headerName: "Действия", + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + {/* */} + +
+ ); + }, + }, + ]; + + const rows = sights.map((sight) => ({ + id: sight.id, + name: sight.name, + city: sight.city, + })); + + return ( + <> + + +
+ +
+ + { + if (rowId) { + await deleteListSight(Number(rowId)); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Sight/index.ts b/src/pages/Sight/index.ts new file mode 100644 index 0000000..4eed577 --- /dev/null +++ b/src/pages/Sight/index.ts @@ -0,0 +1 @@ +export * from "./SightListPage"; diff --git a/src/pages/Snapshot/SnapshotCreatePage/index.tsx b/src/pages/Snapshot/SnapshotCreatePage/index.tsx new file mode 100644 index 0000000..4c931e9 --- /dev/null +++ b/src/pages/Snapshot/SnapshotCreatePage/index.tsx @@ -0,0 +1,69 @@ +import { Button, Paper, TextField } from "@mui/material"; +import { snapshotStore } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Loader2, Save } from "lucide-react"; +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { toast } from "react-toastify"; + +export const SnapshotCreatePage = observer(() => { + const { id } = useParams(); + const { getSnapshot, createSnapshot } = snapshotStore; + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + (async () => { + await getSnapshot(id as string); + })(); + }, [id]); + + return ( + +
+ +
+

Создание снапшота

+
+ setName(e.target.value)} + /> + + +
+
+ ); +}); diff --git a/src/pages/Snapshot/SnapshotListPage/index.tsx b/src/pages/Snapshot/SnapshotListPage/index.tsx new file mode 100644 index 0000000..ef74695 --- /dev/null +++ b/src/pages/Snapshot/SnapshotListPage/index.tsx @@ -0,0 +1,127 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, snapshotStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { DatabaseBackup, Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { + CreateButton, + DeleteModal, + LanguageSwitcher, + SnapshotRestore, +} from "@widgets"; + +export const SnapshotListPage = observer(() => { + const { snapshots, getSnapshots, deleteSnapshot, restoreSnapshot } = + snapshotStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + const [isRestoreModalOpen, setIsRestoreModalOpen] = useState(false); + + useEffect(() => { + getSnapshots(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "name", + headerName: "Название", + flex: 1, + }, + { + field: "parent", + headerName: "Родитель", + flex: 1, + }, + + { + field: "actions", + headerName: "Действия", + width: 300, + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + + +
+ ); + }, + }, + ]; + + const rows = snapshots.map((snapshot) => ({ + id: snapshot.ID, + name: snapshot.Name, + parent: snapshots.find((s) => s.ID === snapshot.ParentID)?.Name, + })); + + return ( + <> + + +
+
+

Снапшоты

+ +
+ +
+ + { + if (rowId) { + await deleteSnapshot(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + { + if (rowId) { + await restoreSnapshot(rowId); + } + setIsRestoreModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsRestoreModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Snapshot/SnapshotPreviewPage/index.tsx b/src/pages/Snapshot/SnapshotPreviewPage/index.tsx new file mode 100644 index 0000000..3e751f0 --- /dev/null +++ b/src/pages/Snapshot/SnapshotPreviewPage/index.tsx @@ -0,0 +1,58 @@ +import { Paper } from "@mui/material"; +import { snapshotStore } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const SnapshotPreviewPage = observer(() => { + const { id } = useParams(); + const { getSnapshot, snapshot } = snapshotStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + await getSnapshot(id as string); + })(); + }, [id]); + + return ( + +
+ + {/*
+ + +
*/} +
+ {snapshot && ( +
+
+

Название

+

{snapshot?.Name}

+
+
+ )} +
+ ); +}); diff --git a/src/pages/Snapshot/index.ts b/src/pages/Snapshot/index.ts new file mode 100644 index 0000000..5c007d4 --- /dev/null +++ b/src/pages/Snapshot/index.ts @@ -0,0 +1,3 @@ +export * from "./SnapshotListPage"; +export * from "./SnapshotPreviewPage"; +export * from "./SnapshotCreatePage"; diff --git a/src/pages/Station/StationCreatePage/index.tsx b/src/pages/Station/StationCreatePage/index.tsx new file mode 100644 index 0000000..e2db4e4 --- /dev/null +++ b/src/pages/Station/StationCreatePage/index.tsx @@ -0,0 +1,94 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, +} from "@mui/material"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Loader2, Save } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import { stationsStore } from "@shared"; +import { useState } from "react"; + +export const StationCreatePage = observer(() => { + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [systemName, setSystemName] = useState(""); + const [direction, setDirection] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const handleCreate = async () => { + try { + setIsLoading(true); + await stationsStore.createStation(name, systemName, direction); + toast.success("Станция успешно создана"); + navigate("/station"); + } catch (error) { + toast.error("Ошибка при создании станции"); + } finally { + setIsLoading(false); + } + }; + + return ( + +
+ +
+

Создание станции

+
+ setName(e.target.value)} + /> + setSystemName(e.target.value)} + /> + + Направление + + + + +
+
+ ); +}); diff --git a/src/pages/Station/StationListPage/index.tsx b/src/pages/Station/StationListPage/index.tsx new file mode 100644 index 0000000..1174cc5 --- /dev/null +++ b/src/pages/Station/StationListPage/index.tsx @@ -0,0 +1,117 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, stationsStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; + +export const StationListPage = observer(() => { + const { stations, getStations, deleteStation } = stationsStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getStations(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "name", + headerName: "Название", + flex: 1, + }, + { + field: "system_name", + headerName: "Системное название", + flex: 1, + }, + { + field: "direction", + headerName: "Направление", + width: 200, + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +

+ {params.row.direction ? "Прямой" : "Обратный"} +

+ ); + }, + }, + { + field: "actions", + headerName: "Действия", + width: 140, + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = stations.map((station) => ({ + id: station.id, + name: station.name, + system_name: station.system_name, + direction: station.direction, + })); + + return ( + <> + + +
+
+

Станции

+ +
+ +
+ + { + if (rowId) { + deleteStation(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Station/index.ts b/src/pages/Station/index.ts new file mode 100644 index 0000000..c1705b8 --- /dev/null +++ b/src/pages/Station/index.ts @@ -0,0 +1 @@ +export * from "./StationListPage"; diff --git a/src/pages/User/UserListPage/index.tsx b/src/pages/User/UserListPage/index.tsx new file mode 100644 index 0000000..679295b --- /dev/null +++ b/src/pages/User/UserListPage/index.tsx @@ -0,0 +1,112 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { languageStore, userStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { DeleteModal, LanguageSwitcher } from "@widgets"; + +export const UserListPage = observer(() => { + const { users, getUsers, deleteUser } = userStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); // Lifted state + const { language } = languageStore; + + useEffect(() => { + getUsers(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "name", + headerName: "Имя", + width: 400, + }, + { + field: "email", + headerName: "Email", + width: 400, + }, + { + field: "is_admin", + headerName: "Роль", + flex: 1, + + renderCell: (params: GridRenderCellParams) => { + return ( +

+ {params.row.is_admin ? "Администратор" : "Пользователь"} +

+ ); + }, + }, + + { + field: "actions", + headerName: "Действия", + flex: 1, + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = users.map((user) => ({ + id: user.id, + email: user.email, + is_admin: user.is_admin, + name: user.name, + })); + + return ( + <> + + +
+ +
+ + { + if (rowId) { + await deleteUser(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/User/UserPreviewPage/index.tsx b/src/pages/User/UserPreviewPage/index.tsx new file mode 100644 index 0000000..431b0a7 --- /dev/null +++ b/src/pages/User/UserPreviewPage/index.tsx @@ -0,0 +1,74 @@ +import { Paper } from "@mui/material"; +import { userStore } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const UserPreviewPage = observer(() => { + const { id } = useParams(); + const { getUser, user } = userStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + await getUser(Number(id)); + })(); + }, [id]); + + return ( + +
+ + {/*
+ + +
*/} +
+ {user && ( +
+
+

Название

+

{user?.name}

+
+ +
+

Email

+

{user?.email}

+
+ +
+

Роль

+

+ {user?.is_admin ? "Администратор" : "Пользователь"} +

+
+
+ )} +
+ ); +}); diff --git a/src/pages/User/index.ts b/src/pages/User/index.ts new file mode 100644 index 0000000..555c90a --- /dev/null +++ b/src/pages/User/index.ts @@ -0,0 +1,2 @@ +export * from "./UserListPage"; +export * from "./UserPreviewPage"; diff --git a/src/pages/Vehicle/VehicleCreatePage/index.tsx b/src/pages/Vehicle/VehicleCreatePage/index.tsx new file mode 100644 index 0000000..34f69a7 --- /dev/null +++ b/src/pages/Vehicle/VehicleCreatePage/index.tsx @@ -0,0 +1,117 @@ +import { + Button, + Paper, + TextField, + Select, + MenuItem, + FormControl, + InputLabel, +} from "@mui/material"; +import { vehicleStore, VEHICLE_TYPES, carrierStore } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft, Save } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { toast } from "react-toastify"; +import { LanguageSwitcher } from "@widgets"; + +export const VehicleCreatePage = observer(() => { + const navigate = useNavigate(); + const [tailNumber, setTailNumber] = useState(""); + const [type, setType] = useState(""); + const [carrierId, setCarrierId] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + carrierStore.getCarriers(); + }, []); + + const handleCreate = async () => { + try { + setIsLoading(true); + await vehicleStore.createVehicle( + Number(tailNumber), + type, + carrierStore.carriers.find((c) => c.id === carrierId)?.full_name!, + carrierId! + ); + toast.success("Транспорт успешно создан"); + } catch (error) { + toast.error("Ошибка при создании транспорта"); + } finally { + setIsLoading(false); + } + }; + + return ( + + +
+ +
+ +
+ setTailNumber(e.target.value)} + /> + + + Тип + + + + + Перевозчик + + + + +
+
+ ); +}); diff --git a/src/pages/Vehicle/VehicleListPage/index.tsx b/src/pages/Vehicle/VehicleListPage/index.tsx new file mode 100644 index 0000000..8d41771 --- /dev/null +++ b/src/pages/Vehicle/VehicleListPage/index.tsx @@ -0,0 +1,133 @@ +import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid"; +import { carrierStore, languageStore, vehicleStore } from "@shared"; +import { useEffect, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { Eye, Trash2 } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { CreateButton, DeleteModal, LanguageSwitcher } from "@widgets"; +import { VEHICLE_TYPES } from "@shared"; + +export const VehicleListPage = observer(() => { + const { vehicles, getVehicles, deleteVehicle } = vehicleStore; + const { carriers, getCarriers } = carrierStore; + const navigate = useNavigate(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [rowId, setRowId] = useState(null); + const { language } = languageStore; + + useEffect(() => { + getVehicles(); + getCarriers(); + }, [language]); + + const columns: GridColDef[] = [ + { + field: "tail_number", + headerName: "Бортовой номер", + flex: 1, + align: "center", + headerAlign: "center", + }, + { + field: "type", + headerName: "Тип", + flex: 1, + align: "center", + headerAlign: "center", + renderCell: (params: GridRenderCellParams) => { + return ( +
+ {VEHICLE_TYPES.find((type) => type.value === params.row.type) + ?.label || params.row.type} +
+ ); + }, + }, + { + field: "carrier", + headerName: "Перевозчик", + flex: 1, + align: "center", + headerAlign: "center", + }, + { + field: "city", + headerName: "Город", + flex: 1, + align: "center", + headerAlign: "center", + }, + + { + field: "actions", + headerName: "Действия", + flex: 1, + align: "center", + headerAlign: "center", + + renderCell: (params: GridRenderCellParams) => { + return ( +
+ + +
+ ); + }, + }, + ]; + + const rows = vehicles.map((vehicle) => ({ + id: vehicle.vehicle.id, + tail_number: vehicle.vehicle.tail_number, + type: vehicle.vehicle.type, + carrier: vehicle.vehicle.carrier, + city: carriers.find((carrier) => carrier.id === vehicle.vehicle.carrier_id) + ?.city, + })); + + return ( + <> + + +
+
+

Транспортные средства

+ +
+ +
+ + { + if (rowId) { + await deleteVehicle(rowId); + } + setIsDeleteModalOpen(false); + setRowId(null); + }} + onCancel={() => { + setIsDeleteModalOpen(false); + setRowId(null); + }} + /> + + ); +}); diff --git a/src/pages/Vehicle/VehiclePreviewPage/index.tsx b/src/pages/Vehicle/VehiclePreviewPage/index.tsx new file mode 100644 index 0000000..207f048 --- /dev/null +++ b/src/pages/Vehicle/VehiclePreviewPage/index.tsx @@ -0,0 +1,70 @@ +import { Paper } from "@mui/material"; +import { vehicleStore, VEHICLE_TYPES } from "@shared"; +import { observer } from "mobx-react-lite"; +import { ArrowLeft } from "lucide-react"; +import { useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +export const VehiclePreviewPage = observer(() => { + const { id } = useParams(); + const { getVehicle, vehicle } = vehicleStore; + const navigate = useNavigate(); + + useEffect(() => { + (async () => { + await getVehicle(Number(id)); + })(); + }, [id]); + + return ( + +
+ + {/*
+ + +
*/} +
+ {vehicle && ( +
+
+

Системный номер

+

{vehicle?.vehicle.tail_number}

+
+
+

Тип транспортного средства

+

+ {VEHICLE_TYPES.find( + (type) => type.value === vehicle?.vehicle.type + )?.label || vehicle?.vehicle.type} +

+
+
+

Перевозчик

+

{vehicle?.vehicle.carrier}

+
+
+ )} +
+ ); +}); diff --git a/src/pages/Vehicle/index.ts b/src/pages/Vehicle/index.ts new file mode 100644 index 0000000..e1ccf6e --- /dev/null +++ b/src/pages/Vehicle/index.ts @@ -0,0 +1,3 @@ +export * from "./VehicleListPage"; +export * from "./VehiclePreviewPage"; +export * from "./VehicleCreatePage"; diff --git a/src/pages/index.ts b/src/pages/index.ts index 2116f1c..8edc95c 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -5,7 +5,15 @@ export * from "./DevicesPage"; export * from "./SightPage"; export * from "./CreateSightPage"; export * from "./MapPage"; -export * from "./MediaListPage"; -export * from "./PreviewMediaPage"; -export * from "./EditMediaPage"; +export * from "./Media"; // export * from "./CreateMediaPage"; +export * from "./Country"; +export * from "./City"; +export * from "./Route"; +export * from "./User"; +export * from "./Snapshot"; +export * from "./Carrier"; +export * from "./Station"; +export * from "./Vehicle"; +export * from "./Article"; +export * from "./Sight"; diff --git a/src/shared/config/constants.tsx b/src/shared/config/constants.tsx index d08aafb..584d681 100644 --- a/src/shared/config/constants.tsx +++ b/src/shared/config/constants.tsx @@ -5,7 +5,12 @@ import { Building2, MonitorSmartphone, Map, - BookImage, + Users, + Earth, + Landmark, + BusFront, + Bus, + GitBranch, } from "lucide-react"; export const DRAWER_WIDTH = 300; @@ -22,12 +27,54 @@ export const NAVIGATION_ITEMS: { secondary: NavigationItem[]; } = { primary: [ + { + id: "countries", + label: "Страны", + icon: Earth, + path: "/country", + }, + { + id: "cities", + label: "Города", + icon: Building2, + path: "/city", + }, + { + id: "carriers", + label: "Перевозчики", + icon: BusFront, + path: "/carrier", + }, + // { + // id: "media", + // label: "Медиа", + // icon: BookImage, + // path: "/media", + // }, + // { + // id: "articles", + // label: "Статьи", + // icon: Newspaper, + // path: "/article", + // }, { id: "attractions", label: "Достопримечательности", - icon: Building2, + icon: Landmark, path: "/sight", }, + // { + // id: "stations", + // label: "Остановки", + // icon: PersonStanding, + // path: "/station", + // }, + { + id: "snapshots", + label: "Снапшоты", + icon: GitBranch, + path: "/snapshot", + }, { id: "map", label: "Карта", @@ -41,10 +88,22 @@ export const NAVIGATION_ITEMS: { path: "/devices", }, { - id: "media", - label: "Медиа", - icon: BookImage, - path: "/media", + id: "vehicles", + label: "Транспорт", + icon: Bus, + path: "/vehicle", + }, + // { + // id: "routes", + // label: "Маршруты", + // icon: Split, + // path: "/route", + // }, + { + id: "users", + label: "Пользователи", + icon: Users, + path: "/user", }, // { // id: "articles", @@ -65,3 +124,8 @@ export const NAVIGATION_ITEMS: { }, ], }; + +export const VEHICLE_TYPES = [ + { label: "Трамвай", value: 1 }, + { label: "Троллейбус", value: 2 }, +]; diff --git a/src/shared/store/ArticlesStore/index.tsx b/src/shared/store/ArticlesStore/index.tsx index 0d30cb2..75649e5 100644 --- a/src/shared/store/ArticlesStore/index.tsx +++ b/src/shared/store/ArticlesStore/index.tsx @@ -25,10 +25,19 @@ class ArticlesStore { en: [], zh: [], }; + articleList: Article[] = []; articleData: Article | null = null; articleMedia: Media | null = null; articleLoading: boolean = false; + getArticleList = async () => { + const response = await authInstance.get("/article"); + + runInAction(() => { + this.articleList = response.data; + }); + }; + getArticles = async (language: Language) => { this.articleLoading = true; const response = await authInstance.get("/article"); diff --git a/src/shared/store/CarrierStore/index.tsx b/src/shared/store/CarrierStore/index.tsx new file mode 100644 index 0000000..28a5533 --- /dev/null +++ b/src/shared/store/CarrierStore/index.tsx @@ -0,0 +1,76 @@ +import { authInstance } from "@shared"; +import { makeAutoObservable, runInAction } from "mobx"; + +export type Carrier = { + id: number; + short_name: string; + full_name: string; + slogan: string; + city: string; + city_id: number; + logo: string; + main_color: string; + left_color: string; + right_color: string; +}; + +class CarrierStore { + carriers: Carrier[] = []; + carrier: Carrier | null = null; + constructor() { + makeAutoObservable(this); + } + + getCarriers = async () => { + const response = await authInstance.get("/carrier"); + + runInAction(() => { + this.carriers = response.data; + }); + }; + + deleteCarrier = async (id: number) => { + await authInstance.delete(`/carrier/${id}`); + + runInAction(() => { + this.carriers = this.carriers.filter((carrier) => carrier.id !== id); + }); + }; + + getCarrier = async (id: number) => { + const response = await authInstance.get(`/carrier/${id}`); + runInAction(() => { + this.carrier = response.data; + }); + return response.data; + }; + + createCarrier = async ( + fullName: string, + shortName: string, + city: string, + cityId: number, + primaryColor: string, + secondaryColor: string, + accentColor: string, + slogan: string, + logoId: string + ) => { + const response = await authInstance.post("/carrier", { + full_name: fullName, + short_name: shortName, + city, + city_id: cityId, + primary_color: primaryColor, + secondary_color: secondaryColor, + accent_color: accentColor, + slogan, + logo: logoId, + }); + runInAction(() => { + this.carriers.push(response.data); + }); + }; +} + +export const carrierStore = new CarrierStore(); diff --git a/src/shared/store/CityStore/index.tsx b/src/shared/store/CityStore/index.tsx index 4f87be0..130b0a7 100644 --- a/src/shared/store/CityStore/index.tsx +++ b/src/shared/store/CityStore/index.tsx @@ -11,19 +11,53 @@ type City = { class CityStore { cities: City[] = []; - + city: City | null = null; constructor() { makeAutoObservable(this); } getCities = async () => { - if (this.cities.length !== 0) return; - const response = await authInstance.get("/city"); + runInAction(() => { this.cities = response.data; }); }; + + deleteCity = async (id: number) => { + await authInstance.delete(`/city/${id}`); + + runInAction(() => { + this.cities = this.cities.filter((city) => city.id !== id); + }); + }; + + getCity = async (id: string) => { + const response = await authInstance.get(`/city/${id}`); + + runInAction(() => { + this.city = response.data; + }); + + return response.data; + }; + + createCity = async ( + name: string, + country: string, + countryCode: string, + mediaId: string + ) => { + const response = await authInstance.post("/city", { + name: name, + country: country, + country_code: countryCode, + arms: mediaId, + }); + runInAction(() => { + this.cities.push(response.data); + }); + }; } export const cityStore = new CityStore(); diff --git a/src/shared/store/CountryStore/index.ts b/src/shared/store/CountryStore/index.ts new file mode 100644 index 0000000..5e48b67 --- /dev/null +++ b/src/shared/store/CountryStore/index.ts @@ -0,0 +1,49 @@ +import { authInstance } from "@shared"; +import { makeAutoObservable, runInAction } from "mobx"; + +export type Country = { + code: string; + name: string; +}; + +class CountryStore { + countries: Country[] = []; + country: Country | null = null; + + constructor() { + makeAutoObservable(this); + } + + getCountries = async () => { + const response = await authInstance.get("/country"); + + runInAction(() => { + this.countries = response.data; + }); + }; + + getCountry = async (code: string) => { + const response = await authInstance.get(`/country/${code}`); + + runInAction(() => { + this.country = response.data; + }); + }; + + deleteCountry = async (code: string) => { + await authInstance.delete(`/country/${code}`); + + runInAction(() => { + this.countries = this.countries.filter( + (country) => country.code !== code + ); + }); + }; + + createCountry = async (code: string, name: string) => { + await authInstance.post("/country", { code: code, name: name }); + await this.getCountries(); + }; +} + +export const countryStore = new CountryStore(); diff --git a/src/shared/store/MediaStore/index.tsx b/src/shared/store/MediaStore/index.tsx index ef56a0a..7daeb26 100644 --- a/src/shared/store/MediaStore/index.tsx +++ b/src/shared/store/MediaStore/index.tsx @@ -76,6 +76,16 @@ class MediaStore { }); return response.data; }; + + createMedia = async (name: string, type: string) => { + const response = await authInstance.post("/media", { + media_name: name, + media_type: type, + }); + runInAction(() => { + this.media.push(response.data); + }); + }; } export const mediaStore = new MediaStore(); diff --git a/src/shared/store/RouteStore/index.ts b/src/shared/store/RouteStore/index.ts new file mode 100644 index 0000000..14d8c4f --- /dev/null +++ b/src/shared/store/RouteStore/index.ts @@ -0,0 +1,45 @@ +import { makeAutoObservable, runInAction } from "mobx"; +import { authInstance } from "@shared"; + +export type Route = { + carrier: string; + carrier_id: number; + center_latitude: number; + center_longitude: number; + governor_appeal: number; + id: number; + path: number[][]; + rotate: number; + route_direction: boolean; + route_number: string; + route_sys_number: string; + scale_max: number; + scale_min: number; + video_preview: string; +}; + +class RouteStore { + routes: Route[] = []; + + constructor() { + makeAutoObservable(this); + } + + getRoutes = async () => { + const response = await authInstance.get("/route"); + + runInAction(() => { + this.routes = response.data; + }); + }; + + deleteRoute = async (id: number) => { + await authInstance.delete(`/route/${id}`); + + runInAction(() => { + this.routes = this.routes.filter((route) => route.id !== id); + }); + }; +} + +export const routeStore = new RouteStore(); \ No newline at end of file diff --git a/src/shared/store/SightsStore/index.tsx b/src/shared/store/SightsStore/index.tsx index 62897aa..63a32ab 100644 --- a/src/shared/store/SightsStore/index.tsx +++ b/src/shared/store/SightsStore/index.tsx @@ -219,6 +219,11 @@ class SightsStore { }, }; }); + + deleteListSight = async (id: number) => { + await authInstance.delete(`/sight/${id}`); + this.sights = this.sights.filter((sight) => sight.id !== id); + }; } export const sightsStore = new SightsStore(); diff --git a/src/shared/store/SnapshotStore/index.ts b/src/shared/store/SnapshotStore/index.ts index 4768390..204d82f 100644 --- a/src/shared/store/SnapshotStore/index.ts +++ b/src/shared/store/SnapshotStore/index.ts @@ -1,6 +1,6 @@ import { authInstance } from "@shared"; -import { API_URL } from "@shared"; -import { makeAutoObservable } from "mobx"; + +import { makeAutoObservable, runInAction } from "mobx"; type Snapshot = { ID: string; @@ -11,14 +11,42 @@ type Snapshot = { class SnapshotStore { snapshots: Snapshot[] = []; + snapshot: Snapshot | null = null; constructor() { makeAutoObservable(this); } getSnapshots = async () => { - const response = await authInstance.get(`${API_URL}/snapshots`); - this.snapshots = response.data; + const response = await authInstance.get(`/snapshots`); + + runInAction(() => { + this.snapshots = response.data; + }); + }; + + deleteSnapshot = async (id: string) => { + await authInstance.delete(`/snapshots/${id}`); + + runInAction(() => { + this.snapshots = this.snapshots.filter((snapshot) => snapshot.ID !== id); + }); + }; + + getSnapshot = async (id: string) => { + const response = await authInstance.get(`/snapshots/${id}`); + + runInAction(() => { + this.snapshot = response.data; + }); + }; + + restoreSnapshot = async (id: string) => { + await authInstance.post(`/snapshots/${id}/restore`); + }; + + createSnapshot = async (name: string) => { + await authInstance.post(`/snapshots`, { name }); }; } diff --git a/src/shared/store/StationsStore/index.ts b/src/shared/store/StationsStore/index.ts new file mode 100644 index 0000000..650a1eb --- /dev/null +++ b/src/shared/store/StationsStore/index.ts @@ -0,0 +1,76 @@ +import { authInstance } from "@shared"; +import { makeAutoObservable, runInAction } from "mobx"; + +type Station = { + id: number; + address: string; + city: string; + city_id: number; + description: string; + direction: boolean; + icon: string; + latitude: number; + longitude: number; + name: string; + offset_x: number; + offset_y: number; + system_name: string; + transfers: { + bus: string; + metro_blue: string; + metro_green: string; + metro_orange: string; + metro_purple: string; + metro_red: string; + train: string; + tram: string; + trolleybus: string; + }; +}; + +class StationsStore { + stations: Station[] = []; + station: Station | null = null; + + constructor() { + makeAutoObservable(this); + } + + getStations = async () => { + const response = await authInstance.get("/station"); + + runInAction(() => { + this.stations = response.data; + }); + }; + + deleteStation = async (id: number) => { + await authInstance.delete(`/station/${id}`); + + runInAction(() => { + this.stations = this.stations.filter((station) => station.id !== id); + }); + }; + + getStation = async (id: number) => { + const response = await authInstance.get(`/station/${id}`); + this.station = response.data; + }; + + createStation = async ( + name: string, + systemName: string, + direction: string + ) => { + const response = await authInstance.post("/station", { + station_name: name, + system_name: systemName, + direction, + }); + runInAction(() => { + this.stations.push(response.data); + }); + }; +} + +export const stationsStore = new StationsStore(); diff --git a/src/shared/store/UserStore/index.ts b/src/shared/store/UserStore/index.ts new file mode 100644 index 0000000..9ea9cb0 --- /dev/null +++ b/src/shared/store/UserStore/index.ts @@ -0,0 +1,44 @@ +import { authInstance } from "@shared"; +import { makeAutoObservable, runInAction } from "mobx"; + +export type User = { + id: number; + email: string; + is_admin: boolean; + name: string; +}; + +class UserStore { + users: User[] = []; + user: User | null = null; + + constructor() { + makeAutoObservable(this); + } + + getUsers = async () => { + const response = await authInstance.get("/user"); + + runInAction(() => { + this.users = response.data; + }); + }; + + getUser = async (id: number) => { + const response = await authInstance.get(`/user/${id}`); + + runInAction(() => { + this.user = response.data as User; + }); + }; + + deleteUser = async (id: number) => { + await authInstance.delete(`/users/${id}`); + + runInAction(() => { + this.users = this.users.filter((user) => user.id !== id); + }); + }; +} + +export const userStore = new UserStore(); diff --git a/src/shared/store/VehicleStore/index.ts b/src/shared/store/VehicleStore/index.ts index 63856ab..1ead75d 100644 --- a/src/shared/store/VehicleStore/index.ts +++ b/src/shared/store/VehicleStore/index.ts @@ -1,4 +1,4 @@ -import { API_URL, authInstance } from "@shared"; +import { authInstance } from "@shared"; import { makeAutoObservable } from "mobx"; export type Vehicle = { @@ -22,15 +22,43 @@ export type Vehicle = { class VehicleStore { vehicles: Vehicle[] = []; + vehicle: Vehicle | null = null; constructor() { makeAutoObservable(this); } getVehicles = async () => { - const response = await authInstance.get(`${API_URL}/vehicle`); + const response = await authInstance.get(`/vehicle`); this.vehicles = response.data; }; + + deleteVehicle = async (id: number) => { + await authInstance.delete(`/vehicle/${id}`); + this.vehicles = this.vehicles.filter( + (vehicle) => vehicle.vehicle.id !== id + ); + }; + + getVehicle = async (id: number) => { + const response = await authInstance.get(`/vehicle/${id}`); + this.vehicle = response.data; + }; + + createVehicle = async ( + tailNumber: number, + type: string, + carrier: string, + carrierId: number + ) => { + await authInstance.post("/vehicle", { + tail_number: tailNumber, + type, + carrier, + carrier_id: carrierId, + }); + await this.getVehicles(); + }; } export const vehicleStore = new VehicleStore(); diff --git a/src/shared/store/index.ts b/src/shared/store/index.ts index efa6fe6..bddc885 100644 --- a/src/shared/store/index.ts +++ b/src/shared/store/index.ts @@ -9,3 +9,8 @@ export * from "./ArticlesStore"; export * from "./EditSightStore"; export * from "./MediaStore"; export * from "./CreateSightStore"; +export * from "./CountryStore"; +export * from "./RouteStore"; +export * from "./UserStore"; +export * from "./CarrierStore"; +export * from "./StationsStore"; diff --git a/src/widgets/CreateButton/index.tsx b/src/widgets/CreateButton/index.tsx new file mode 100644 index 0000000..b3b5011 --- /dev/null +++ b/src/widgets/CreateButton/index.tsx @@ -0,0 +1,25 @@ +import { Button } from "@mui/material"; +import { Plus } from "lucide-react"; +import { useNavigate } from "react-router-dom"; + +interface CreateButtonProps { + label: string; + path: string; +} + +export const CreateButton = ({ label, path }: CreateButtonProps) => { + const navigate = useNavigate(); + + return ( + + ); +}; diff --git a/src/widgets/LanguageSwitcher/index.tsx b/src/widgets/LanguageSwitcher/index.tsx index b6e1650..6ae59aa 100644 --- a/src/widgets/LanguageSwitcher/index.tsx +++ b/src/widgets/LanguageSwitcher/index.tsx @@ -9,7 +9,6 @@ type Language = (typeof LANGUAGES)[number]; export const LanguageSwitcher = observer(() => { const { language, setLanguage } = languageStore; - // Memoize getLanguageLabel for consistent rendering const getLanguageLabel = useCallback((lang: Language) => { switch (lang) { case "ru": @@ -45,7 +44,7 @@ export const LanguageSwitcher = observer(() => { }; return ( -
+
{/* Added some styling for better visualization */} {LANGUAGES.map((lang) => ( + +
+
+ + ); +}; diff --git a/src/widgets/index.ts b/src/widgets/index.ts index 3ace673..98752ad 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -14,3 +14,5 @@ export * from "./MediaAreaForSight"; export * from "./ImageUploadCard"; export * from "./LeaveAgree"; export * from "./DeleteModal"; +export * from "./SnapshotRestore"; +export * from "./CreateButton"; diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index b5f695b..23a0313 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/app/index.tsx","./src/app/router/index.tsx","./src/entities/index.ts","./src/entities/navigation/index.ts","./src/entities/navigation/model/index.ts","./src/entities/navigation/ui/index.tsx","./src/features/index.ts","./src/features/navigation/index.ts","./src/features/navigation/ui/index.tsx","./src/pages/index.ts","./src/pages/createmediapage/index.tsx","./src/pages/createsightpage/index.tsx","./src/pages/devicespage/index.tsx","./src/pages/editmediapage/index.tsx","./src/pages/editsightpage/index.tsx","./src/pages/loginpage/index.tsx","./src/pages/mainpage/index.tsx","./src/pages/mappage/index.tsx","./src/pages/medialistpage/index.tsx","./src/pages/previewmediapage/index.tsx","./src/pages/sightpage/index.tsx","./src/shared/index.tsx","./src/shared/api/index.tsx","./src/shared/config/constants.tsx","./src/shared/config/index.ts","./src/shared/const/index.ts","./src/shared/lib/index.ts","./src/shared/lib/decodejwt/index.ts","./src/shared/lib/mui/theme.ts","./src/shared/modals/index.ts","./src/shared/modals/previewmediadialog/index.tsx","./src/shared/modals/selectarticledialog/index.tsx","./src/shared/modals/selectmediadialog/index.tsx","./src/shared/modals/uploadmediadialog/index.tsx","./src/shared/store/index.ts","./src/shared/store/articlesstore/index.tsx","./src/shared/store/authstore/index.tsx","./src/shared/store/citystore/index.tsx","./src/shared/store/createsightstore/index.tsx","./src/shared/store/devicesstore/index.tsx","./src/shared/store/editsightstore/index.tsx","./src/shared/store/languagestore/index.tsx","./src/shared/store/mediastore/index.tsx","./src/shared/store/sightsstore/index.tsx","./src/shared/store/snapshotstore/index.ts","./src/shared/store/vehiclestore/index.ts","./src/shared/ui/index.ts","./src/shared/ui/backbutton/index.tsx","./src/shared/ui/coordinatesinput/index.tsx","./src/shared/ui/input/index.tsx","./src/shared/ui/modal/index.tsx","./src/shared/ui/tabpanel/index.tsx","./src/widgets/index.ts","./src/widgets/deletemodal/index.tsx","./src/widgets/devicestable/index.tsx","./src/widgets/imageuploadcard/index.tsx","./src/widgets/languageswitcher/index.tsx","./src/widgets/layout/index.tsx","./src/widgets/layout/ui/appbar.tsx","./src/widgets/layout/ui/drawer.tsx","./src/widgets/layout/ui/drawerheader.tsx","./src/widgets/leaveagree/index.tsx","./src/widgets/mediaarea/index.tsx","./src/widgets/mediaareaforsight/index.tsx","./src/widgets/mediaviewer/threeview.tsx","./src/widgets/mediaviewer/index.tsx","./src/widgets/modelviewer3d/index.tsx","./src/widgets/reactmarkdown/index.tsx","./src/widgets/reactmarkdowneditor/index.tsx","./src/widgets/sightedit/index.tsx","./src/widgets/sightheader/index.ts","./src/widgets/sightheader/ui/index.tsx","./src/widgets/sighttabs/index.ts","./src/widgets/sighttabs/createinformationtab/mediauploadbox.tsx","./src/widgets/sighttabs/createinformationtab/index.tsx","./src/widgets/sighttabs/createlefttab/index.tsx","./src/widgets/sighttabs/createrighttab/index.tsx","./src/widgets/sighttabs/informationtab/index.tsx","./src/widgets/sighttabs/leftwidgettab/index.tsx","./src/widgets/sighttabs/rightwidgettab/index.tsx","./src/widgets/sightstable/index.tsx","./src/widgets/modals/index.ts","./src/widgets/modals/selectarticledialog/index.tsx"],"version":"5.8.3"} \ No newline at end of file +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/app/index.tsx","./src/app/router/index.tsx","./src/entities/index.ts","./src/entities/navigation/index.ts","./src/entities/navigation/model/index.ts","./src/entities/navigation/ui/index.tsx","./src/features/index.ts","./src/features/navigation/index.ts","./src/features/navigation/ui/index.tsx","./src/pages/index.ts","./src/pages/article/index.ts","./src/pages/article/articlelistpage/index.tsx","./src/pages/carrier/index.ts","./src/pages/carrier/carriercreatepage/index.tsx","./src/pages/carrier/carrierlistpage/index.tsx","./src/pages/carrier/carrierpreviewpage/index.tsx","./src/pages/city/index.ts","./src/pages/city/citycreatepage/index.tsx","./src/pages/city/citylistpage/index.tsx","./src/pages/city/citypreviewpage/index.tsx","./src/pages/country/index.ts","./src/pages/country/countrycreatepage/index.tsx","./src/pages/country/countrylistpage/index.tsx","./src/pages/country/countrypreviewpage/index.tsx","./src/pages/createsightpage/index.tsx","./src/pages/devicespage/index.tsx","./src/pages/editsightpage/index.tsx","./src/pages/loginpage/index.tsx","./src/pages/mainpage/index.tsx","./src/pages/mappage/index.tsx","./src/pages/media/index.ts","./src/pages/media/mediacreatepage/index.tsx","./src/pages/media/mediaeditpage/index.tsx","./src/pages/media/medialistpage/index.tsx","./src/pages/media/mediapreviewpage/index.tsx","./src/pages/route/index.ts","./src/pages/route/routecreatepage/index.tsx","./src/pages/route/routelistpage/index.tsx","./src/pages/sight/index.ts","./src/pages/sight/sightlistpage/index.tsx","./src/pages/sightpage/index.tsx","./src/pages/snapshot/index.ts","./src/pages/snapshot/snapshotcreatepage/index.tsx","./src/pages/snapshot/snapshotlistpage/index.tsx","./src/pages/snapshot/snapshotpreviewpage/index.tsx","./src/pages/station/index.ts","./src/pages/station/stationcreatepage/index.tsx","./src/pages/station/stationlistpage/index.tsx","./src/pages/user/index.ts","./src/pages/user/userlistpage/index.tsx","./src/pages/user/userpreviewpage/index.tsx","./src/pages/vehicle/index.ts","./src/pages/vehicle/vehiclecreatepage/index.tsx","./src/pages/vehicle/vehiclelistpage/index.tsx","./src/pages/vehicle/vehiclepreviewpage/index.tsx","./src/shared/index.tsx","./src/shared/api/index.tsx","./src/shared/config/constants.tsx","./src/shared/config/index.ts","./src/shared/const/index.ts","./src/shared/lib/index.ts","./src/shared/lib/decodejwt/index.ts","./src/shared/lib/mui/theme.ts","./src/shared/modals/index.ts","./src/shared/modals/previewmediadialog/index.tsx","./src/shared/modals/selectarticledialog/index.tsx","./src/shared/modals/selectmediadialog/index.tsx","./src/shared/modals/uploadmediadialog/index.tsx","./src/shared/store/index.ts","./src/shared/store/articlesstore/index.tsx","./src/shared/store/authstore/index.tsx","./src/shared/store/carrierstore/index.tsx","./src/shared/store/citystore/index.tsx","./src/shared/store/countrystore/index.ts","./src/shared/store/createsightstore/index.tsx","./src/shared/store/devicesstore/index.tsx","./src/shared/store/editsightstore/index.tsx","./src/shared/store/languagestore/index.tsx","./src/shared/store/mediastore/index.tsx","./src/shared/store/routestore/index.ts","./src/shared/store/sightsstore/index.tsx","./src/shared/store/snapshotstore/index.ts","./src/shared/store/stationsstore/index.ts","./src/shared/store/userstore/index.ts","./src/shared/store/vehiclestore/index.ts","./src/shared/ui/index.ts","./src/shared/ui/backbutton/index.tsx","./src/shared/ui/coordinatesinput/index.tsx","./src/shared/ui/input/index.tsx","./src/shared/ui/modal/index.tsx","./src/shared/ui/tabpanel/index.tsx","./src/widgets/index.ts","./src/widgets/createbutton/index.tsx","./src/widgets/deletemodal/index.tsx","./src/widgets/devicestable/index.tsx","./src/widgets/imageuploadcard/index.tsx","./src/widgets/languageswitcher/index.tsx","./src/widgets/layout/index.tsx","./src/widgets/layout/ui/appbar.tsx","./src/widgets/layout/ui/drawer.tsx","./src/widgets/layout/ui/drawerheader.tsx","./src/widgets/leaveagree/index.tsx","./src/widgets/mediaarea/index.tsx","./src/widgets/mediaareaforsight/index.tsx","./src/widgets/mediaviewer/threeview.tsx","./src/widgets/mediaviewer/index.tsx","./src/widgets/modelviewer3d/index.tsx","./src/widgets/reactmarkdown/index.tsx","./src/widgets/reactmarkdowneditor/index.tsx","./src/widgets/sightedit/index.tsx","./src/widgets/sightheader/index.ts","./src/widgets/sightheader/ui/index.tsx","./src/widgets/sighttabs/index.ts","./src/widgets/sighttabs/createinformationtab/mediauploadbox.tsx","./src/widgets/sighttabs/createinformationtab/index.tsx","./src/widgets/sighttabs/createlefttab/index.tsx","./src/widgets/sighttabs/createrighttab/index.tsx","./src/widgets/sighttabs/informationtab/index.tsx","./src/widgets/sighttabs/leftwidgettab/index.tsx","./src/widgets/sighttabs/rightwidgettab/index.tsx","./src/widgets/sightstable/index.tsx","./src/widgets/snapshotrestore/index.tsx","./src/widgets/modals/index.ts","./src/widgets/modals/selectarticledialog/index.tsx"],"version":"5.8.3"} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index cd3374e..200f2bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24,7 +24,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.3.tgz" integrity sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw== -"@babel/core@^7.26.10": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.26.10": version "7.27.3" resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.3.tgz" integrity sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA== @@ -133,15 +133,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.26.0", "@babel/runtime@^7.27.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": - version "7.27.3" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz" - integrity sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw== - -"@babel/runtime@^7.26.7": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.4.tgz#a91ec580e6c00c67118127777c316dfd5a5a6abf" - integrity sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA== +"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.26.0", "@babel/runtime@^7.26.7", "@babel/runtime@^7.27.1", "@babel/runtime@^7.27.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.27.6" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== "@babel/template@^7.27.2": version "7.27.2" @@ -178,28 +173,6 @@ resolved "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz" integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow== -"@emnapi/core@^1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.3.tgz#9ac52d2d5aea958f67e52c40a065f51de59b77d6" - integrity sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g== - dependencies: - "@emnapi/wasi-threads" "1.0.2" - tslib "^2.4.0" - -"@emnapi/runtime@^1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" - integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== - dependencies: - tslib "^2.4.0" - -"@emnapi/wasi-threads@1.0.2", "@emnapi/wasi-threads@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz#977f44f844eac7d6c138a415a123818c655f874c" - integrity sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA== - dependencies: - tslib "^2.4.0" - "@emotion/babel-plugin@^11.13.5": version "11.13.5" resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz" @@ -245,7 +218,7 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== -"@emotion/react@^11.14.0": +"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.14.0", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0", "@emotion/react@^11.9.0": version "11.14.0" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz" integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== @@ -275,7 +248,7 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== -"@emotion/styled@^11.14.0": +"@emotion/styled@^11.14.0", "@emotion/styled@^11.3.0", "@emotion/styled@^11.8.1": version "11.14.0" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz" integrity sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA== @@ -307,131 +280,11 @@ resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== -"@esbuild/aix-ppc64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz#4e0f91776c2b340e75558f60552195f6fad09f18" - integrity sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA== - -"@esbuild/android-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz#bc766407f1718923f6b8079c8c61bf86ac3a6a4f" - integrity sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg== - -"@esbuild/android-arm@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.5.tgz#4290d6d3407bae3883ad2cded1081a234473ce26" - integrity sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA== - -"@esbuild/android-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.5.tgz#40c11d9cbca4f2406548c8a9895d321bc3b35eff" - integrity sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw== - "@esbuild/darwin-arm64@0.25.5": version "0.25.5" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz" integrity sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ== -"@esbuild/darwin-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz#e27a5d92a14886ef1d492fd50fc61a2d4d87e418" - integrity sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ== - -"@esbuild/freebsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz#97cede59d638840ca104e605cdb9f1b118ba0b1c" - integrity sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw== - -"@esbuild/freebsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz#71c77812042a1a8190c3d581e140d15b876b9c6f" - integrity sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw== - -"@esbuild/linux-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz#f7b7c8f97eff8ffd2e47f6c67eb5c9765f2181b8" - integrity sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg== - -"@esbuild/linux-arm@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz#2a0be71b6cd8201fa559aea45598dffabc05d911" - integrity sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw== - -"@esbuild/linux-ia32@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz#763414463cd9ea6fa1f96555d2762f9f84c61783" - integrity sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA== - -"@esbuild/linux-loong64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz#428cf2213ff786a502a52c96cf29d1fcf1eb8506" - integrity sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg== - -"@esbuild/linux-mips64el@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz#5cbcc7fd841b4cd53358afd33527cd394e325d96" - integrity sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg== - -"@esbuild/linux-ppc64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz#0d954ab39ce4f5e50f00c4f8c4fd38f976c13ad9" - integrity sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ== - -"@esbuild/linux-riscv64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz#0e7dd30730505abd8088321e8497e94b547bfb1e" - integrity sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA== - -"@esbuild/linux-s390x@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz#5669af81327a398a336d7e40e320b5bbd6e6e72d" - integrity sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ== - -"@esbuild/linux-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz#b2357dd153aa49038967ddc1ffd90c68a9d2a0d4" - integrity sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw== - -"@esbuild/netbsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz#53b4dfb8fe1cee93777c9e366893bd3daa6ba63d" - integrity sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw== - -"@esbuild/netbsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz#a0206f6314ce7dc8713b7732703d0f58de1d1e79" - integrity sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ== - -"@esbuild/openbsd-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz#2a796c87c44e8de78001d808c77d948a21ec22fd" - integrity sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw== - -"@esbuild/openbsd-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz#28d0cd8909b7fa3953af998f2b2ed34f576728f0" - integrity sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg== - -"@esbuild/sunos-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz#a28164f5b997e8247d407e36c90d3fd5ddbe0dc5" - integrity sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA== - -"@esbuild/win32-arm64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz#6eadbead38e8bd12f633a5190e45eff80e24007e" - integrity sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw== - -"@esbuild/win32-ia32@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz#bab6288005482f9ed2adb9ded7e88eba9a62cc0d" - integrity sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ== - -"@esbuild/win32-x64@0.25.5": - version "0.25.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz#7fc114af5f6563f19f73324b5d5ff36ece0803d1" - integrity sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g== - "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0": version "4.7.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz" @@ -480,7 +333,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.27.0", "@eslint/js@^9.25.0": +"@eslint/js@^9.25.0", "@eslint/js@9.27.0": version "9.27.0" resolved "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz" integrity sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA== @@ -500,7 +353,7 @@ "@hello-pangea/dnd@^18.0.1": version "18.0.1" - resolved "https://registry.yarnpkg.com/@hello-pangea/dnd/-/dnd-18.0.1.tgz#7d5ef7fe8bddf195307b16e03635b1be582b7b8d" + resolved "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz" integrity sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ== dependencies: "@babel/runtime" "^7.26.7" @@ -593,7 +446,7 @@ resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.0.tgz" integrity sha512-E0OqhZv548Qdc0PwWhLVA2zmjJZSTvaL4ZhoswmI8NJEC1tpW2js6LLP827jrW9MEiXYdz3QS6+hask83w74yQ== -"@mui/material@^7.1.0": +"@mui/material@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/material@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@mui/material/-/material-7.1.0.tgz" integrity sha512-ahUJdrhEv+mCp4XHW+tHIEYzZMSRLg8z4AjUOsj44QpD1ZaMxQoVOG2xiHvLFdcsIPbgSRx1bg1eQSheHBgvtg== @@ -632,7 +485,7 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^7.1.0": +"@mui/system@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/system@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@mui/system/-/system-7.1.0.tgz" integrity sha512-iedAWgRJMCxeMHvkEhsDlbvkK+qKf9me6ofsf7twk/jfT4P1ImVf7Rwb5VubEA0sikrVL+1SkoZM41M4+LNAVA== @@ -646,33 +499,45 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.4.2": - version "7.4.2" - resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz" - integrity sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA== +"@mui/types@^7.4.2", "@mui/types@^7.4.3": + version "7.4.3" + resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.3.tgz" + integrity sha512-2UCEiK29vtiZTeLdS2d4GndBKacVyxGvReznGXGr+CzW/YhjIX+OHUdCIczZjzcRAgKBGmE9zCIgoV9FleuyRQ== dependencies: "@babel/runtime" "^7.27.1" -"@mui/utils@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz" - integrity sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw== +"@mui/utils@^7.1.0", "@mui/utils@^7.1.1": + version "7.1.1" + resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.1.1.tgz" + integrity sha512-BkOt2q7MBYl7pweY2JWwfrlahhp+uGLR8S+EhiyRaofeRYUWL2YKbSGQvN4hgSN1i8poN0PaUiii1kEMrchvzg== dependencies: "@babel/runtime" "^7.27.1" - "@mui/types" "^7.4.2" + "@mui/types" "^7.4.3" "@types/prop-types" "^15.7.14" clsx "^2.1.1" prop-types "^15.8.1" react-is "^19.1.0" -"@napi-rs/wasm-runtime@^0.2.10": - version "0.2.10" - resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz#f3b7109419c6670000b2401e0c778b98afc25f84" - integrity sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ== +"@mui/x-data-grid@^8.5.1": + version "8.5.1" + resolved "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-8.5.1.tgz" + integrity sha512-Ukodx8cOc/GR4+2zr4DRNBJJOlyeJNaxK4hggWv7VchDL7Jf70dLZO7oLXPhEFG05Yna81RatL/UFsRYIdWI1Q== dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@tybys/wasm-util" "^0.9.0" + "@babel/runtime" "^7.27.4" + "@mui/utils" "^7.1.1" + "@mui/x-internals" "8.5.1" + clsx "^2.1.1" + prop-types "^15.8.1" + reselect "^5.1.1" + use-sync-external-store "^1.5.0" + +"@mui/x-internals@8.5.1": + version "8.5.1" + resolved "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.5.1.tgz" + integrity sha512-7rAWK7SB6FxEIXKgsHsJjIzeeKOLxFJ16gePgZVWlvyew+xDb4P0fgjwW3ThcJjgvkUm0UhGGfLh/JP8l514IA== + dependencies: + "@babel/runtime" "^7.27.4" + "@mui/utils" "^7.1.1" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -682,7 +547,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -700,7 +565,7 @@ resolved "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz" integrity sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog== -"@photo-sphere-viewer/core@^5.13.2": +"@photo-sphere-viewer/core@^5.13.2", "@photo-sphere-viewer/core@>=5.13.1": version "5.13.2" resolved "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.13.2.tgz" integrity sha512-rL4Ey39Prx4Iyxt1f2tAqlXvqu4/ovXfUvIpLt540OpZJiFjWccs6qLywof9vuhBJ7PXHudHWCjRPce0W8kx8w== @@ -739,7 +604,7 @@ utility-types "^3.11.0" zustand "^5.0.1" -"@react-three/fiber@^9.1.2": +"@react-three/fiber@^9.0.0", "@react-three/fiber@^9.1.2": version "9.1.2" resolved "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.1.2.tgz" integrity sha512-k8FR9yVHV9kIF3iuOD0ds5hVymXYXfgdKklqziBVod9ZEJ8uk05Zjw29J/omU3IKeUfLNAIHfxneN3TUYM4I2w== @@ -762,106 +627,11 @@ resolved "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.9.tgz" integrity sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w== -"@rollup/rollup-android-arm-eabi@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz#f39f09f60d4a562de727c960d7b202a2cf797424" - integrity sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw== - -"@rollup/rollup-android-arm64@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz#d19af7e23760717f1d879d4ca3d2cd247742dff2" - integrity sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA== - "@rollup/rollup-darwin-arm64@4.41.1": version "4.41.1" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz" integrity sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w== -"@rollup/rollup-darwin-x64@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz#aa66d2ba1a25e609500e13bef06dc0e71cc0c0d4" - integrity sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg== - -"@rollup/rollup-freebsd-arm64@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz#df10a7b6316a0ef1028c6ca71a081124c537e30d" - integrity sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg== - -"@rollup/rollup-freebsd-x64@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz#a3fdce8a05e95b068cbcb46e4df5185e407d0c35" - integrity sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA== - -"@rollup/rollup-linux-arm-gnueabihf@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz#49f766c55383bd0498014a9d76924348c2f3890c" - integrity sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg== - -"@rollup/rollup-linux-arm-musleabihf@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz#1d4d7d32fc557e17d52e1857817381ea365e2959" - integrity sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA== - -"@rollup/rollup-linux-arm64-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz#f4fc317268441e9589edad3be8f62b6c03009bc1" - integrity sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA== - -"@rollup/rollup-linux-arm64-musl@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz#63a1f1b0671cb17822dabae827fef0e443aebeb7" - integrity sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg== - -"@rollup/rollup-linux-loongarch64-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz#c659b01cc6c0730b547571fc3973e1e955369f98" - integrity sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz#612e746f9ad7e58480f964d65e0d6c3f4aae69a8" - integrity sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A== - -"@rollup/rollup-linux-riscv64-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz#4610dbd1dcfbbae32fbc10c20ae7387acb31110c" - integrity sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw== - -"@rollup/rollup-linux-riscv64-musl@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz#054911fab40dc83fafc21e470193c058108f19d8" - integrity sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw== - -"@rollup/rollup-linux-s390x-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz#98896eca8012547c7f04bd07eaa6896825f9e1a5" - integrity sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g== - -"@rollup/rollup-linux-x64-gnu@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz#01cf56844a1e636ee80dfb364e72c2b7142ad896" - integrity sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A== - -"@rollup/rollup-linux-x64-musl@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz#e67c7531df6dff0b4c241101d4096617fbca87c3" - integrity sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ== - -"@rollup/rollup-win32-arm64-msvc@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz#7eeada98444e580674de6989284e4baacd48ea65" - integrity sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ== - -"@rollup/rollup-win32-ia32-msvc@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz#516c4b54f80587b4a390aaf4940b40870271d35d" - integrity sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg== - -"@rollup/rollup-win32-x64-msvc@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz#848f99b0d9936d92221bb6070baeff4db6947a30" - integrity sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw== - "@tailwindcss/node@4.1.8": version "4.1.8" resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.8.tgz" @@ -875,73 +645,11 @@ source-map-js "^1.2.1" tailwindcss "4.1.8" -"@tailwindcss/oxide-android-arm64@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.8.tgz#4cb4b464636fc7e3154a1bb7df38a828291b3e9a" - integrity sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg== - "@tailwindcss/oxide-darwin-arm64@4.1.8": version "4.1.8" resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.8.tgz" integrity sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A== -"@tailwindcss/oxide-darwin-x64@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.8.tgz#d0f3fa4c3bde21a772e29e31c9739d91db79de12" - integrity sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw== - -"@tailwindcss/oxide-freebsd-x64@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.8.tgz#545c94c941007ed1aa2e449465501b70d59cb3da" - integrity sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg== - -"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.8.tgz#e1bdbf63a179081669b8cd1c9523889774760eb9" - integrity sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ== - -"@tailwindcss/oxide-linux-arm64-gnu@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.8.tgz#8d28093bbd43bdae771a2dcca720e926baa57093" - integrity sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q== - -"@tailwindcss/oxide-linux-arm64-musl@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.8.tgz#cc6cece814d813885ead9cd8b9d55aeb3db56c97" - integrity sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ== - -"@tailwindcss/oxide-linux-x64-gnu@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.8.tgz#4cac14fa71382574773fb7986d9f0681ad89e3de" - integrity sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g== - -"@tailwindcss/oxide-linux-x64-musl@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.8.tgz#e085f1ccbc8f97625773a6a3afc2a6f88edf59da" - integrity sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg== - -"@tailwindcss/oxide-wasm32-wasi@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.8.tgz#c5e19fffe67f25cabf12a357bba4e87128151ea0" - integrity sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@emnapi/wasi-threads" "^1.0.2" - "@napi-rs/wasm-runtime" "^0.2.10" - "@tybys/wasm-util" "^0.9.0" - tslib "^2.8.0" - -"@tailwindcss/oxide-win32-arm64-msvc@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.8.tgz#77521f23f91604c587736927fd2cb526667b7344" - integrity sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA== - -"@tailwindcss/oxide-win32-x64-msvc@4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.8.tgz#55c876ab35f8779d1dceec61483cd9834d7365ac" - integrity sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ== - "@tailwindcss/oxide@4.1.8": version "4.1.8" resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.8.tgz" @@ -987,13 +695,6 @@ resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz" integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA== -"@tybys/wasm-util@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" - integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== - dependencies: - tslib "^2.4.0" - "@types/babel__core@^7.20.5": version "7.20.5" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" @@ -1053,7 +754,7 @@ dependencies: "@types/estree" "*" -"@types/estree@*", "@types/estree@1.0.7", "@types/estree@^1.0.0", "@types/estree@^1.0.6": +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6", "@types/estree@1.0.7": version "1.0.7" resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz" integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== @@ -1087,7 +788,7 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== -"@types/node@^22.15.24": +"@types/node@^18.0.0 || ^20.0.0 || >=22.0.0", "@types/node@^22.15.24": version "22.15.24" resolved "https://registry.npmjs.org/@types/node/-/node-22.15.24.tgz" integrity sha512-w9CZGm9RDjzTh/D+hFwlBJ3ziUaVw7oufKA3vOFSOZlzmW9AkZnfjPb+DLnrV6qtgL/LNmP0/2zBNCFHL3F0ng== @@ -1129,7 +830,7 @@ resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@^19.1.2": +"@types/react@*", "@types/react@^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react@^18.2.25 || ^19", "@types/react@^19.0.0", "@types/react@^19.1.2", "@types/react@>=16.8", "@types/react@>=18", "@types/react@>=18.0.0": version "19.1.6" resolved "https://registry.npmjs.org/@types/react/-/react-19.1.6.tgz" integrity sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q== @@ -1148,7 +849,7 @@ dependencies: "@types/estree" "*" -"@types/three@*": +"@types/three@*", "@types/three@>=0.134.0": version "0.177.0" resolved "https://registry.npmjs.org/@types/three/-/three-0.177.0.tgz" integrity sha512-/ZAkn4OLUijKQySNci47lFO+4JLE1TihEjsGWPUT+4jWqxtwOPPEwJV1C3k5MEx0mcBPCdkFjzRzDOnHEI1R+A== @@ -1173,7 +874,7 @@ "@types/use-sync-external-store@^0.0.6": version "0.0.6" - resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc" + resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz" integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== "@types/webxr@*", "@types/webxr@^0.5.2": @@ -1196,7 +897,7 @@ natural-compare "^1.4.0" ts-api-utils "^2.1.0" -"@typescript-eslint/parser@8.33.0": +"@typescript-eslint/parser@^8.33.0", "@typescript-eslint/parser@8.33.0": version "8.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz" integrity sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ== @@ -1224,7 +925,7 @@ "@typescript-eslint/types" "8.33.0" "@typescript-eslint/visitor-keys" "8.33.0" -"@typescript-eslint/tsconfig-utils@8.33.0", "@typescript-eslint/tsconfig-utils@^8.33.0": +"@typescript-eslint/tsconfig-utils@^8.33.0", "@typescript-eslint/tsconfig-utils@8.33.0": version "8.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz" integrity sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug== @@ -1239,7 +940,7 @@ debug "^4.3.4" ts-api-utils "^2.1.0" -"@typescript-eslint/types@8.33.0", "@typescript-eslint/types@^8.33.0": +"@typescript-eslint/types@^8.33.0", "@typescript-eslint/types@8.33.0": version "8.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz" integrity sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg== @@ -1317,7 +1018,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.14.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0: version "8.14.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== @@ -1416,7 +1117,7 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.24.0: +browserslist@^4.24.0, "browserslist@>= 4.21.0": version "4.24.5" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz" integrity sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== @@ -1553,7 +1254,7 @@ convert-source-map@^2.0.0: cookie@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + resolved "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz" integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== cosmiconfig@^7.0.0: @@ -1585,7 +1286,7 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.6: css-box-model@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + resolved "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz" integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== dependencies: tiny-invariant "^1.0.6" @@ -1675,7 +1376,7 @@ earcut@^3.0.0: resolved "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz" integrity sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw== -easymde@^2.20.0: +easymde@^2.20.0, "easymde@>= 2.0.0 < 3.0.0": version "2.20.0" resolved "https://registry.npmjs.org/easymde/-/easymde-2.20.0.tgz" integrity sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ== @@ -1807,7 +1508,7 @@ eslint-visitor-keys@^4.2.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz" integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== -eslint@^9.25.0: +"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.25.0, eslint@>=8.40: version "9.27.0" resolved "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz" integrity sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q== @@ -2363,7 +2064,7 @@ its-fine@^2.0.0: dependencies: "@types/react-reconciler" "^0.28.9" -jiti@^2.4.2: +jiti@*, jiti@^2.4.2, jiti@>=1.21.0: version "2.4.2" resolved "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz" integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== @@ -2442,52 +2143,7 @@ lightningcss-darwin-arm64@1.30.1: resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz" integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== -lightningcss-darwin-x64@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" - integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== - -lightningcss-freebsd-x64@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" - integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== - -lightningcss-linux-arm-gnueabihf@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" - integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== - -lightningcss-linux-arm64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" - integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== - -lightningcss-linux-arm64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" - integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== - -lightningcss-linux-x64-gnu@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" - integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== - -lightningcss-linux-x64-musl@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" - integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== - -lightningcss-win32-arm64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" - integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== - -lightningcss-win32-x64-msvc@1.30.1: - version "1.30.1" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" - integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== - -lightningcss@1.30.1: +lightningcss@^1.21.0, lightningcss@1.30.1: version "1.30.1" resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz" integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== @@ -2950,7 +2606,7 @@ mobx-react-lite@^4.1.0: dependencies: use-sync-external-store "^1.4.0" -mobx@^6.13.7: +mobx@^6.13.7, mobx@^6.9.0: version "6.13.7" resolved "https://registry.npmjs.org/mobx/-/mobx-6.13.7.tgz" integrity sha512-aChaVU/DO5aRPmk1GX8L+whocagUUpBQqoPtJk+cm7UOXUk87J4PeWCh6nNmTTIfEhiR9DI/+FnA8dln/hTK7g== @@ -3109,7 +2765,7 @@ picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^4.0.2: +"picomatch@^3 || ^4", picomatch@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== @@ -3154,7 +2810,7 @@ promise-worker-transferable@^1.0.4: is-promise "^2.1.0" lie "^3.0.2" -prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.5.4, prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -3205,7 +2861,7 @@ quickselect@^3.0.0: raf-schd@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + resolved "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz" integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== rbush@^4.0.0: @@ -3215,7 +2871,12 @@ rbush@^4.0.0: dependencies: quickselect "^3.0.0" -react-dom@^19.1.0: +react-colorful@^5.6.1: + version "5.6.1" + resolved "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz" + integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== + +"react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18 || ^19", "react-dom@^18.0.0 || ^19.0.0", react-dom@^19, react-dom@^19.0.0, react-dom@^19.1.0, react-dom@>=16.0.0, react-dom@>=16.13, react-dom@>=16.6.0, react-dom@>=16.8.0, react-dom@>=16.8.2, react-dom@>=18: version "19.1.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz" integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== @@ -3274,7 +2935,7 @@ react-reconciler@^0.31.0: react-redux@^9.2.0: version "9.2.0" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5" + resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz" integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== dependencies: "@types/use-sync-external-store" "^0.0.6" @@ -3287,14 +2948,14 @@ react-refresh@^0.17.0: react-router-dom@^7.6.1: version "7.6.2" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.6.2.tgz#e97e386ab390b6503a2a7968124b7a3237fb10c7" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.2.tgz" integrity sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA== dependencies: react-router "7.6.2" react-router@7.6.2: version "7.6.2" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.6.2.tgz#9f48b343bead7d0a94e28342fc4f9ae29131520e" + resolved "https://registry.npmjs.org/react-router/-/react-router-7.6.2.tgz" integrity sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w== dependencies: cookie "^1.0.1" @@ -3329,14 +2990,14 @@ react-use-measure@^2.1.7: resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz" integrity sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg== -react@^19.1.0: +"react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18.0 || ^19", "react@^18.0.0 || ^19.0.0", react@^19, react@^19.0.0, react@^19.1.0, "react@>= 16.8 || 18.0.0", "react@>= 16.8.0", react@>=16.0.0, react@>=16.13, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=16.8.2, react@>=17.0, react@>=18, react@>=18.0.0: version "19.1.0" resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz" integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== -redux@^5.0.1: +redux@^5.0.0, redux@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz" integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== rehype-raw@^7.0.0: @@ -3374,6 +3035,11 @@ require-from-string@^2.0.2: resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +reselect@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz" + integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" @@ -3458,7 +3124,7 @@ semver@^7.6.0: set-cookie-parser@^2.6.0: version "2.7.1" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" + resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz" integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== shebang-command@^2.0.0: @@ -3550,7 +3216,7 @@ suspend-react@^0.1.3: resolved "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz" integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ== -tailwindcss@4.1.8, tailwindcss@^4.1.8: +tailwindcss@^4.1.8, "tailwindcss@>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1", tailwindcss@4.1.8: version "4.1.8" resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.8.tgz" integrity sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og== @@ -3599,14 +3265,14 @@ three@^0.175.0: resolved "https://registry.npmjs.org/three/-/three-0.175.0.tgz" integrity sha512-nNE3pnTHxXN/Phw768u0Grr7W4+rumGg/H6PgeseNJojkJtmeHJfZWi41Gp2mpXl1pg1pf1zjwR4McM1jTqkpg== -three@^0.177.0: +three@^0.177.0, "three@>= 0.159.0", three@>=0.125.0, three@>=0.126.1, three@>=0.128.0, three@>=0.134.0, three@>=0.137, three@>=0.156, three@>=0.159: version "0.177.0" resolved "https://registry.npmjs.org/three/-/three-0.177.0.tgz" integrity sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg== tiny-invariant@^1.0.6: version "1.3.3" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== tinyglobby@^0.2.13: @@ -3659,9 +3325,9 @@ ts-api-utils@^2.1.0: resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz" integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== -tslib@^2.4.0, tslib@^2.7.0, tslib@^2.8.0: +tslib@^2.7.0: version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== tunnel-rat@^0.1.2: @@ -3687,7 +3353,7 @@ typescript-eslint@^8.30.1: "@typescript-eslint/parser" "8.33.0" "@typescript-eslint/utils" "8.33.0" -typescript@~5.8.3: +typescript@>=4.8.4, "typescript@>=4.8.4 <5.9.0", typescript@~5.8.3: version "5.8.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== @@ -3768,7 +3434,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -use-sync-external-store@^1.2.2, use-sync-external-store@^1.4.0: +use-sync-external-store@^1.2.2, use-sync-external-store@^1.4.0, use-sync-external-store@^1.5.0, use-sync-external-store@>=1.2.0: version "1.5.0" resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz" integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A== @@ -3814,7 +3480,7 @@ vfile@^6.0.0: "@types/unist" "^3.0.0" vfile-message "^4.0.0" -vite@^6.3.5: +"vite@^4.2.0 || ^5.0.0 || ^6.0.0", "vite@^5.2.0 || ^6", vite@^6.3.5: version "6.3.5" resolved "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz" integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== @@ -3880,6 +3546,11 @@ yaml@^1.10.0: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.4.2: + version "2.8.0" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz" + integrity sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"