Compare commits

...

17 Commits

Author SHA1 Message Date
9a20c9f098 feat: rewrite the form to react-hook-form and add validation
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-02-03 00:06:16 +03:00
12982cdf9e Merge pull request 'feature/order-view-upgrade' (#75) from feature/order-view-upgrade into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #75
Reviewed-by: Primakov Alexandr Alexandrovich <primakovpro@gmail.com>
2025-02-02 13:34:10 +03:00
RustamRu
31b440656c feat: order view status polling feature (#74)
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-01-26 19:28:23 +03:00
RustamRu
45c4ca16c8 feat: use RTK Query to get order deails (#73) 2025-01-26 19:20:36 +03:00
e3d316c418 Merge pull request 'fix: fill location from autocomplete (#71)' (#72) from feature/order-form-upgrade into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #72
Reviewed-by: Primakov Alexandr Alexandrovich <primakovpro@gmail.com>
2025-01-26 15:59:57 +03:00
RustamRu
4c26928d23 fix: fill location from autocomplete (#71)
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-01-26 15:47:53 +03:00
1471bf94dd Merge pull request 'fix: option select (#55)' (#70) from feature/graphic-car-body-select into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #70
Reviewed-by: Primakov Alexandr Alexandrovich <primakovpro@gmail.com>
2025-01-26 15:26:03 +03:00
RustamRu
d3ffaa97f8 fix: option select (#55)
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-01-26 15:06:11 +03:00
acd09d427c fix: change endpoint order
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-26 12:48:54 +03:00
34bf557a6f fix: change endpoint orders
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-26 12:43:40 +03:00
5e0ac9f7a5 fix: change endpoint
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-26 12:36:42 +03:00
9a2ef18925 Merge pull request 'feat: add RTK for master' (#69) from feature/RTK into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #69
2025-01-26 12:25:44 +03:00
d15bd6f7d2 feat: add RTK for master
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-26 12:21:34 +03:00
adce5392a1 Merge pull request 'feat: add update status and masters (#67)' (#68) from feature/updateOrders into main
All checks were successful
it-academy/dry-wash-pl/pipeline/head This commit looks good
Reviewed-on: #68
2025-01-26 12:15:45 +03:00
1b01c0ba4f fix: add :id
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
it-academy/dry-wash-pl/pipeline/head This commit looks good
2025-01-26 11:08:43 +03:00
54ced18ea2 fix: eslint checks (#67)
All checks were successful
it-academy/dry-wash-pl/pipeline/pr-main This commit looks good
2025-01-25 17:15:41 +03:00
0ddcaa5d52 feat: add update status and masters (#67)
Some checks failed
it-academy/dry-wash-pl/pipeline/head There was a failure building this commit
it-academy/dry-wash-pl/pipeline/pr-main There was a failure building this commit
2025-01-25 17:12:02 +03:00
47 changed files with 946 additions and 541 deletions

View File

@@ -21,6 +21,7 @@ module.exports = {
features: { features: {
'dry-wash-pl': { 'dry-wash-pl': {
// add your features here in the format [featureName]: { value: string } // add your features here in the format [featureName]: { value: string }
'order-view-status-polling': { value: '3000' }
}, },
}, },
config: { config: {

View File

@@ -42,7 +42,7 @@
"dry-wash.order-create.create-order-query.success.title": "The order is successfully created", "dry-wash.order-create.create-order-query.success.title": "The order is successfully created",
"dry-wash.order-create.create-order-query.error.title": "Failed to create an order", "dry-wash.order-create.create-order-query.error.title": "Failed to create an order",
"dry-wash.order-view.title": "Your order", "dry-wash.order-view.title": "Your order",
"dry-wash.order-view.get-order-query.error.title": "Failed to fetch the details of order #{{number}}", "dry-wash.order-view.get-order-query.error.title": "Failed to fetch the details of order",
"dry-wash.order-view.details.title": "Order #{{number}}", "dry-wash.order-view.details.title": "Order #{{number}}",
"dry-wash.order-view.details.owner": "Owner", "dry-wash.order-view.details.owner": "Owner",
"dry-wash.order-view.details.car": "Car", "dry-wash.order-view.details.car": "Car",
@@ -58,7 +58,8 @@
"dry-wash.arm.order.status.pending": "Pending", "dry-wash.arm.order.status.pending": "Pending",
"dry-wash.arm.order.status.working": "Working", "dry-wash.arm.order.status.working": "Working",
"dry-wash.arm.order.status.canceled": "Canceled", "dry-wash.arm.order.status.canceled": "Canceled",
"dry-wash.arm.order.status.placeholder": "Select Status", "dry-wash.arm.order.status.placeholder": "Select status",
"dry-wash.arm.order.master.placeholder": "Select master",
"dry-wash.arm.order.table.header.carNumber": "Car Number", "dry-wash.arm.order.table.header.carNumber": "Car Number",
"dry-wash.arm.order.table.header.washingTime": "Washing Time", "dry-wash.arm.order.table.header.washingTime": "Washing Time",
"dry-wash.arm.order.table.header.orderDate": "Order Date", "dry-wash.arm.order.table.header.orderDate": "Order Date",
@@ -85,6 +86,15 @@
"dry-wash.arm.master.drawer.inputPhone.placeholder": "Enter Phone Number", "dry-wash.arm.master.drawer.inputPhone.placeholder": "Enter Phone Number",
"dry-wash.arm.master.drawer.button.save": "Save", "dry-wash.arm.master.drawer.button.save": "Save",
"dry-wash.arm.master.drawer.button.cancel": "Cancel", "dry-wash.arm.master.drawer.button.cancel": "Cancel",
"dry-wash.arm.master.drawer.toast.create-master": "Master created",
"dry-wash.arm.master.drawer.toast.error.empty-fields": "Fields cannot be empty",
"dry-wash.arm.master.drawer.toast.error.base": "Error",
"dry-wash.arm.master.drawer.toast.error.create-master": "Error creating master",
"dry-wash.arm.master.drawer.toast.error.create-master-details": "Failed to add master. Please try again",
"dry-wash.arm.master.drawer.form.name.required": "Master name is required",
"dry-wash.arm.master.drawer.form.phone.required": "Phone number is required",
"dry-wash.arm.master.drawer.form.phone.pattern": "Invalid phone number",
"dry-wash.arm.master.drawer.form.name.minLength": "Name must contain at least 2 characters",
"dry-wash.arm.master.sideBar.orders": "Orders", "dry-wash.arm.master.sideBar.orders": "Orders",
"dry-wash.arm.master.sideBar.master": "Masters", "dry-wash.arm.master.sideBar.master": "Masters",
"dry-wash.arm.master.sideBar.title": "Dry Master", "dry-wash.arm.master.sideBar.title": "Dry Master",

View File

@@ -7,6 +7,7 @@
"dry-wash.arm.order.status.working": "В работе", "dry-wash.arm.order.status.working": "В работе",
"dry-wash.arm.order.status.canceled": "Отменено", "dry-wash.arm.order.status.canceled": "Отменено",
"dry-wash.arm.order.status.placeholder": "Выберите статус", "dry-wash.arm.order.status.placeholder": "Выберите статус",
"dry-wash.arm.order.master.placeholder": "Выберите мастера",
"dry-wash.arm.order.table.header.carNumber": "Номер машины", "dry-wash.arm.order.table.header.carNumber": "Номер машины",
"dry-wash.arm.order.table.header.washingTime": "Время мойки", "dry-wash.arm.order.table.header.washingTime": "Время мойки",
"dry-wash.arm.order.table.header.orderDate": "Дата заказа", "dry-wash.arm.order.table.header.orderDate": "Дата заказа",
@@ -35,6 +36,15 @@
"dry-wash.arm.master.drawer.inputPhone.placeholder": "Введите номер телефона", "dry-wash.arm.master.drawer.inputPhone.placeholder": "Введите номер телефона",
"dry-wash.arm.master.drawer.button.save": "Сохранить", "dry-wash.arm.master.drawer.button.save": "Сохранить",
"dry-wash.arm.master.drawer.button.cancel": "Отменить", "dry-wash.arm.master.drawer.button.cancel": "Отменить",
"dry-wash.arm.master.drawer.toast.create-master": "Мастер создан",
"dry-wash.arm.master.drawer.toast.error.empty-fields": "Поля не могут быть пустыми",
"dry-wash.arm.master.drawer.toast.error.base": "Ошибка",
"dry-wash.arm.master.drawer.toast.error.create-master": "Ошибка при создании мастера",
"dry-wash.arm.master.drawer.toast.error.create-master-details": "Не удалось добавить мастера. Попробуйте еще раз",
"dry-wash.arm.master.drawer.form.name.required": "Имя мастера обязательно",
"dry-wash.arm.master.drawer.form.phone.required": "Телефон обязателен",
"dry-wash.arm.master.drawer.form.phone.pattern": "Некорректный номер телефона",
"dry-wash.arm.master.drawer.form.name.minLength": "Имя должно содержать минимум 2 символа",
"dry-wash.arm.master.sideBar.orders": "Заказы", "dry-wash.arm.master.sideBar.orders": "Заказы",
"dry-wash.arm.master.sideBar.master": "Мастера", "dry-wash.arm.master.sideBar.master": "Мастера",
"dry-wash.arm.master.sideBar.title": "Сухой мастер", "dry-wash.arm.master.sideBar.title": "Сухой мастер",
@@ -81,7 +91,7 @@
"dry-wash.order-create.create-order-query.success.title": "Заказ успешно создан", "dry-wash.order-create.create-order-query.success.title": "Заказ успешно создан",
"dry-wash.order-create.create-order-query.error.title": "Не удалось создать заказ", "dry-wash.order-create.create-order-query.error.title": "Не удалось создать заказ",
"dry-wash.order-view.title": "Ваш заказ", "dry-wash.order-view.title": "Ваш заказ",
"dry-wash.order-view.get-order-query.error.title": "Не удалось загрузить детали заказа №{{number}}", "dry-wash.order-view.get-order-query.error.title": "Не удалось загрузить детали заказа",
"dry-wash.order-view.details.title": "Заказ №{{number}}", "dry-wash.order-view.details.title": "Заказ №{{number}}",
"dry-wash.order-view.details.owner": "Владелец", "dry-wash.order-view.details.owner": "Владелец",
"dry-wash.order-view.details.car": "Автомобиль", "dry-wash.order-view.details.car": "Автомобиль",

548
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "0.5.0", "version": "0.5.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@brojs/cli": "^1.6.3", "@brojs/cli": "^1.8.4",
"@chakra-ui/icons": "^2.2.4", "@chakra-ui/icons": "^2.2.4",
"@chakra-ui/react": "^2.10.5", "@chakra-ui/react": "^2.10.5",
"@emotion/react": "^11.4.1", "@emotion/react": "^11.4.1",
@@ -17,6 +17,7 @@
"@fontsource/open-sans": "^5.1.0", "@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4", "@lottiefiles/react-lottie-player": "^3.5.4",
"@pbe/react-yandex-maps": "^1.2.5", "@pbe/react-yandex-maps": "^1.2.5",
"@reduxjs/toolkit": "^2.5.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"express": "^4.21.1", "express": "^4.21.1",
@@ -29,6 +30,7 @@
"react-i18next": "^15.1.1", "react-i18next": "^15.1.1",
"react-icons": "^5.3.0", "react-icons": "^5.3.0",
"react-phone-number-input": "^3.4.9", "react-phone-number-input": "^3.4.9",
"react-redux": "^9.2.0",
"react-router-dom": "^6.27.0" "react-router-dom": "^6.27.0"
}, },
"devDependencies": { "devDependencies": {
@@ -69,9 +71,10 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.26.2", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz",
"integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==",
"license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -106,12 +109,13 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.26.2", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz",
"integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.2", "@babel/parser": "^7.26.5",
"@babel/types": "^7.26.0", "@babel/types": "^7.26.5",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@@ -132,25 +136,13 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "node_modules/@babel/helper-compilation-targets": {
"version": "7.25.9", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz",
"integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/traverse": "^7.25.9", "@babel/compat-data": "^7.26.5",
"@babel/types": "^7.25.9"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz",
"integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==",
"dependencies": {
"@babel/compat-data": "^7.25.9",
"@babel/helper-validator-option": "^7.25.9", "@babel/helper-validator-option": "^7.25.9",
"browserslist": "^4.24.0", "browserslist": "^4.24.0",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",
@@ -190,13 +182,13 @@
} }
}, },
"node_modules/@babel/helper-create-regexp-features-plugin": { "node_modules/@babel/helper-create-regexp-features-plugin": {
"version": "7.25.9", "version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz",
"integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-annotate-as-pure": "^7.25.9",
"regexpu-core": "^6.1.1", "regexpu-core": "^6.2.0",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"engines": { "engines": {
@@ -276,9 +268,9 @@
} }
}, },
"node_modules/@babel/helper-plugin-utils": { "node_modules/@babel/helper-plugin-utils": {
"version": "7.25.9", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
"integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -302,14 +294,14 @@
} }
}, },
"node_modules/@babel/helper-replace-supers": { "node_modules/@babel/helper-replace-supers": {
"version": "7.25.9", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz",
"integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9",
"@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9",
"@babel/traverse": "^7.25.9" "@babel/traverse": "^7.26.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -318,19 +310,6 @@
"@babel/core": "^7.0.0" "@babel/core": "^7.0.0"
} }
}, },
"node_modules/@babel/helper-simple-access": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz",
"integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==",
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.25.9",
"@babel/types": "^7.25.9"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-skip-transparent-expression-wrappers": { "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.25.9", "version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
@@ -395,11 +374,12 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.2", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz",
"integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.0" "@babel/types": "^7.26.7"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -625,12 +605,12 @@
} }
}, },
"node_modules/@babel/plugin-transform-block-scoped-functions": { "node_modules/@babel/plugin-transform-block-scoped-functions": {
"version": "7.25.9", "version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz",
"integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9" "@babel/helper-plugin-utils": "^7.26.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -809,12 +789,11 @@
} }
}, },
"node_modules/@babel/plugin-transform-exponentiation-operator": { "node_modules/@babel/plugin-transform-exponentiation-operator": {
"version": "7.25.9", "version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz",
"integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9",
"@babel/helper-plugin-utils": "^7.25.9" "@babel/helper-plugin-utils": "^7.25.9"
}, },
"engines": { "engines": {
@@ -949,14 +928,13 @@
} }
}, },
"node_modules/@babel/plugin-transform-modules-commonjs": { "node_modules/@babel/plugin-transform-modules-commonjs": {
"version": "7.25.9", "version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz",
"integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-module-transforms": "^7.25.9", "@babel/helper-module-transforms": "^7.26.0",
"@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9"
"@babel/helper-simple-access": "^7.25.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1031,12 +1009,12 @@
} }
}, },
"node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
"version": "7.25.9", "version": "7.26.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz",
"integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9" "@babel/helper-plugin-utils": "^7.26.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1361,12 +1339,12 @@
} }
}, },
"node_modules/@babel/plugin-transform-typeof-symbol": { "node_modules/@babel/plugin-transform-typeof-symbol": {
"version": "7.25.9", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz",
"integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9" "@babel/helper-plugin-utils": "^7.26.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1376,14 +1354,14 @@
} }
}, },
"node_modules/@babel/plugin-transform-typescript": { "node_modules/@babel/plugin-transform-typescript": {
"version": "7.25.9", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.7.tgz",
"integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", "integrity": "sha512-5cJurntg+AT+cgelGP9Bt788DKiAw9gIMSMU2NJrLAilnj0m8WZWUNZPSLOmadYsujHutpgElO+50foX+ib/Wg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-annotate-as-pure": "^7.25.9",
"@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9",
"@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
"@babel/plugin-syntax-typescript": "^7.25.9" "@babel/plugin-syntax-typescript": "^7.25.9"
}, },
@@ -1458,14 +1436,14 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.26.0", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz",
"integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", "integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.26.0", "@babel/compat-data": "^7.26.5",
"@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-validator-option": "^7.25.9", "@babel/helper-validator-option": "^7.25.9",
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9",
"@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9",
@@ -1479,7 +1457,7 @@
"@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-arrow-functions": "^7.25.9",
"@babel/plugin-transform-async-generator-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.25.9",
"@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-async-to-generator": "^7.25.9",
"@babel/plugin-transform-block-scoped-functions": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.26.5",
"@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-block-scoping": "^7.25.9",
"@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9",
"@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-class-static-block": "^7.26.0",
@@ -1490,7 +1468,7 @@
"@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-keys": "^7.25.9",
"@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9",
"@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9",
"@babel/plugin-transform-exponentiation-operator": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.26.3",
"@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-export-namespace-from": "^7.25.9",
"@babel/plugin-transform-for-of": "^7.25.9", "@babel/plugin-transform-for-of": "^7.25.9",
"@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-function-name": "^7.25.9",
@@ -1499,12 +1477,12 @@
"@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9",
"@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9",
"@babel/plugin-transform-modules-amd": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9",
"@babel/plugin-transform-modules-commonjs": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3",
"@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-systemjs": "^7.25.9",
"@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9",
"@babel/plugin-transform-new-target": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6",
"@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-numeric-separator": "^7.25.9",
"@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9",
"@babel/plugin-transform-object-super": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9",
@@ -1521,7 +1499,7 @@
"@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9",
"@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9",
"@babel/plugin-transform-template-literals": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.25.9",
"@babel/plugin-transform-typeof-symbol": "^7.25.9", "@babel/plugin-transform-typeof-symbol": "^7.26.7",
"@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-escapes": "^7.25.9",
"@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9",
"@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9",
@@ -1555,9 +1533,9 @@
} }
}, },
"node_modules/@babel/preset-react": { "node_modules/@babel/preset-react": {
"version": "7.25.9", "version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz",
"integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9",
@@ -1618,15 +1596,16 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.25.9", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz",
"integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.25.9", "@babel/generator": "^7.26.5",
"@babel/parser": "^7.25.9", "@babel/parser": "^7.26.7",
"@babel/template": "^7.25.9", "@babel/template": "^7.25.9",
"@babel/types": "^7.25.9", "@babel/types": "^7.26.7",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@@ -1644,9 +1623,10 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.0", "version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz",
"integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9" "@babel/helper-validator-identifier": "^7.25.9"
@@ -1656,17 +1636,17 @@
} }
}, },
"node_modules/@brojs/cli": { "node_modules/@brojs/cli": {
"version": "1.6.3", "version": "1.8.4",
"resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.6.3/cli-1.6.3.tgz", "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fcli/-/1.8.4/cli-1.8.4.tgz",
"integrity": "sha512-noSKt8mxNFSV6fhRwmoyTX4lPELN5wSDBn1X/0JqCfiOdmzgMfzoWlGfUp752V/goWJyFumArc+s6x5vEqGrsw==", "integrity": "sha512-j/J3Obet8qP2yvXv0cpg9qhjbwIfU3iOFvLJWFRkUZ6enbMeR6lM/ixsj23nCLMphs/DPF/i21dVC27MhlZ3QQ==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@brojs/dev-server": "^1.6.3", "@brojs/dev-server": "^1.8.4",
"@brojs/fire.app": "^1.6.3", "@brojs/fire.app": "^1.6.3",
"@brojs/i18nextreactconfig": "^1.5.0", "@brojs/i18nextreactconfig": "^1.5.0",
"@brojs/templates": "^1.5.0", "@brojs/templates": "^1.5.0",
"@brojs/utils": "^1.5.0", "@brojs/utils": "^1.5.0",
"@brojs/webpack-config": "^1.5.0", "@brojs/webpack-config": "^1.8.3",
"axios": "^1.7.2", "axios": "^1.7.2",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"commander": "^12.1.0" "commander": "^12.1.0"
@@ -1676,15 +1656,15 @@
} }
}, },
"node_modules/@brojs/dev-server": { "node_modules/@brojs/dev-server": {
"version": "1.6.3", "version": "1.8.4",
"resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fdev-server/-/1.6.3/dev-server-1.6.3.tgz", "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fdev-server/-/1.8.4/dev-server-1.8.4.tgz",
"integrity": "sha512-pKDScQu2sSRNa7o9CVyfTU4mc37fdDpMQXvaT2/MW64kSqTcg1RczZIJGOD61/Uf+73DgDkZsO4gaXXboJceuQ==", "integrity": "sha512-nwMoRURSPOf5Yz6DVCV6ZB72Eyxq7dCxJ6cTb9Ef8U8mWwIRRjKrzN+v1ylezu7hLTaYpGlRC6bPyNJ8rdNp3g==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@brojs/fire.app": "^1.6.3", "@brojs/fire.app": "^1.6.3",
"@brojs/templates": "^1.5.0", "@brojs/templates": "^1.5.0",
"@brojs/utils": "^1.5.0", "@brojs/utils": "^1.5.0",
"@brojs/webpack-config": "^1.5.0", "@brojs/webpack-config": "^1.8.3",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cookie-session": "^2.1.0", "cookie-session": "^2.1.0",
"express-session": "^1.18.0", "express-session": "^1.18.0",
@@ -1751,9 +1731,9 @@
} }
}, },
"node_modules/@brojs/webpack-config": { "node_modules/@brojs/webpack-config": {
"version": "1.5.0", "version": "1.8.3",
"resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fwebpack-config/-/1.5.0/webpack-config-1.5.0.tgz", "resolved": "https://git.bro-js.ru/api/packages/bro-js/npm/%40brojs%2Fwebpack-config/-/1.8.3/webpack-config-1.8.3.tgz",
"integrity": "sha512-Qp7PEhv8Aw6K80BgAgpxhuHz2ypHsihVSjIM2wSVkHKxFl0kJaykJS1G0ON2bEqSE2Toeg1zP/c5B5Icf1pK6A==", "integrity": "sha512-PCWC10yKRWfrUX9kHKNiP5Uerfw/VYttPm1a5CIII4fYqi4AV9lFWBjvAs/W28pDgiOlPXue+n77DCgT3eR1tQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.21.0", "@babel/core": "^7.21.0",
@@ -1761,6 +1741,7 @@
"@babel/preset-react": "^7.18.6", "@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0", "@babel/preset-typescript": "^7.21.0",
"@brojs/utils": "^1.5.0", "@brojs/utils": "^1.5.0",
"@types/webpack-env": "^1.18.5",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.2",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
@@ -2524,9 +2505,9 @@
} }
}, },
"node_modules/@jsonjoy.com/json-pack": { "node_modules/@jsonjoy.com/json-pack": {
"version": "1.1.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.1.tgz",
"integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "integrity": "sha512-osjeBqMJ2lb/j/M8NCPjs1ylqWIcTRTycIhVB5pt6LgzgeRSb0YRZ7j9RfA8wIUrsr/medIuhVyonXRZWLyfdw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/base64": "^1.1.1",
@@ -2639,6 +2620,38 @@
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/@reduxjs/toolkit": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.0.tgz",
"integrity": "sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==",
"dependencies": {
"immer": "^10.0.3",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"reselect": "^5.1.0"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@reduxjs/toolkit/node_modules/immer": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
"integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.20.0", "version": "1.20.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz",
@@ -2766,12 +2779,12 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.9.0", "version": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.8" "undici-types": "~6.20.0"
} }
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
@@ -2802,6 +2815,17 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"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=="
},
"node_modules/@types/webpack-env": {
"version": "1.18.6",
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.6.tgz",
"integrity": "sha512-b32JtXK2UJHdXWUiNdIXxeAUXJu+FZG6HRMDNZu+o6QTzQ3dsDNR6Q7XQj5GD5skljXgb5zxc/+G/ZxkFKdlyg==",
"license": "MIT"
},
"node_modules/@types/yandex-maps": { "node_modules/@types/yandex-maps": {
"version": "2.1.29", "version": "2.1.29",
"resolved": "https://registry.npmjs.org/@types/yandex-maps/-/yandex-maps-2.1.29.tgz", "resolved": "https://registry.npmjs.org/@types/yandex-maps/-/yandex-maps-2.1.29.tgz",
@@ -3840,9 +3864,9 @@
} }
}, },
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.24.2", "version": "4.24.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
"integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -3857,10 +3881,11 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001669", "caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.41", "electron-to-chromium": "^1.5.73",
"node-releases": "^2.0.18", "node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.1" "update-browserslist-db": "^1.1.1"
}, },
"bin": { "bin": {
@@ -3911,9 +3936,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001669", "version": "1.0.30001695",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
"integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -3927,7 +3952,8 @@
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
] ],
"license": "CC-BY-4.0"
}, },
"node_modules/chalk": { "node_modules/chalk": {
"version": "5.3.0", "version": "5.3.0",
@@ -4200,12 +4226,12 @@
} }
}, },
"node_modules/core-js-compat": { "node_modules/core-js-compat": {
"version": "3.39.0", "version": "3.40.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz",
"integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"browserslist": "^4.24.2" "browserslist": "^4.24.3"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -4602,9 +4628,10 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.41", "version": "1.5.88",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz",
"integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==" "integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==",
"license": "ISC"
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "9.2.2", "version": "9.2.2",
@@ -4621,9 +4648,9 @@
} }
}, },
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.17.1", "version": "5.18.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"graceful-fs": "^4.2.4", "graceful-fs": "^4.2.4",
@@ -4757,9 +4784,9 @@
} }
}, },
"node_modules/es-module-lexer": { "node_modules/es-module-lexer": {
"version": "1.5.4", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
@@ -5581,9 +5608,19 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-uri": { "node_modules/fast-uri": {
"version": "3.0.3", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/fastq": { "node_modules/fastq": {
@@ -6041,6 +6078,20 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -7577,9 +7628,9 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -7635,9 +7686,10 @@
} }
}, },
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.18", "version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"license": "MIT"
}, },
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
@@ -8147,9 +8199,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.49", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -8166,7 +8218,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.8",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
@@ -8187,9 +8239,9 @@
} }
}, },
"node_modules/postcss-modules-local-by-default": { "node_modules/postcss-modules-local-by-default": {
"version": "4.1.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz",
"integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"icss-utils": "^5.0.0", "icss-utils": "^5.0.0",
@@ -8735,6 +8787,28 @@
"react-dom": ">=16.8" "react-dom": ">=16.8"
} }
}, },
"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==",
"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-remove-scroll": { "node_modules/react-remove-scroll": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
@@ -8892,6 +8966,19 @@
"recursive-watch": "bin.js" "recursive-watch": "bin.js"
} }
}, },
"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=="
},
"node_modules/redux-thunk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
"peerDependencies": {
"redux": "^5.0.0"
}
},
"node_modules/reflect.getprototypeof": { "node_modules/reflect.getprototypeof": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
@@ -8966,15 +9053,15 @@
} }
}, },
"node_modules/regexpu-core": { "node_modules/regexpu-core": {
"version": "6.1.1", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
"integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerate": "^1.4.2", "regenerate": "^1.4.2",
"regenerate-unicode-properties": "^10.2.0", "regenerate-unicode-properties": "^10.2.0",
"regjsgen": "^0.8.0", "regjsgen": "^0.8.0",
"regjsparser": "^0.11.0", "regjsparser": "^0.12.0",
"unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-ecmascript": "^2.0.0",
"unicode-match-property-value-ecmascript": "^2.1.0" "unicode-match-property-value-ecmascript": "^2.1.0"
}, },
@@ -8989,9 +9076,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/regjsparser": { "node_modules/regjsparser": {
"version": "0.11.2", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
"integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"jsesc": "~3.0.2" "jsesc": "~3.0.2"
@@ -9009,6 +9096,11 @@
"node": ">=0.10.0" "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=="
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.8", "version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -9147,9 +9239,9 @@
} }
}, },
"node_modules/schema-utils": { "node_modules/schema-utils": {
"version": "4.2.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.9", "@types/json-schema": "^7.0.9",
@@ -9158,7 +9250,7 @@
"ajv-keywords": "^5.1.0" "ajv-keywords": "^5.1.0"
}, },
"engines": { "engines": {
"node": ">= 12.13.0" "node": ">= 10.13.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@@ -9309,10 +9401,13 @@
} }
}, },
"node_modules/shell-quote": { "node_modules/shell-quote": {
"version": "1.8.1", "version": "1.8.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
"integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
"license": "MIT", "license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@@ -9669,9 +9764,9 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.36.0", "version": "5.37.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz",
"integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
@@ -9687,16 +9782,16 @@
} }
}, },
"node_modules/terser-webpack-plugin": { "node_modules/terser-webpack-plugin": {
"version": "5.3.10", "version": "5.3.11",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/trace-mapping": "^0.3.20", "@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5", "jest-worker": "^27.4.5",
"schema-utils": "^3.1.1", "schema-utils": "^4.3.0",
"serialize-javascript": "^6.0.1", "serialize-javascript": "^6.0.2",
"terser": "^5.26.0" "terser": "^5.31.1"
}, },
"engines": { "engines": {
"node": ">= 10.13.0" "node": ">= 10.13.0"
@@ -9720,55 +9815,6 @@
} }
} }
}, },
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"license": "MIT",
"peerDependencies": {
"ajv": "^6.9.1"
}
},
"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"license": "MIT"
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/terser/node_modules/commander": { "node_modules/terser/node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -10107,9 +10153,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.19.8", "version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/unicode-canonical-property-names-ecmascript": { "node_modules/unicode-canonical-property-names-ecmascript": {
@@ -10249,6 +10295,14 @@
} }
} }
}, },
"node_modules/use-sync-external-store": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -10307,16 +10361,16 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
}, },
"node_modules/webpack": { "node_modules/webpack": {
"version": "5.96.1", "version": "5.97.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
"integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/eslint-scope": "^3.7.7", "@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6", "@types/estree": "^1.0.6",
"@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/ast": "^1.14.1",
"@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.14.1",
"@webassemblyjs/wasm-parser": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.14.0", "acorn": "^8.14.0",
"browserslist": "^4.24.0", "browserslist": "^4.24.0",
"chrome-trace-event": "^1.0.2", "chrome-trace-event": "^1.0.2",
@@ -10382,9 +10436,9 @@
} }
}, },
"node_modules/webpack-dev-middleware/node_modules/memfs": { "node_modules/webpack-dev-middleware/node_modules/memfs": {
"version": "4.14.0", "version": "4.17.0",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.0.tgz",
"integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", "integrity": "sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/json-pack": "^1.0.3",

View File

@@ -17,7 +17,7 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@brojs/cli": "^1.6.3", "@brojs/cli": "^1.8.4",
"@chakra-ui/icons": "^2.2.4", "@chakra-ui/icons": "^2.2.4",
"@chakra-ui/react": "^2.10.5", "@chakra-ui/react": "^2.10.5",
"@emotion/react": "^11.4.1", "@emotion/react": "^11.4.1",
@@ -25,6 +25,7 @@
"@fontsource/open-sans": "^5.1.0", "@fontsource/open-sans": "^5.1.0",
"@lottiefiles/react-lottie-player": "^3.5.4", "@lottiefiles/react-lottie-player": "^3.5.4",
"@pbe/react-yandex-maps": "^1.2.5", "@pbe/react-yandex-maps": "^1.2.5",
"@reduxjs/toolkit": "^2.5.0",
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"express": "^4.21.1", "express": "^4.21.1",
@@ -37,6 +38,7 @@
"react-i18next": "^15.1.1", "react-i18next": "^15.1.1",
"react-icons": "^5.3.0", "react-icons": "^5.3.0",
"react-phone-number-input": "^3.4.9", "react-phone-number-input": "^3.4.9",
"react-redux": "^9.2.0",
"react-router-dom": "^6.27.0" "react-router-dom": "^6.27.0"
}, },
"devDependencies": { "devDependencies": {

15
src/__data__/features.ts Normal file
View File

@@ -0,0 +1,15 @@
import { getFeatures } from "@brojs/cli";
const features = getFeatures('dry-wash-pl');
export const FEATURE = {
orderViewStatusPolling: {
isOn: Boolean(features['order-view-status-polling']),
getValue: () => {
const interval = parseInt(features['order-view-status-polling'].value);
if (!Number.isNaN(interval)) {
return interval;
}
}
}
};

View File

@@ -0,0 +1,27 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { getConfigValue } from '@brojs/cli';
import { Master } from '../../models/api/master';
import { extractBodyFromResponse } from './utils';
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: getConfigValue('dry-wash.api') }),
tagTypes: ['Masters'],
endpoints: (builder) => ({
getMasters: builder.query<Master[], void>({
query: () => ({ url: '/arm/masters' }),
transformResponse: extractBodyFromResponse<Master[]>,
providesTags: ['Masters'],
}),
addMaster: builder.mutation<void, Pick<Master, 'name' | 'phone'>>({
query: (master) => ({
url: '/arm/masters',
method: 'POST',
body: master,
}),
invalidatesTags: ['Masters'],
}),
}),
});

View File

@@ -0,0 +1,14 @@
import { GetOrder } from "../../models/api";
import { api } from "./api";
import { extractBodyFromResponse, extractErrorMessageFromResponse } from "./utils";
export const landingApi = api.injectEndpoints({
endpoints: ({ query }) => ({
getOrder: query<GetOrder.Response, GetOrder.Params>({
query: ({ orderId }) => `/order/${orderId}`,
transformResponse: extractBodyFromResponse<GetOrder.Response>,
transformErrorResponse: extractErrorMessageFromResponse,
})
})
});

View File

@@ -0,0 +1,15 @@
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { BaseResponse } from "../../models/api";
export const extractBodyFromResponse = <Body>(response: BaseResponse<Body>) => {
if (response.success) {
return response.body;
}
};
export const extractErrorMessageFromResponse = ({ data }: FetchBaseQueryError) => {
if (typeof data === 'object' && 'message' in data && typeof data.message === 'string') {
return data.message;
}
};

14
src/__data__/store.ts Normal file
View File

@@ -0,0 +1,14 @@
import { configureStore } from '@reduxjs/toolkit';
import { api } from './service/api';
export const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(api.middleware),
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

View File

@@ -72,6 +72,34 @@ const armService = () => {
return await response.json(); return await response.json();
}; };
const updateOrders = async ({
id,
status,
notes,
masterId,
}: {
id: string;
status?: string;
notes?: string;
masterId?: string;
}) => {
const body = JSON.stringify({ status, notes, masterId });
const response = await fetch(`${endpoint}/order/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body,
});
if (!response.ok) {
throw new Error(`Failed to fetch update masters: ${response.status}`);
}
return await response.json();
};
const updateMaster = async ({ const updateMaster = async ({
id, id,
name, name,
@@ -98,7 +126,14 @@ const armService = () => {
return await response.json(); return await response.json();
}; };
return { fetchOrders, fetchMasters, addMaster, deleteMaster, updateMaster }; return {
fetchOrders,
fetchMasters,
addMaster,
deleteMaster,
updateMaster,
updateOrders,
};
}; };
export { armService, ArmEndpoints }; export { armService, ArmEndpoints };

View File

@@ -1,12 +1,11 @@
import { getConfigValue } from '@brojs/cli'; import { getConfigValue } from '@brojs/cli';
import { useEffect, useState } from 'react'; import { useState } from 'react';
import { CreateOrder, GetOrder } from '../models/api'; import { CreateOrder } from '../models/api';
import { QueryState, Trigger } from './types'; import { QueryState, Trigger } from './types';
enum LandingEndpoints { enum LandingEndpoints {
ORDER = '/order',
ORDER_CREATE = '/order/create', ORDER_CREATE = '/order/create',
} }
@@ -63,45 +62,4 @@ const useCreateOrderMutation = <D extends CreateOrder.Response>(): [
return [createOrder, { isLoading, isSuccess, data, isError, error }]; return [createOrder, { isLoading, isSuccess, data, isError, error }];
}; };
const useGetOrderQuery = <D extends GetOrder.Response>({ export { useCreateOrderMutation };
orderId,
}: GetOrder.Params): QueryState<D> => {
const [isLoading, setIsLoading] = useState<QueryState<D>['isLoading']>(true);
const [isSuccess, setIsSuccess] = useState<QueryState<D>['isSuccess']>();
const [data, setData] = useState<QueryState<D>['data']>();
const [isError, setIsError] = useState<QueryState<D>['isError']>();
const [error, setError] = useState<QueryState<D>['error']>();
useEffect(() => {
(async () => {
try {
const response = await fetch(
`${endpoint}${LandingEndpoints.ORDER}/${orderId}`,
);
if (!response.ok) {
const errorResponseObject =
(await response.json()) as QueryState<D>['error'];
setIsError(true);
setError(errorResponseObject);
throw errorResponseObject;
}
const dataResponseObject =
(await response.json()) as QueryState<D>['data'];
setIsSuccess(true);
setData(dataResponseObject);
} catch (error) {
setIsError(true);
setError(error);
throw error;
} finally {
setIsLoading(false);
}
})();
}, []);
return { isLoading, isSuccess, data, isError, error };
};
export { useCreateOrderMutation, useGetOrderQuery };

View File

@@ -1,19 +1,23 @@
import React from 'react'; import React from 'react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { ChakraProvider, theme as chakraTheme } from '@chakra-ui/react'; import { ChakraProvider, theme as chakraTheme } from '@chakra-ui/react';
import { Provider } from 'react-redux';
import Routers from './routes'; import Routers from './routes';
import ErrorBoundary from './components/ErrorBoundary'; import ErrorBoundary from './components/ErrorBoundary';
import { store } from './__data__/store';
const App = () => { const App = () => {
return ( return (
<ChakraProvider theme={chakraTheme}> <Provider store={store}>
<ErrorBoundary> <ChakraProvider theme={chakraTheme}>
<BrowserRouter> <ErrorBoundary>
<Routers /> <BrowserRouter>
</BrowserRouter> <Routers />
</ErrorBoundary> </BrowserRouter>
</ChakraProvider> </ErrorBoundary>
</ChakraProvider>
</Provider>
); );
}; };

View File

@@ -3,6 +3,7 @@ export { default as CrossoverImg } from './crossover.webp';
export { default as HatchbackImg } from './hatchback.webp'; export { default as HatchbackImg } from './hatchback.webp';
export { default as LiftbackImg } from './liftback.webp'; export { default as LiftbackImg } from './liftback.webp';
export { default as MinivanImg } from './minivan.webp'; export { default as MinivanImg } from './minivan.webp';
export { default as OtherImg } from './other.webp';
export { default as PickupImg } from './pickup.webp'; export { default as PickupImg } from './pickup.webp';
export { default as SedanImg } from './sedan.webp'; export { default as SedanImg } from './sedan.webp';
export { default as SportsCarImg } from './sports-car.webp'; export { default as SportsCarImg } from './sports-car.webp';

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,4 +1,5 @@
import React, { useState } from 'react'; import React, { useEffect } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { import {
Button, Button,
FormControl, FormControl,
@@ -14,95 +15,136 @@ import {
useToast, useToast,
InputGroup, InputGroup,
InputLeftElement, InputLeftElement,
FormErrorMessage,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PhoneIcon } from '@chakra-ui/icons'; import { PhoneIcon } from '@chakra-ui/icons';
import { armService } from '../../api/arm'; import { api } from '../../__data__/service/api';
import showToast from '../../helpers/showToast';
import { DrawerInputs } from '../../models/arm/form';
const MasterDrawer = ({ isOpen, onClose }) => { interface MasterDrawerProps {
const { addMaster } = armService(); isOpen: boolean;
const toast = useToast(); onClose: () => void;
}
const [newMaster, setNewMaster] = useState({ name: '', phone: '' }); const MasterDrawer = ({ isOpen, onClose }: MasterDrawerProps) => {
const {
const handleSave = async () => { register,
if (newMaster.name.trim() === '' || newMaster.phone.trim() === '') { handleSubmit,
return; reset,
} formState: { errors },
} = useForm<DrawerInputs>();
try {
await addMaster(newMaster);
toast({
title: 'Мастер создан.',
description: `Мастер "${newMaster.name}" успешно добавлен.`,
status: 'success',
duration: 5000,
isClosable: true,
position: 'top-right',
});
onClose();
} catch (error) {
toast({
title: 'Ошибка при создании мастера.',
description: 'Не удалось добавить мастера. Попробуйте еще раз.',
status: 'error',
duration: 5000,
isClosable: true,
position: 'top-right',
});
console.error(error);
}
};
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.master.drawer', keyPrefix: 'dry-wash.arm.master.drawer',
}); });
const onSubmit: SubmitHandler<DrawerInputs> = async (data) => {
const trimMaster = {
name: data.name.trim(),
phone: data.phone.trim(),
};
const isEmptyFields = trimMaster.name === '' || trimMaster.phone === '';
if (isEmptyFields) {
showToast({
toast,
title: t('toast.error.base'),
description: t('toast.error.empty-fields'),
status: 'error',
});
return;
}
await addMaster(trimMaster);
};
const [addMaster, { error, isSuccess }] = api.useAddMasterMutation();
const toast = useToast();
useEffect(() => {
if (isSuccess) {
showToast({
toast,
title: t('toast.create-master'),
status: 'success',
});
reset();
onClose();
}
}, [isSuccess]);
useEffect(() => {
if (error) {
showToast({
toast,
title: t('toast.error.create-master'),
description: t('toast.error.create-master-details'),
status: 'error',
});
console.error(error);
}
}, [error]);
return ( return (
<Drawer isOpen={isOpen} onClose={onClose} size='md'> <Drawer isOpen={isOpen} onClose={onClose} size='md'>
<DrawerOverlay /> <DrawerOverlay />
<DrawerContent> <DrawerContent>
<DrawerCloseButton /> <form onSubmit={handleSubmit(onSubmit)}>
<DrawerHeader>{t('title')}</DrawerHeader> <DrawerCloseButton />
<DrawerBody> <DrawerHeader>{t('title')}</DrawerHeader>
<FormControl mb='4'> <DrawerBody>
<FormLabel>{t('inputName.label')}</FormLabel> <FormControl mb='4' isInvalid={!!errors.name}>
<Input <FormLabel>{t('inputName.label')}</FormLabel>
// isInvalid
value={newMaster.name}
onChange={(e) =>
setNewMaster({ ...newMaster, name: e.target.value })
}
placeholder={t('inputName.placeholder')}
/>
</FormControl>
<FormControl>
<FormLabel>{t('inputPhone.label')}</FormLabel>
<InputGroup>
<InputLeftElement pointerEvents='none'>
<PhoneIcon color='gray.300' />
</InputLeftElement>
<Input <Input
// isInvalid {...register('name', {
value={newMaster.phone} required: t('form.name.required'),
onChange={(e) => minLength: {
setNewMaster({ ...newMaster, phone: e.target.value }) value: 2,
} message: t('form.name.minLength'),
placeholder={t('inputPhone.placeholder')} },
})}
placeholder={t('inputName.placeholder')}
/> />
</InputGroup> <FormErrorMessage>
</FormControl> {errors.name && errors.name.message}
</DrawerBody> </FormErrorMessage>
<DrawerFooter> </FormControl>
<Button colorScheme='teal' mr={3} onClick={handleSave}> <FormControl isInvalid={!!errors.phone}>
{t('button.save')} <FormLabel>{t('inputPhone.label')}</FormLabel>
</Button> <InputGroup>
<Button variant='ghost' onClick={onClose}> <InputLeftElement pointerEvents='none'>
{t('button.cancel')} <PhoneIcon color='gray.300' />
</Button> </InputLeftElement>
</DrawerFooter> <Input
{...register('phone', {
required: t('form.phone.required'),
pattern: {
value: /^(\+7|8)\d{10}$/,
message: t('form.phone.pattern'),
},
setValueAs: (value) => value.replace(/[^\d+]/g, ''),
})}
placeholder={t('inputPhone.placeholder')}
/>
</InputGroup>
<FormErrorMessage>
{errors.phone && errors.phone.message}
</FormErrorMessage>
</FormControl>
</DrawerBody>
<DrawerFooter>
<Button colorScheme='teal' mr={3} type='submit'>
{t('button.save')}
</Button>
<Button variant='ghost' onClick={onClose}>
{t('button.cancel')}
</Button>
</DrawerFooter>
</form>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
); );

View File

@@ -7,19 +7,6 @@ import { getTimeSlot } from '../../lib';
import EditableWrapper from '../Editable/Editable'; import EditableWrapper from '../Editable/Editable';
import { armService } from '../../api/arm'; import { armService } from '../../api/arm';
export interface Schedule {
id: string;
startWashTime: string;
endWashTime: string;
}
export type MasterProps = {
id: string;
name: string;
phone: string;
schedule: Schedule[];
};
const MasterItem = ({ name, phone, id, schedule }) => { const MasterItem = ({ name, phone, id, schedule }) => {
const { updateMaster } = armService(); const { updateMaster } = armService();
const { t } = useTranslation('~', { const { t } = useTranslation('~', {

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect } from 'react';
import { import {
Box, Box,
Heading, Heading,
@@ -19,8 +19,7 @@ import { useTranslation } from 'react-i18next';
import MasterItem from '../MasterItem'; import MasterItem from '../MasterItem';
import MasterDrawer from '../MasterDrawer'; import MasterDrawer from '../MasterDrawer';
import { armService } from '../../api/arm'; import { api } from '../../__data__/service/api';
import { MasterProps } from '../MasterItem/MasterItem';
const TABLE_HEADERS = [ const TABLE_HEADERS = [
'name' as const, 'name' as const,
@@ -36,35 +35,23 @@ const Masters = () => {
keyPrefix: 'dry-wash.arm.master', keyPrefix: 'dry-wash.arm.master',
}); });
const [masters, setMasters] = useState<MasterProps[]>([]); const {
const [loading, setLoading] = useState(false); data: masters,
const [error, setError] = useState<string | null>(null); error,
isLoading,
const { fetchMasters } = armService(); isSuccess,
} = api.useGetMastersQuery();
useEffect(() => { useEffect(() => {
const loadMasters = async () => { if (error) {
setLoading(true); toast({
title: t('error.title'),
try { status: 'error',
const data = await fetchMasters(); isClosable: true,
setMasters(data.body); position: 'bottom-right',
} catch (err) { });
setError(err.message); }
toast({ }, [error]);
title: t('error.title'),
status: 'error',
duration: 5000,
isClosable: true,
position: 'bottom-right',
});
} finally {
setLoading(false);
}
};
loadMasters();
}, [toast, t]);
return ( return (
<Box p='8'> <Box p='8'>
@@ -83,22 +70,21 @@ const Masters = () => {
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{loading && ( {isLoading && (
<Tr> <Tr>
<Td colSpan={TABLE_HEADERS.length} textAlign='center' py='8'> <Td colSpan={TABLE_HEADERS.length} textAlign='center' py='8'>
<Spinner size='lg' /> <Spinner size='lg' />
</Td> </Td>
</Tr> </Tr>
)} )}
{!loading && masters.length === 0 && !error && ( {isSuccess && masters.length === 0 && (
<Tr> <Tr>
<Td colSpan={TABLE_HEADERS.length}> <Td colSpan={TABLE_HEADERS.length}>
<Text>{t('table.empty')}</Text> <Text>{t('table.empty')}</Text>
</Td> </Td>
</Tr> </Tr>
)} )}
{!loading && {isSuccess &&
!error &&
masters.map((master, index) => ( masters.map((master, index) => (
<MasterItem key={index} {...master} /> <MasterItem key={index} {...master} />
))} ))}

View File

@@ -1,10 +1,11 @@
import React, { useState } from 'react'; import React, { ChangeEvent, useState } from 'react';
import { Td, Tr, Link, Select } from '@chakra-ui/react'; import { Td, Tr, Link, Select } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { MasterProps } from '../MasterItem/MasterItem';
import { getTimeSlot } from '../../lib'; import { getTimeSlot } from '../../lib';
import { Master } from '../../models/api/master';
import { armService } from '../../api/arm';
const statuses = [ const statuses = [
'pending' as const, 'pending' as const,
@@ -25,9 +26,10 @@ export type OrderProps = {
status?: GetArrItemType<typeof statuses>; status?: GetArrItemType<typeof statuses>;
phone?: string; phone?: string;
location?: string; location?: string;
master: MasterProps; master: Master;
notes: ''; notes: '';
allMasters: MasterProps[]; allMasters: Master[];
id: string;
}; };
type Status = (typeof statuses)[number]; type Status = (typeof statuses)[number];
@@ -50,7 +52,10 @@ const OrderItem = ({
location, location,
master, master,
allMasters, allMasters,
id,
}: OrderProps) => { }: OrderProps) => {
const { updateOrders } = armService();
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.arm.order', keyPrefix: 'dry-wash.arm.order',
}); });
@@ -59,15 +64,37 @@ const OrderItem = ({
const bgColor = statusColors[statusSelect]; const bgColor = statusColors[statusSelect];
const [masterSelect, setMaster] = useState(master?.name); const [masterSelect, setMaster] = useState(master?.name);
const handelChangeMasters = (e: ChangeEvent<HTMLSelectElement>) => {
const masterName = e.target.value;
const selectedMaster = allMasters.find(
(master) => master.name === masterName,
);
if (selectedMaster) {
setMaster(masterName);
updateOrders({ id, masterId: selectedMaster.id });
} else {
console.error('Master not found');
}
};
const handeChangeStatus = (e: ChangeEvent<HTMLSelectElement>) => {
const status = e.target.value;
updateOrders({ id, status });
setStatus(e.target.value as OrderProps['status']);
};
return ( return (
<Tr> <Tr>
<Td>{carNumber}</Td> <Td>{carNumber}</Td>
<Td>{getTimeSlot(startWashTime, endWashTime)}</Td> <Td>
<Td>{dayjs(orderDate).format('DD.MM.YYYY')}</Td> {dayjs(orderDate).format('DD.MM.YYYY')} <br />
{getTimeSlot(startWashTime, endWashTime)}
</Td>
<Td> <Td>
<Select <Select
value={statusSelect} value={statusSelect}
onChange={(e) => setStatus(e.target.value as OrderProps['status'])} onChange={handeChangeStatus}
placeholder={t(`status.placeholder`)} placeholder={t(`status.placeholder`)}
bg={bgColor} bg={bgColor}
> >
@@ -81,8 +108,8 @@ const OrderItem = ({
<Td> <Td>
<Select <Select
value={masterSelect} value={masterSelect}
onChange={(e) => setMaster(e.target.value as OrderProps['status'])} onChange={handelChangeMasters}
placeholder={t(`status.placeholder`)} placeholder={t(`master.placeholder`)}
> >
{allMasters.map((item) => ( {allMasters.map((item) => (
<option key={item.id} value={item.name}> <option key={item.id} value={item.name}>

View File

@@ -19,11 +19,10 @@ import OrderItem from '../OrderItem';
import { OrderProps } from '../OrderItem/OrderItem'; import { OrderProps } from '../OrderItem/OrderItem';
import { armService } from '../../api/arm'; import { armService } from '../../api/arm';
import DateNavigator from '../DateNavigator'; import DateNavigator from '../DateNavigator';
import { MasterProps } from '../MasterItem/MasterItem'; import { Master } from '../../models/api/master';
const TABLE_HEADERS = [ const TABLE_HEADERS = [
'carNumber' as const, 'carNumber' as const,
'washingTime' as const,
'orderDate' as const, 'orderDate' as const,
'status' as const, 'status' as const,
'masters' as const, 'masters' as const,
@@ -42,7 +41,7 @@ const Orders = () => {
const toast = useToast(); const toast = useToast();
const [orders, setOrders] = useState<OrderProps[]>([]); const [orders, setOrders] = useState<OrderProps[]>([]);
const [allMasters, setAllMasters] = useState<MasterProps[]>([]); const [allMasters, setAllMasters] = useState<Master[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date());

View File

@@ -1,34 +1,38 @@
import React, { forwardRef, useState } from 'react'; import React, { forwardRef } from 'react';
import { import {
Input, Input,
Image,
InputProps,
Box, Box,
Popover, Popover,
PopoverAnchor, PopoverAnchor,
PopoverContent, PopoverContent,
PopoverBody, PopoverBody,
List, useRadioGroup,
ListItem, Grid,
GridItem,
UseRadioGroupProps,
useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { carBodySelectOptions } from './helper'; import { carBodySelectOptions, getInputValue } from './helper';
import { CarBodySelectOption } from './types'; import { CarBodyOption } from './option';
import { CarBodySelectProps } from './types';
export const CarBodySelect = forwardRef<HTMLInputElement, InputProps>( export const CarBodySelect = forwardRef<HTMLInputElement, CarBodySelectProps>(
function CarBodySelect(props, ref) { function CarBodySelect(props, ref) {
const initialOption = carBodySelectOptions.find(({ value }) => value === Number(props.value)); const handleOptionClick: UseRadioGroupProps['onChange'] = (value) => {
const [selected, setSelected] = useState<Partial<CarBodySelectOption>>(initialOption);
const handleOptionClick = (option: CarBodySelectOption) => {
setSelected(option);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
props.onChange(option.value); props.onChange(value);
}; };
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false); const { value, getRadioProps, getRootProps } = useRadioGroup({
defaultValue: props.value,
value: props.value,
onChange: handleOptionClick,
});
const { isOpen, onOpen, onClose } = useDisclosure();
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
keyPrefix: 'dry-wash.order-create.car-body-select', keyPrefix: 'dry-wash.order-create.car-body-select',
@@ -37,7 +41,7 @@ export const CarBodySelect = forwardRef<HTMLInputElement, InputProps>(
return ( return (
<Box width='100%'> <Box width='100%'>
<Popover <Popover
isOpen={isDropdownOpen} isOpen={isOpen}
autoFocus={false} autoFocus={false}
placement='bottom-start' placement='bottom-start'
matchWidth matchWidth
@@ -46,45 +50,29 @@ export const CarBodySelect = forwardRef<HTMLInputElement, InputProps>(
<Input <Input
{...props} {...props}
ref={ref} ref={ref}
value={ value={getInputValue(Number(value), t) ?? props.value}
selected?.labelTKey
? t(`options.${selected.labelTKey}`)
: undefined
}
readOnly readOnly
onClick={() => setIsDropdownOpen(true)} onClick={onOpen}
onBlur={() => setIsDropdownOpen(false)} onBlur={onClose}
placeholder={t('placeholder')} placeholder={t('placeholder')}
/> />
</PopoverAnchor> </PopoverAnchor>
<PopoverContent width='100%' maxWidth='100%'> <PopoverContent width='100%' maxWidth='100%'>
<PopoverBody border='1px' borderColor='gray.300' p={0}> <PopoverBody border='1px' borderColor='gray.300' p={0}>
<List <Grid
display='grid' templateColumns='repeat(auto-fit, minmax(150px, 1fr))'
gridTemplateColumns='repeat(auto-fit, minmax(150px, 1fr))' {...getRootProps()}
> >
{carBodySelectOptions.map((option) => ( {carBodySelectOptions.map(({ value, img, labelTKey }) => (
<ListItem <GridItem key={value}>
key={option.value} <CarBodyOption
display='flex' image={img}
flexDirection='column' label={t(`options.${labelTKey}`)}
justifyContent='flex-end' {...getRadioProps({ value: String(value) })}
alignItems='center' />
p={2} </GridItem>
cursor='pointer'
_hover={{
bgColor: 'primary.50',
}}
_active={{
bgColor: 'primary.100',
}}
onClick={() => handleOptionClick(option)}
>
<Image src={option.img} />
{t(`options.${option.labelTKey}`)}
</ListItem>
))} ))}
</List> </Grid>
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Popover> </Popover>

View File

@@ -1,3 +1,6 @@
import { TFunction } from "i18next";
import { InputProps } from "@chakra-ui/react";
import { import {
CoupeImg, CoupeImg,
CrossoverImg, CrossoverImg,
@@ -8,7 +11,8 @@ import {
SedanImg, SedanImg,
SportsCarImg, SportsCarImg,
StationWagonImg, StationWagonImg,
SuvImg SuvImg,
OtherImg
} from "../../../../assets/images"; } from "../../../../assets/images";
import { Car } from "../../../../models/landing"; import { Car } from "../../../../models/landing";
@@ -67,6 +71,17 @@ export const carBodySelectOptions: CarBodySelectOption[] = [
}, },
{ {
value: Car.BodyStyle.OTHER, value: Car.BodyStyle.OTHER,
labelTKey: 'other' labelTKey: 'other',
img: OtherImg
}, },
]; ];
export const getInputValue = (value: Car.BodyStyle, t: TFunction<"~", "dry-wash.order-create.car-body-select">): InputProps['value'] => {
const { labelTKey } = carBodySelectOptions.find((option) => value === option.value) ?? {};
if (labelTKey) {
return t(`options.${labelTKey}`);
}
return;
};

View File

@@ -0,0 +1,39 @@
import React from 'react';
import {
ImageProps,
StackProps,
Image,
useRadio,
chakra,
Box,
UseRadioProps,
Flex,
} from '@chakra-ui/react';
import { getPropsByState } from './helper';
type CarBodyOptionProps = {
image: ImageProps['src'];
label: StackProps['children'];
} & UseRadioProps;
export const CarBodyOption = ({
image,
label,
...radioProps
}: CarBodyOptionProps) => {
const { state, getInputProps, getRadioProps, htmlProps, getLabelProps } =
useRadio(radioProps);
return (
<chakra.label {...htmlProps} cursor='pointer'>
<input {...getInputProps({})} hidden />
<Box {...getRadioProps()} p={2} {...getPropsByState(state)}>
<Flex direction='column' alignItems='center' {...getLabelProps()}>
<Image src={image} rounded={4} />
{label}
</Flex>
</Box>
</chakra.label>
);
};

View File

@@ -0,0 +1,19 @@
import {
BoxProps,
} from '@chakra-ui/react';
import { RadioState } from '@chakra-ui/react/dist/types/radio/use-radio';
export const getPropsByState = ({ isChecked }: RadioState): BoxProps => {
if (isChecked) {
return {
bgColor: 'primary.200',
_hover: { bgColor: 'primary.100' },
_active: { bgColor: 'primary.300' },
};
}
return {
_hover: { bgColor: 'primary.50' },
_active: { bgColor: 'primary.100' },
};
};

View File

@@ -0,0 +1 @@
export { CarBodyOption } from './car-body-option';

View File

@@ -1,3 +1,5 @@
import { InputProps } from "@chakra-ui/react";
import { Car } from "../../../../models/landing"; import { Car } from "../../../../models/landing";
export type CarBodySelectOption = { export type CarBodySelectOption = {
@@ -16,3 +18,7 @@ export type CarBodySelectOption = {
'other'; 'other';
img?: string; img?: string;
}; };
export type CarBodySelectProps = {
value?: string;
} & Pick<InputProps, 'onChange'>;

View File

@@ -9,6 +9,7 @@ export const defaultValues: Partial<OrderFormValues> = {
phone: '', phone: '',
carNumber: '', carNumber: '',
carColor: '', carColor: '',
carBody: '',
availableDatetimeBegin: '', availableDatetimeBegin: '',
availableDatetimeEnd: '', availableDatetimeEnd: '',
}; };

View File

@@ -42,21 +42,29 @@ export const LocationInput = memo(
const onInputChange: InputProps['onChange'] = async (e) => { const onInputChange: InputProps['onChange'] = async (e) => {
const newInputValue = e.target.value; const newInputValue = e.target.value;
setInputValue(newInputValue);
if (newInputValue.trim().length > 3) { if (
try { isValidLocation(newInputValue) &&
const address = extractAddress(newInputValue); (await isRealLocation(ymaps, newInputValue))
const results = await ymaps.suggest(address); ) {
setSuggestions(results); onChange(newInputValue);
} catch (error) {
console.error(error);
}
} else { } else {
setSuggestions([]); setInputValue(newInputValue);
if (newInputValue.trim().length > 3) {
try {
const address = extractAddress(newInputValue);
const results = await ymaps.suggest(address);
setSuggestions(results);
} catch (error) {
console.error(error);
}
} else {
setSuggestions([]);
}
setIsSuggestionsPanelOpen(suggestions.length > 1);
} }
setIsSuggestionsPanelOpen(suggestions.length > 1);
}; };
const onFocus: InputProps['onFocus'] = () => { const onFocus: InputProps['onFocus'] = () => {
@@ -103,7 +111,7 @@ export const LocationInput = memo(
{...props} {...props}
ref={ref} ref={ref}
onBlur={onBlur} onBlur={onBlur}
value={inputValue} value={inputValue ?? value}
onChange={onInputChange} onChange={onInputChange}
onFocus={onFocus} onFocus={onFocus}
placeholder={t('placeholder')} placeholder={t('placeholder')}

View File

@@ -19,7 +19,7 @@ import { OrderStatus } from './status';
type OrderDetailsProps = Pick< type OrderDetailsProps = Pick<
Order.View, Order.View,
| 'id' | 'orderNumber'
| 'status' | 'status'
| 'phone' | 'phone'
| 'carNumber' | 'carNumber'
@@ -32,7 +32,7 @@ type OrderDetailsProps = Pick<
>; >;
export const OrderDetails: FC<OrderDetailsProps> = ({ export const OrderDetails: FC<OrderDetailsProps> = ({
id, orderNumber,
status, status,
phone, phone,
carNumber, carNumber,
@@ -58,7 +58,7 @@ export const OrderDetails: FC<OrderDetailsProps> = ({
gap={2} gap={2}
> >
<Heading as='h2' size='lg'> <Heading as='h2' size='lg'>
{t('title', { number: id })} {t('title', { number: orderNumber })}
</Heading> </Heading>
<OrderStatus value={status} /> <OrderStatus value={status} />
</HStack> </HStack>

View File

@@ -15,19 +15,19 @@ const getPropsByStatus = (
colorScheme: 'red', colorScheme: 'red',
children: t('canceled'), children: t('canceled'),
}; };
case 'progress':
return {
colorScheme: 'yellow',
children: t('progress'),
};
case 'pending': case 'pending':
return { return {
colorScheme: 'yellow', colorScheme: 'yellow',
children: t('pending'), children: t('pending'),
}; };
case 'progress':
return {
colorScheme: 'orange',
children: t('progress'),
};
case 'working': case 'working':
return { return {
colorScheme: 'yellow', colorScheme: 'orange',
children: t('working'), children: t('working'),
}; };
case 'complete': case 'complete':

21
src/helpers/showToast.ts Normal file
View File

@@ -0,0 +1,21 @@
import { UseToastOptions } from '@chakra-ui/react';
interface ShowToast {
toast: (options: UseToastOptions) => void;
title: string;
description?: string;
status: 'info' | 'warning' | 'success' | 'error';
}
const showToast = ({ toast, title, description, status }: ShowToast) => {
toast({
title,
description,
status,
duration: 5000,
isClosable: true,
position: 'top-right',
});
};
export default showToast;

13
src/models/api/common.ts Normal file
View File

@@ -0,0 +1,13 @@
type SuccessResponse<Body> = {
success: true;
body: Body;
};
export type ErrorMessage = string;
type ErrorResponse = {
success: false;
message: ErrorMessage;
};
export type BaseResponse<Body> = SuccessResponse<Body> | ErrorResponse;

View File

@@ -1 +1,2 @@
export * from './common';
export * from './order'; export * from './order';

12
src/models/api/master.ts Normal file
View File

@@ -0,0 +1,12 @@
export interface Schedule {
id: string;
startWashTime: string;
endWashTime: string;
}
export type Master = {
id: string;
name: string;
phone: string;
schedule: Schedule[];
};

View File

@@ -1,6 +1,16 @@
/* eslint-disable @typescript-eslint/no-namespace */ /* eslint-disable @typescript-eslint/no-namespace */
import { Order } from "../landing"; import { Order } from "../landing";
import { ErrorMessage } from "./common";
export namespace GetOrder {
export type Response = Order.View;
export type Params = {
orderId: Order.Id
};
export type Error = ErrorMessage;
}
export namespace CreateOrder { export namespace CreateOrder {
export type Response = { export type Response = {
id: Order.Id id: Order.Id
@@ -8,11 +18,4 @@ export namespace CreateOrder {
export type Params = { export type Params = {
body: Order.Create body: Order.Create
}; };
};
export namespace GetOrder {
export type Response = Order.View;
export type Params = {
orderId: Order.Id
};
}; };

4
src/models/arm/form.ts Normal file
View File

@@ -0,0 +1,4 @@
export type DrawerInputs = {
phone: string;
name: string;
};

View File

@@ -26,6 +26,8 @@ export type Create = {
} }
}; };
export type Number = string;
export type View = { export type View = {
phone: Customer.PhoneNumber; phone: Customer.PhoneNumber;
carNumber: Car.RegistrationNumber; carNumber: Car.RegistrationNumber;
@@ -34,6 +36,7 @@ export type View = {
location: Washing.Location; location: Washing.Location;
startWashTime: Washing.AvailableBeginDateTime; startWashTime: Washing.AvailableBeginDateTime;
endWashTime: Washing.AvailableEndDateTime; endWashTime: Washing.AvailableEndDateTime;
orderNumber: Number,
status: Status, status: Status,
notes: string; notes: string;
created: IsoDate; created: IsoDate;

View File

@@ -1,5 +1,13 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { Alert, AlertDescription, AlertIcon, AlertTitle, HStack, Spinner } from '@chakra-ui/react'; import {
Alert,
AlertDescription,
AlertIcon,
AlertTitle,
Box,
HStack,
Spinner,
} from '@chakra-ui/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Container, Heading, VStack } from '@chakra-ui/react'; import { Container, Heading, VStack } from '@chakra-ui/react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
@@ -10,7 +18,9 @@ import {
} from '../../containers'; } from '../../containers';
import { OrderDetails } from '../../components/order-view'; import { OrderDetails } from '../../components/order-view';
import { Order } from '../../models/landing'; import { Order } from '../../models/landing';
import { useGetOrderQuery } from '../../api'; import { landingApi } from '../../__data__/service/landing.api';
import { ErrorMessage } from '../../models/api';
import { FEATURE } from '../../__data__/features';
const Page: FC = () => { const Page: FC = () => {
const { t } = useTranslation('~', { const { t } = useTranslation('~', {
@@ -21,12 +31,21 @@ const Page: FC = () => {
const { const {
isLoading, isLoading,
isSuccess, isSuccess,
data: { body: order } = {}, data: order,
isError, isError,
error, error,
} = useGetOrderQuery({ } = landingApi.useGetOrderQuery(
orderId, {
}); orderId,
},
FEATURE.orderViewStatusPolling.isOn
? {
pollingInterval: FEATURE.orderViewStatusPolling.getValue(),
skipPollingIfUnfocused: true,
}
: undefined,
);
const errorMessage = error as ErrorMessage;
return ( return (
<LandingThemeProvider> <LandingThemeProvider>
@@ -51,7 +70,7 @@ const Page: FC = () => {
<> <>
{isSuccess && ( {isSuccess && (
<OrderDetails <OrderDetails
id={order.id} orderNumber={order.orderNumber}
status={order.status} status={order.status}
phone={order.phone} phone={order.phone}
carNumber={order.carNumber} carNumber={order.carNumber}
@@ -66,14 +85,14 @@ const Page: FC = () => {
</> </>
<> <>
{isError && ( {isError && (
<Alert status='error'> <Alert status='error' alignItems='flex-start'>
<AlertIcon /> <AlertIcon />
<AlertTitle> <Box>
{t('get-order-query.error.title', { <AlertTitle>
number: orderId, {t('get-order-query.error.title')}
})} </AlertTitle>
</AlertTitle> <AlertDescription>{errorMessage}</AlertDescription>
<AlertDescription>{error.data?.error}</AlertDescription> </Box>
</Alert> </Alert>
)} )}
</> </>

View File

@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-require-imports */ /* eslint-disable @typescript-eslint/no-require-imports */
const router = require('express').Router(); const router = require('express').Router();
const STUBS = { masters: 'success', orders: 'success', orderView: 'success' }; const STUBS = { masters: 'success', orders: 'success', orderView: 'success-pending' };
router.get('/set/:name/:value', (req, res) => { router.get('/set/:name/:value', (req, res) => {
const { name, value } = req.params; const { name, value } = req.params;
@@ -18,15 +18,18 @@ router.get('/', (req, res) => {
<legend>Мастера</legend> <legend>Мастера</legend>
${generateRadioInput('masters', 'success')} ${generateRadioInput('masters', 'success')}
${generateRadioInput('masters', 'error')} ${generateRadioInput('masters', 'error')}
${generateRadioInput('masters', 'empty')}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Заказы</legend> <legend>Заказы</legend>
${generateRadioInput('orders', 'success')} ${generateRadioInput('orders', 'success')}
${generateRadioInput('orders', 'error')} ${generateRadioInput('orders', 'error')}
${generateRadioInput('orders', 'empty')}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Лендинг - Детали заказа</legend> <legend>Лендинг - Детали заказа</legend>
${generateRadioInput('orderView', 'success')} ${generateRadioInput('orderView', 'success-pending')}
${generateRadioInput('orderView', 'success-working')}
${generateRadioInput('orderView', 'error')} ${generateRadioInput('orderView', 'error')}
</fieldset> </fieldset>
</div>`); </div>`);
@@ -40,4 +43,4 @@ function generateRadioInput(name, type) {
<input ${STUBS[name] === type ? 'checked' : ''} onclick="fetch('/api/admin/set/${name}/${type}')" type="radio" name="${name}"> <input ${STUBS[name] === type ? 'checked' : ''} onclick="fetch('/api/admin/set/${name}/${type}')" type="radio" name="${name}">
${type} ${type}
</label>`; </label>`;
} }

View File

@@ -53,6 +53,16 @@ router.delete('/arm/masters/:id', (req, res) => {
); );
}); });
router.patch('/orders/:id', (req, res) => {
res
.status(/error/.test(STUBS.orders) ? 500 : 200)
.send(
/^error$/.test(STUBS.orders)
? commonError
: require(`../json/arm-orders/${STUBS.orders}.json`),
);
});
router.post('/arm/orders', (req, res) => { router.post('/arm/orders', (req, res) => {
res res
.status(/error/.test(STUBS.orders) ? 500 : 200) .status(/error/.test(STUBS.orders) ? 500 : 200)
@@ -77,9 +87,7 @@ router.get('/order/:orderId', ({ params }, res) => {
}); });
router.post('/order/create', (req, res) => { router.post('/order/create', (req, res) => {
res res.status(200).send({ success: true, body: { ok: true } });
.status(200)
.send({ success: true, body: { ok: true } });
}); });
router.use('/admin', require('./admin')); router.use('/admin', require('./admin'));

View File

@@ -0,0 +1,4 @@
{
"success": true,
"body": []
}

View File

@@ -6,9 +6,14 @@
"name": "Иван Иванов", "name": "Иван Иванов",
"phone": "+7 900 123 45 67" "phone": "+7 900 123 45 67"
}, },
{
"name": "Олег Макаров",
"phone": "79001234567",
"id": "23423442"
},
{ {
"id": "345354234", "id": "345354234",
"name": "Иван Иванов", "name": "Иван Галкин",
"schedule": [ { "schedule": [ {
"id": "order1", "id": "order1",
"startWashTime": "2024-11-24T10:30:00.000Z", "startWashTime": "2024-11-24T10:30:00.000Z",

View File

@@ -0,0 +1,4 @@
{
"success": true,
"body": []
}

View File

@@ -7,10 +7,14 @@
"startWashTime": "2024-11-24T10:30:00.000Z", "startWashTime": "2024-11-24T10:30:00.000Z",
"endWashTime": "2024-11-24T16:30:00.000Z", "endWashTime": "2024-11-24T16:30:00.000Z",
"orderDate": "2024-11-24T08:41:46.366Z", "orderDate": "2024-11-24T08:41:46.366Z",
"status": "progress", "status": "pending",
"phone": "79001234563", "phone": "79001234563",
"location": "Казань, ул. Баумана, 1", "location": "Казань, ул. Баумана, 1",
"master": [], "master": {
"name": "Олег Макаров",
"phone": "79001234567",
"id": "23423442"
},
"notes": "" "notes": ""
}, },
{ {

View File

@@ -0,0 +1,4 @@
{
"success": false,
"message": "Не удалось загрузить детали заказа"
}

View File

@@ -8,10 +8,11 @@
"startWashTime": "2025-01-19T14:03:00.000Z", "startWashTime": "2025-01-19T14:03:00.000Z",
"endWashTime": "2025-01-19T14:03:00.000Z", "endWashTime": "2025-01-19T14:03:00.000Z",
"location": "55.793833888711006,49.19037910644527 Республика Татарстан (Татарстан), Казань, жилой район Седьмое Небо", "location": "55.793833888711006,49.19037910644527 Республика Татарстан (Татарстан), Казань, жилой район Седьмое Небо",
"status": "progress", "orderNumber": "1",
"status": "pending",
"notes": "", "notes": "",
"created": "2025-01-19T14:04:02.985Z", "created": "2025-01-19T14:04:02.985Z",
"updated": "2025-01-19T14:04:02.987Z", "updated": "2025-01-19T14:04:02.987Z",
"id": "678d06527d78ec30be2679d8" "id": "id1"
} }
} }

View File

@@ -0,0 +1,18 @@
{
"success": true,
"body": {
"phone": "+79876543210",
"carNumber": "А123АА16",
"carBody": 2,
"carColor": "#ffffff",
"startWashTime": "2025-01-19T14:03:00.000Z",
"endWashTime": "2025-01-19T14:03:00.000Z",
"location": "55.793833888711006,49.19037910644527 Республика Татарстан (Татарстан), Казань, жилой район Седьмое Небо",
"orderNumber": "1",
"status": "working",
"notes": "",
"created": "2025-01-19T14:04:02.985Z",
"updated": "2025-01-19T14:04:02.987Z",
"id": "id1"
}
}