commit c5aee9e2ece88ea94858b86cb48c0ca3839cae1f Author: Possible Date: Thu Apr 3 17:05:59 2025 +0100 Update | Project Ready diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..1cf0c6c Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..615c01e --- /dev/null +++ b/README.md @@ -0,0 +1,130 @@ +# PARADISE DOCK BUILDER + +## SETUP Process + +- You are expected to clone this repository and set up a new repo remotely on ur github with the code (Preferably name the repo with your name. E.g john_doe_paradise_dock_builder_solution) + To set up locally + + - **a.** clone the repo to your local machine + - **a.** update remote origin + - **b.** install dependencies (using -- "npm install") + - **b.** run locally on your computer using this command - "npm run dev" + +- Make sure to commit each fix with a valid message entailing what issue was fixed in the commit. This will help when grading your solution + +- When you are done, cross check all fixes and then submit the repo that has your solutions. + +- Any commit after your submmission will be discarded and won't be graded. + +- PLEASE make sure to deploy the app to a live server, to allow full test by the Development team and the Quality Assurance Team (preferably netlify or vercel) + +## Table of Contents + +1. [Dock Category](#dock-category) +2. [Dock Data](#dock-data) +3. [Issues](#issues) + +## Dock Category + +- **Dock Category** is a category of the docks. + - **Dock Category** can be one of the following: + - **ROLL-IN** + - **FLOATING** + - **SECTIONAL** + - **WEDGES** + - **RAMPS** + - **BOAT LIFE LIFTS (2 CYLINDER)** + - **BOAT LIFE LIFTS (4 CYLINDER)** + - **ACCESSORIES** + +## Dock Data + +- **Dock Data** is the collection of all the docks information + - docks is as follows: { + itemName: activeDockCategory (ROLL-IN, FLOATING, SECTIONAL, WEDGES, RAMPS, BOAT LIFTS (2 CYLINDER), BOAT LIFTS (4 CYLINDER), ACCESSORIES) + image: dock?.image, + category: category, + length: dock?.length, + materials: materials, + top_view: dock?.top_view, + width: dock?.width, + lift_range: dock?.lift_range, + model: dock?.model, + no_of_cylinders: dock?.no_of_cylinders, + name: dock?.name, + thumbnail: dock?.thumbnail, + weight_capacity: dock?.weight_capacity + }; + - this information is to be attached to every dock that is added into the canvas editor as `dockData` + +#### The Issues Are Listed Below + +1. On the sidebar, each dock is listed as tablets with names and dimensions or size, and when you click on a dock, it will is added to the canvas editor + + Now the issue here is that is doesn't work + + Please fix this issue. (Tip - An onDockSelect handles this in Builder.jsx file) + +2. CopySelection Functionality is not working + Expected Behavior: When you click on the copy button, the selected object in the canvas editor should be copied to the clipboard + Actual Behavior: The selected object is not copied to the clipboard + + Please fix this issue. + +3. PasteSelection Functionality is not working + Expected Behavior: When you click on the paste button, the selected object in the clipboard should be pasted to the canvas editor + Actual Behavior: The selected object is not pasted to the canvas editor + + Please fix this issue. + +4. onRedoClick Functionality is not working + Expected Behavior: When you click on the redo button, the last undone action should be redone + Actual Behavior: The last undone action is not redone + + Please fix this issue. + +5. onUndoClick Functionality is not working + Expected Behavior: When you click on the undo button, the last action should be undone + Actual Behavior: The last action is not undone + + Please fix this issue. + +6. onPrintScreen Functionality is not working + Expected Behavior: When you click on the print screen button, the canvas editor should be printed + Actual Behavior: The canvas editor is not printed + + Please fix this issue. + +7. onDeleteSelection Functionality is not working + Expected Behavior: When you click on the delete button, the selected object in the canvas editor should be deleted + Actual Behavior: The selected object is not deleted + + Please fix this issue. + +8. on the sidebar the downloadImage function is not working + + Expected Behavior: When you click on the download button, the selected dock should be downloaded as a png file and also trigger the download of the dockData you extracted in excel format + Actual Behavior: The selected dock is not downloaded as a png file + + Please fix this issue. + +9. on the sidebar onDownloadFile triggers toJSON function + + Expected Behavior: When you click on the download button, the canvas editor content is downloaded as a json file + Actual Behavior: Nothing happens when you click on the download button + + Please fix this issue. + +10. on the sidebar, the onUploadFile triigers uploadFile function + + Expected Behavior: When you click on the upload button, the json file we had previously downloaded should be uploaded, its data extracted and loaded into the editor + Actual Behavior: Nothing happens when you click on the upload button + + Please fix this issue. + +11. Finally, objects in the canvas editor of the category DockPanelCategories.Accessories, DockPanelCategories.BoatLift2, DockPanelCategories.BoatLift4, when being moved, should snap to the nearest snap point of other objects of any the above listed categories + + Expected Behavior: When you move an object in the canvas editor of the category DockPanelCategories.Accessories, DockPanelCategories.BoatLift2, DockPanelCategories.BoatLift4, it should snap to the nearest snap point of other objects of any the above listed categories + Actual Behavior: Objects in the canvas editor of the category DockPanelCategories.Accessories, DockPanelCategories.BoatLift2, DockPanelCategories.BoatLift4 are not snapping to the nearest snap point of other objects of any the above listed categories + + Please fix this issue. diff --git a/boat_lifts.sql b/boat_lifts.sql new file mode 100644 index 0000000..0731ab9 --- /dev/null +++ b/boat_lifts.sql @@ -0,0 +1,52 @@ +-- Adminer 4.6.2 MySQL dump + +SET NAMES utf8; +SET time_zone = '+00:00'; +SET foreign_key_checks = 0; +SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; + +DROP TABLE IF EXISTS `paralift_boat_lifts`; +CREATE TABLE `paralift_boat_lifts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `create_at` date NOT NULL, + `update_at` datetime NOT NULL, + `model` varchar(255) NOT NULL, + `weight_capacity` float NOT NULL, + `lift_range` int(11) NOT NULL, + `no_of_cylinders` int(11) NOT NULL, + `length` float DEFAULT NULL, + `width` float DEFAULT NULL, + `image` longtext NOT NULL, + `top_view` longtext NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + +INSERT INTO `paralift_boat_lifts` (`id`, `create_at`, `update_at`, `model`, `weight_capacity`, `lift_range`, `no_of_cylinders`, `length`, `width`, `image`, `top_view`) VALUES +(8, '2022-11-17', '2022-11-17 18:25:37', 'PH-2K-4', 2000, 4, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(9, '2022-11-17', '2022-11-17 18:28:51', 'PH-2K-5', 2000, 5, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(10, '2022-11-17', '2022-11-17 18:27:02', 'PH-2K-6', 2000, 6, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(11, '2022-11-17', '2022-11-17 18:27:29', 'PH-6.5K-4', 6500, 4, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(12, '2022-11-17', '2022-11-17 18:27:57', 'PH-6K-5', 6000, 5, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(13, '2022-11-17', '2022-11-17 18:28:32', 'PH-6K-6', 6000, 6, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(14, '2022-11-17', '2022-11-17 18:29:25', 'PH-8.5K-4', 8500, 4, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(15, '2022-11-17', '2022-11-17 18:29:53', 'PH-8K-5', 8000, 5, 2, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/2%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(16, '2022-11-17', '2022-11-17 18:33:12', 'PH-8K-6', 8000, 6, 4, 14.84, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-6%2C8K-4%2C5%2C6.png'), +(17, '2022-11-17', '2022-11-17 18:37:36', 'PH-11K-4S', 1100, 4, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(20, '2022-11-17', '2022-11-17 18:55:35', 'PH-11K-4', 11000, 4, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(21, '2022-11-17', '2022-11-17 18:56:18', 'PH-10K-5', 10000, 5, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(22, '2022-11-17', '2022-11-17 18:57:25', 'PH-10K-6', 10000, 6, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(23, '2022-11-17', '2022-11-17 18:59:12', 'PH-13K-4', 13000, 4, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(24, '2022-11-17', '2022-11-17 18:59:39', 'PH-12K-5', 12000, 5, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(25, '2022-11-17', '2022-11-17 19:00:36', 'PH-12K-6', 12000, 6, 4, 16.85, 11.3, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-10%2C12K-4%2C5%2C6.png'), +(26, '2022-11-17', '2022-11-17 19:05:57', 'PH-15K-4', 15000, 4, 4, 20.95, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-15K-4%2C5%2C6.png'), +(27, '2022-11-17', '2022-11-17 19:06:47', 'PH-15K-5', 15000, 5, 4, 20.95, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-15K-4%2C5%2C6.png'), +(28, '2022-11-17', '2022-11-17 19:07:28', 'PH-15K-6', 15000, 6, 4, 20.95, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-15K-4%2C5%2C6.png'), +(29, '2022-11-17', '2022-11-17 19:08:30', 'PH-20K-4', 20000, 4, 4, 22.86, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-20K-4%2C5%2C6.png'), +(30, '2022-11-17', '2022-11-17 19:09:09', 'PH-20K-5', 20000, 5, 4, 22.86, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-20K-4%2C5%2C6.png'), +(31, '2022-11-17', '2022-11-17 19:10:21', 'PH-20K-6', 20000, 6, 4, 22.86, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-20K-4%2C5%2C6.png'), +(32, '2022-11-17', '2022-11-17 19:11:09', 'PH-24K-4', 24000, 4, 4, 25.03, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-24K-4%2C5%2C6.png'), +(33, '2022-11-17', '2022-11-17 19:12:07', 'PH-24K-5', 24000, 5, 4, 25.03, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-24K-4%2C5%2C6.png'), +(34, '2022-11-17', '2022-11-17 19:12:37', 'PH-24K-6', 24000, 6, 4, 25.03, 12.41, 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/4%20Cylinder%20Boat%20Lift-min.png', 'https://s3.us-west-1.amazonaws.com/com.mkdlab.images/PH-24K-4%2C5%2C6.png') +ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `create_at` = VALUES(`create_at`), `update_at` = VALUES(`update_at`), `model` = VALUES(`model`), `weight_capacity` = VALUES(`weight_capacity`), `lift_range` = VALUES(`lift_range`), `no_of_cylinders` = VALUES(`no_of_cylinders`), `length` = VALUES(`length`), `width` = VALUES(`width`), `image` = VALUES(`image`), `top_view` = VALUES(`top_view`); + +-- 2025-04-02 18:13:38 diff --git a/index.html b/index.html new file mode 100644 index 0000000..9d950f5 --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + + + + Paradise Dock + + + + +
+ + + + \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..243270c --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "jsx": "react", + "baseUrl": ".", + "paths": { + "Components/*": [ + "src/components/*" + ], + "Pages/*": [ + "src/pages/*" + ], + "Utils/*": [ + "src/utils/*" + ], + "Assets/*": [ + "src/assets/*" + ], + "Src/*": [ + "src/*" + ], + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..33e21f3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5235 @@ +{ + "name": "adminportal", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "adminportal", + "version": "0.0.0", + "dependencies": { + "@fontsource/rajdhani": "^4.5.10", + "@heroicons/react": "^2.0.12", + "@hookform/resolvers": "^2.8.10", + "@stripe/react-stripe-js": "^1.9.0", + "@stripe/stripe-js": "^1.32.0", + "@uppy/aws-s3": "^2.1.0", + "@uppy/core": "^2.2.0", + "@uppy/dashboard": "^2.1.4", + "@uppy/drag-drop": "^2.1.0", + "@uppy/dropbox": "^2.0.5", + "@uppy/google-drive": "^2.0.5", + "@uppy/onedrive": "^2.0.6", + "@uppy/react": "^2.2.0", + "@uppy/tus": "^2.3.0", + "@uppy/xhr-upload": "^2.1.0", + "bootstrap": "^5.2.2", + "fabric": "5.2.4", + "fabricjs-react": "1.0.8", + "framer-motion": "^10.12.4", + "moment": "^2.29.3", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-hook-form": "^7.34.2", + "react-loading-skeleton": "^3.1.0", + "react-router": "^6.2.2", + "react-router-dom": "^6.2.2", + "tw-elements": "^1.0.0-alpha12", + "uppy": "^2.9.1", + "xlsx": "^0.18.5", + "yup": "^0.32.11" + }, + "devDependencies": { + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^1.3.0", + "autoprefixer": "^10.4.7", + "postcss": "^8.4.14", + "tailwindcss": "^3.0.24", + "vite": "^2.9.9" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", + "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.26.10", + "@babel/types": "^7.26.10", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", + "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "dev": true, + "dependencies": { + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", + "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.26.10" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", + "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.10", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", + "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", + "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fontsource/rajdhani": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@fontsource/rajdhani/-/rajdhani-4.5.10.tgz", + "integrity": "sha512-4qsQsC4BELF8FC6UEBs5QBkek4v+/t0PYmQYtw1WDlNlq0V5mjUldMxjXzZano9/5HBihL7ztfQRPOf8WYexIQ==" + }, + "node_modules/@heroicons/react": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz", + "integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==", + "peerDependencies": { + "react": ">= 16 || ^19.0.0-rc" + } + }, + "node_modules/@hookform/resolvers": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.11.tgz", + "integrity": "sha512-bA3aZ79UgcHj7tFV7RlgThzwSSHZgvfbt2wprldRkYBcMopdMvHyO17Wwp/twcJasNFischFfS7oz8Katz8DdQ==", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, + "node_modules/@stripe/react-stripe-js": { + "version": "1.16.5", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.16.5.tgz", + "integrity": "sha512-lVPW3IfwdacyS22pP+nBB6/GNFRRhT/4jfgAK6T2guQmtzPwJV1DogiGGaBNhiKtSY18+yS8KlHSu+PvZNclvQ==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@stripe/stripe-js": "^1.44.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@stripe/stripe-js": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.54.2.tgz", + "integrity": "sha512-R1PwtDvUfs99cAjfuQ/WpwJ3c92+DAMy9xGApjqlWQMj0FKQabUAys2swfTRNzuYAYJh7NqK2dzcYVNkKLEKUg==" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==" + }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.19", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.19.tgz", + "integrity": "sha512-fcdJqaHOMDbiAwJnXv6XCzX0jDW77yI3tJqYh1Byn8EL5/S628WRx9b/y3DnNe55zTukUQKrfYxiZls2dHcUMw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "dev": true, + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@uppy/audio": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@uppy/audio/-/audio-0.3.3.tgz", + "integrity": "sha512-HmIE3berOiHZko0G8cZyIx6B0xY3EphjlLqUM3Q5xPJk6iU4ELIQWXjdgfYs7AFCSOPLcOf5IxldoSxAFCr+Cw==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/aws-s3": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@uppy/aws-s3/-/aws-s3-2.2.4.tgz", + "integrity": "sha512-kdyrm79fWm1uMUvza4LwD76zh7gmV41VlB5S5WojtT5JjT/hHlfsYZIuXNqqt7oWSzHUNPwAKxPvp9fHmEJ/tw==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.3", + "@uppy/xhr-upload": "^2.1.3", + "nanoid": "^3.1.25" + }, + "peerDependencies": { + "@uppy/core": "^2.3.4" + } + }, + "node_modules/@uppy/aws-s3-multipart": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@uppy/aws-s3-multipart/-/aws-s3-multipart-2.4.3.tgz", + "integrity": "sha512-2z/mTmDceQimsHGEXuhdUL6v7Twsj1TKLDTxp+YPEtf9cuSBhzwkUd/YltHHa8tH/ocdDXs4rwLuMZBXNIo0Qw==", + "deprecated": "Use @uppy/aws-s3 instead.", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/box": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@uppy/box/-/box-1.0.8.tgz", + "integrity": "sha512-ACgfD1o+f+Tu+K99605p5HhziYyHqa8B5wx3Lf/e5XqqdaHBi99qyJ902I8UVQQpdr/KCvkF1hbxtsPep5+Geg==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/companion-client": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz", + "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "namespace-emitter": "^2.0.1" + } + }, + "node_modules/@uppy/compressor": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@uppy/compressor/-/compressor-0.3.3.tgz", + "integrity": "sha512-EsaKXOksToMDjTmrJhWJ8xKJsZyJCQysHwo5aoLQ/7lq+wVifF8TqvglT1Z8c8nSRkgcDum39vw8oQqvlmdyNQ==", + "dependencies": { + "@transloadit/prettier-bytes": "^0.0.9", + "@uppy/utils": "^4.1.2", + "compressorjs": "^1.1.1", + "preact": "^10.5.13", + "promise-queue": "^2.2.5" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/compressor/node_modules/@transloadit/prettier-bytes": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.9.tgz", + "integrity": "sha512-pCvdmea/F3Tn4hAtHqNXmjcixSaroJJ+L3STXlYJdir1g1m2mRQpWbN8a4SvgQtaw2930Ckhdx8qXdXBFMKbAA==" + }, + "node_modules/@uppy/core": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz", + "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.1.1", + "@uppy/utils": "^4.1.3", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "node_modules/@uppy/dashboard": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@uppy/dashboard/-/dashboard-2.4.3.tgz", + "integrity": "sha512-OPpvosiRaZXN873mraDmiM8T8c+2rIl86Ho7lQPsq+aQfjLUiPML+Y2rjmwDPE6eo7EiBszV5dQkO6vPjGO8/g==", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/informer": "^2.1.1", + "@uppy/provider-views": "^2.1.3", + "@uppy/status-bar": "^2.2.2", + "@uppy/thumbnail-generator": "^2.2.2", + "@uppy/utils": "^4.1.3", + "classnames": "^2.2.6", + "is-shallow-equal": "^1.0.1", + "lodash.debounce": "^4.0.8", + "memoize-one": "^5.0.4", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.4" + } + }, + "node_modules/@uppy/drag-drop": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/drag-drop/-/drag-drop-2.1.2.tgz", + "integrity": "sha512-J6hBiYcBc8p6U9PylqtZ+eMJ48yT1qP1Xzon2Pou5AQxQ4D7UAL97OvcjnONpOfp8P7uGmaqXFUubBNgEUCfQg==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/drop-target": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@uppy/drop-target/-/drop-target-1.1.4.tgz", + "integrity": "sha512-TCFTLqBnHGDJTV0DOjiT8HYO/YKm39Sg3tXNdubhidWAy/S4UVAj73X634UVOQascK5Fo4iHSwWaj8052xAETw==", + "dependencies": { + "@uppy/utils": "^4.1.2" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/dropbox": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@uppy/dropbox/-/dropbox-2.0.8.tgz", + "integrity": "sha512-nvzRTW38sEsj0jhtMizLq0aEQbkY1fd5rDQy6phobt07aiJ8T/KT2NrefuIUaT1ECkz929l0yqDbrdSk7iynZw==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/facebook": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@uppy/facebook/-/facebook-2.0.8.tgz", + "integrity": "sha512-2sz8IFowl/7nOH0Sx4OK6Uo/Wps7ARUYmJs5vjeYUNzODdnQM6WZPmDpQ0vfJW/5cgj8ilx87kUaCLZul1Ey1A==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/file-input": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/file-input/-/file-input-2.1.2.tgz", + "integrity": "sha512-tdn6HNMnLOC2xpdZYbdXNSjTS9EpLvY97vOfq9SZWkoX/cmZiOf6JfFc3Qm8pS3RRnVmwsdi5usEPbzMQ5RAEg==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/form": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@uppy/form/-/form-2.0.7.tgz", + "integrity": "sha512-FsZ97NRUeXCi5iAJB2VAxxCa+WOizrP8y42g2dD36S783e81a4iZqSm2N7WSC3PQHNu7OKkQnPYN+9xU0w5emw==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "get-form-data": "^2.0.0" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/golden-retriever": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/golden-retriever/-/golden-retriever-2.1.3.tgz", + "integrity": "sha512-G1zBjgsfzMjebQ9KMLTE5H6AX/fuMAe6izFx6B6FE0M4mJ9ZZ+ClbHQeFzomepagGq8dJoIB4M85CzRyq5Igbw==", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/utils": "^4.1.3", + "lodash.throttle": "^4.1.1" + }, + "peerDependencies": { + "@uppy/core": "^2.3.4" + } + }, + "node_modules/@uppy/google-drive": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/google-drive/-/google-drive-2.1.2.tgz", + "integrity": "sha512-78JAaoV3MNeaNDCzJpym5nIY0NynWivyjcbJ6Ool2xyAKqS5nBUXnAG+ciEl8ZMAhFdv94kI9pLtrRNezYI7vg==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/image-editor": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@uppy/image-editor/-/image-editor-1.4.2.tgz", + "integrity": "sha512-oqcvIphTQVhRJiMpi7aRe5gx2O+GqVOp9G+/kNPDjFZTZoS6vTrGWdmlr27dt0JkZarckjOK7+2iboCSIe9Qqg==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "cropperjs": "1.5.7", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/informer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/informer/-/informer-2.1.1.tgz", + "integrity": "sha512-aSdtJO0QvDGzcWHQ1Kd1hOFLyn+0e8LY82708WGkt8BwYwjmKhCJUuxdPDsCu3I2wpFUSUzpvQ9pik7AajBFjw==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/instagram": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/instagram/-/instagram-2.1.2.tgz", + "integrity": "sha512-dvQJ6PeX9hFN5f0+hi7qx2zDtZz0AyNYqB/O41VUulO0eDgfh8c4r4w4EUp676o9aY/0Ia71il7D5y3vtysqIA==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/onedrive": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/onedrive/-/onedrive-2.1.2.tgz", + "integrity": "sha512-rlRNPdOT+AWmeDkiGqQODjATQw6w3Xn/Uod6Ct2JvJhLhxImbTsxDedQotwE18m3AnQ9wLdLM9cCGAcvKeEsHg==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/progress-bar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/progress-bar/-/progress-bar-2.1.2.tgz", + "integrity": "sha512-BzO+LSMDj+daT93yoUhNdkQ1Bq79lSm+hTUcuFpUt397B0ETzUeHUg3wUj39Zu3r7BlO/JmQLbH4NkejK4rYGg==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/provider-views": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/provider-views/-/provider-views-2.1.3.tgz", + "integrity": "sha512-IXk8j+0nXxsTLV1KwUJbholiwMYXJ9H2r7pJlBRiu/lB/hgd5t7ENqt2susnepBFQJ+XlaIsuM5YVLgppBwc5w==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "classnames": "^2.2.6", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/react": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@uppy/react/-/react-2.2.3.tgz", + "integrity": "sha512-Zr8KRHATAPeYGI10Xty+KS4rSh3mvoE5l++9Ondo0Qu7TbFPIrmLlq52d9yMI1dV4hd98kshv6kRa394Ex4UbQ==", + "dependencies": { + "@uppy/dashboard": "^2.4.2", + "@uppy/drag-drop": "^2.1.2", + "@uppy/file-input": "^2.1.2", + "@uppy/progress-bar": "^2.1.2", + "@uppy/status-bar": "^2.2.2", + "@uppy/utils": "^4.1.2", + "prop-types": "^15.6.1" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3", + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@uppy/redux-dev-tools": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/redux-dev-tools/-/redux-dev-tools-2.1.1.tgz", + "integrity": "sha512-dLJv/gofRIkyw6RIUFQxCOhtvplRjQNcp7BlbSfThH0AkaRtm+dH/0hjCpl6wED5r746u+ZUoZyMi7P4STGC0g==", + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/remote-sources": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@uppy/remote-sources/-/remote-sources-0.1.2.tgz", + "integrity": "sha512-MBsFAvXH8tEMzl3E+5s0F27K3iwewV/7QaXeHrgOcToxlAuk7f+3xmYCKIt9vK3pp7iSebJ0SQ/qaHSHZizL2g==", + "dependencies": { + "@uppy/box": "^1.0.8", + "@uppy/dashboard": "^2.4.2", + "@uppy/dropbox": "^2.0.8", + "@uppy/facebook": "^2.0.8", + "@uppy/google-drive": "^2.1.2", + "@uppy/instagram": "^2.1.2", + "@uppy/onedrive": "^2.1.2", + "@uppy/unsplash": "^2.1.1", + "@uppy/url": "^2.2.1", + "@uppy/zoom": "^1.1.2" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/screen-capture": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@uppy/screen-capture/-/screen-capture-2.1.2.tgz", + "integrity": "sha512-gsVtosu/3rHe2W2oJQUwcNFdBZuJ6DQmILrtdMicBN4SuQck0ClmztOTjQXGuCurjSErS5HHvxz3G98I/F5Epw==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/status-bar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/status-bar/-/status-bar-2.2.2.tgz", + "integrity": "sha512-XV4/3RyNF42enqPc4wWZupqI1KuGtfdt49waux7kebxaGqNzV+T72o/C+QDDqY/h4mKadrp6p98/BnMefC5QtQ==", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/utils": "^4.1.2", + "classnames": "^2.2.6", + "lodash.throttle": "^4.1.1", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/store-default": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz", + "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==" + }, + "node_modules/@uppy/store-redux": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/store-redux/-/store-redux-2.1.1.tgz", + "integrity": "sha512-RFb/fi4BBlC+l1TC/Z76Wo1ZsssAr4Su23C0ZgB1KCA2RrXRIu7dkwQuFHvy+HokJhhyDPm3Sm474ulPr5wpzA==", + "dependencies": { + "nanoid": "^3.1.25" + } + }, + "node_modules/@uppy/thumbnail-generator": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/thumbnail-generator/-/thumbnail-generator-2.2.2.tgz", + "integrity": "sha512-5VwwzzvKRqXJNz28U/VwXu9K9dHY5vXQvzljxqkeCJrKIMgu/8vzKEFndAPY6sJZkUcF0jtAb3gUU2q5TGRlJg==", + "dependencies": { + "@uppy/utils": "^4.1.3", + "exifr": "^7.0.0" + }, + "peerDependencies": { + "@uppy/core": "^2.3.4" + } + }, + "node_modules/@uppy/transloadit": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@uppy/transloadit/-/transloadit-2.3.7.tgz", + "integrity": "sha512-LETmEvMX/Am3Gu/thxttHGdIy7oOjU2+G5+VHozzyBF8Z1kqW0p+LUS0HwWM9w7cz4S/Yi+ZI+rP0aR5J2txhg==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/tus": "^2.4.3", + "@uppy/utils": "^4.1.2", + "component-emitter": "^1.2.1", + "socket.io-client": "^4.1.3" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/tus": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@uppy/tus/-/tus-2.4.6.tgz", + "integrity": "sha512-0R8D65YKZRyvx+SKNKPkgVYrgAcZiz6vtzc+ZmcCePFXNZj945kFIoeqNUuQ9aQlkIasihKB4kut6X2F4G93IA==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.3", + "tus-js-client": "^2.1.1" + }, + "peerDependencies": { + "@uppy/core": "^2.3.4" + } + }, + "node_modules/@uppy/unsplash": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/unsplash/-/unsplash-2.1.1.tgz", + "integrity": "sha512-S6pX12ierlx9iBkTXvPlljmPI32CYdp61WoLrGXrhmZmCrFsk64ngZK7PVmkJ4avsokNq5vDjkZvgjxZ5wmtzQ==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/url": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@uppy/url/-/url-2.2.1.tgz", + "integrity": "sha512-OY85TLyaQG0ELd3+fX9KTJ41EOmsWvVYMYQvNXSs/+K+xe52mzEqV8PK85dxlQwEIuPAGtQQGz+6IICuwsWDdA==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/utils": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz", + "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==", + "dependencies": { + "lodash.throttle": "^4.1.1" + } + }, + "node_modules/@uppy/webcam": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/webcam/-/webcam-2.2.2.tgz", + "integrity": "sha512-7pYFhzYRj7AcwXg0onrcDMUjW5uNC8ImF9PhUzaZBtp9pnXMKpxfbiHv3MobqH8XtCZWYAvPizPc4dqDMY7iJA==", + "dependencies": { + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/xhr-upload": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz", + "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2", + "nanoid": "^3.1.25" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@uppy/zoom": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@uppy/zoom/-/zoom-1.1.2.tgz", + "integrity": "sha512-b19x6jnEqCnm7UNyM/vO+AVq4xaaPuVD3wzpkzh47aROtLm/DGVKhTFSJAFVfae7iE4JmeA80JHXYYfb7dgUFA==", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/utils": "^4.1.2", + "preact": "^10.5.13" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz", + "integrity": "sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.17.10", + "@babel/plugin-transform-react-jsx": "^7.17.3", + "@babel/plugin-transform-react-jsx-development": "^7.16.7", + "@babel/plugin-transform-react-jsx-self": "^7.16.7", + "@babel/plugin-transform-react-jsx-source": "^7.16.7", + "@rollup/pluginutils": "^4.2.1", + "react-refresh": "^0.13.0", + "resolve": "^1.22.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "optional": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "optional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "optional": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "optional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "optional": true + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/blueimp-canvas-to-blob": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz", + "integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==" + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "optional": true + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001706", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", + "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chart.js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", + "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combine-errors": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/combine-errors/-/combine-errors-3.0.3.tgz", + "integrity": "sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==", + "dependencies": { + "custom-error-instance": "2.1.1", + "lodash.uniqby": "4.5.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compressorjs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.2.1.tgz", + "integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==", + "dependencies": { + "blueimp-canvas-to-blob": "^3.29.0", + "is-blob": "^2.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "optional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cropperjs": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.7.tgz", + "integrity": "sha512-sGj+G/ofKh+f6A4BtXLJwtcKJgMUsXYVUubfTo9grERiDGXncttefmue/fyQFvn8wfdyoD1KhDRYLfjkJFl0yw==" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "optional": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "optional": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "optional": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/custom-error-instance": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", + "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==" + }, + "node_modules/custom-event-polyfill": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz", + "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "optional": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "optional": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "devOptional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "optional": true + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, + "node_modules/detect-autofill": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/detect-autofill/-/detect-autofill-1.1.4.tgz", + "integrity": "sha512-utCBQwCR/beSnADQmBC7C4tTueBBkYCl6WSpfGUkYKO/+MzPxqYGj6G4MvHzcKmH1gCTK+VunX2vaagvkRXPvA==", + "dependencies": { + "custom-event-polyfill": "^1.0.7" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "optional": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "optional": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.122", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.122.tgz", + "integrity": "sha512-EML1wnwkY5MFh/xUnCvY8FrhUuKzdYhowuZExZOfwJo+Zu9OsNCI23Cgl5y7awy7HrUHSwB1Z8pZX5TI34lsUg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", + "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", + "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", + "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", + "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", + "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", + "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", + "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", + "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", + "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", + "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", + "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", + "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", + "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", + "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", + "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", + "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", + "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", + "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", + "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "optional": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "optional": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exifr": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz", + "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==" + }, + "node_modules/fabric": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/fabric/-/fabric-5.2.4.tgz", + "integrity": "sha512-3+oLKvsbSJ76/nvPPrQVuUJDp0kOh8i867PpdrOPIHUyN+eLc+9nY3rmzMmDw6ndRm20f/uULv55G8sN01j9+Q==", + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "canvas": "^2.8.0", + "jsdom": "^19.0.0" + } + }, + "node_modules/fabricjs-react": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/fabricjs-react/-/fabricjs-react-1.0.8.tgz", + "integrity": "sha512-IHsxpEAAxXAUToSsQQw6OMjJNkHYwURqdf+RPjeSilPn1iVpDfBpSyYBX+hqCTg3x7b7WplYZOi/bhmrxMVvYQ==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "fabric": "^4.3.1", + "react": "^17.0.1", + "react-dom": "^17.0.1" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.18.0.tgz", + "integrity": "sha512-oGlDh1Q1XqYPksuTD/usb0I70hq95OUzmL9+6Zd+Hs4XV0oaISBa/UUMSjYiq6m8EUF32132mOJ8xVZS+I0S6w==", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "optional": true + }, + "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, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-form-data/-/get-form-data-2.0.0.tgz", + "integrity": "sha512-YUpw0aTWeGliifqMYrTohe/YdqVmKLmaNwuscd2WlRNGfba57JHGuuvvv2c6LiZdFys285POVWANTh6SqcwFag==" + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "optional": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "optional": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "optional": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "optional": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "optional": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-blob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "optional": true + }, + "node_modules/is-shallow-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shallow-equal/-/is-shallow-equal-1.0.1.tgz", + "integrity": "sha512-lq5RvK+85Hs5J3p4oA4256M1FEffzmI533ikeDHvJd42nouRRx5wBzt36JuviiGe5dIPyHON/d0/Up+PBo6XkQ==" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsdom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", + "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", + "optional": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.5.0", + "acorn-globals": "^6.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.1", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0", + "ws": "^8.2.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash._baseiteratee": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz", + "integrity": "sha512-nqB9M+wITz0BX/Q2xg6fQ8mLkyfF7MU7eE+MNBNjTHFKeKaZAPEzEg+E8LWxKWf1DQVflNEn9N49yAuqKh2mWQ==", + "dependencies": { + "lodash._stringtopath": "~4.8.0" + } + }, + "node_modules/lodash._basetostring": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz", + "integrity": "sha512-SwcRIbyxnN6CFEEK4K1y+zuApvWdpQdBHM/swxP962s8HIxPO3alBH5t3m/dl+f4CMUug6sJb7Pww8d13/9WSw==" + }, + "node_modules/lodash._baseuniq": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", + "integrity": "sha512-Ja1YevpHZctlI5beLA7oc5KNDhGcPixFhcqSiORHNsp/1QTv7amAXzw+gu4YOvErqVlMVyIJGgtzeepCnnur0A==", + "dependencies": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "node_modules/lodash._createset": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", + "integrity": "sha512-GTkC6YMprrJZCYU3zcqZj+jkXkrXzq3IPBcF/fIPpNEAB4hZEtXU8zp/RwKOvZl43NUmwDbyRk3+ZTbeRdEBXA==" + }, + "node_modules/lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==" + }, + "node_modules/lodash._stringtopath": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz", + "integrity": "sha512-SXL66C731p0xPDC5LZg4wI5H+dJo/EO4KTqOMwLYCH3+FmmfAKJEZCm6ohGpI+T1xwsDsJCfL4OnhorllvlTPQ==", + "dependencies": { + "lodash._basetostring": "~4.12.0" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, + "node_modules/lodash.uniqby": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz", + "integrity": "sha512-IRt7cfTtHy6f1aRVA5n7kT8rgN3N1nH6MOWLcHfpWG2SH19E3JksLK38MktLxZDhlAjCP9jpIXkOnRXlu6oByQ==", + "dependencies": { + "lodash._baseiteratee": "~4.7.0", + "lodash._baseuniq": "~4.6.0" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", + "dependencies": { + "wildcard": "^1.1.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "optional": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==" + }, + "node_modules/nan": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "optional": true + }, + "node_modules/nanoclone": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.19.tgz", + "integrity": "sha512-94bcyI3RsqiZufXjkr3ltkI86iEl+I7uiHVDtcq9wJUTwYQJ5odHDeSzkkrRzi80jJ8MaeZgqKjH1bAWAFw9bA==", + "optional": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "optional": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz", + "integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/preact": { + "version": "10.26.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.4.tgz", + "integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proper-lockfile": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz", + "integrity": "sha512-rjaeGbsmhNDcDInmwi4MuI6mRwJu6zq8GjYCLuSuE7GF+4UjgzkL69sVKKJ2T2xH61kK7rXvGYpvaTu909oXaQ==", + "dependencies": { + "graceful-fs": "^4.1.2", + "retry": "^0.10.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "optional": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-hook-form": { + "version": "7.54.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.54.2.tgz", + "integrity": "sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-loading-skeleton": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.5.0.tgz", + "integrity": "sha512-gxxSyLbrEAdXTKgfbpBEFZCO/P153DnqSCQau2+o6lNy1jgMRr2MmRmOzMmyrwSaSYLRB8g7b0waYPmUjz7IhQ==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-refresh": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz", + "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz", + "integrity": "sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz", + "integrity": "sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "engines": { + "node": "*" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.77.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz", + "integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "optional": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "optional": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "optional": true + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "optional": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "optional": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/tus-js-client": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tus-js-client/-/tus-js-client-2.3.2.tgz", + "integrity": "sha512-5a2rm7gp+G7Z+ZB0AO4PzD/dwczB3n1fZeWO5W8AWLJ12RRk1rY4Aeb2VAYX9oKGE+/rGPrdxoFPA/vDSVKnpg==", + "dependencies": { + "buffer-from": "^1.1.2", + "combine-errors": "^3.0.3", + "is-stream": "^2.0.0", + "js-base64": "^2.6.1", + "lodash.throttle": "^4.1.1", + "proper-lockfile": "^2.0.1", + "url-parse": "^1.5.7" + } + }, + "node_modules/tw-elements": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tw-elements/-/tw-elements-1.1.0.tgz", + "integrity": "sha512-IUr9YW2l99oTVZxuVjQg6rpuCpo6VZqbaKGYmZUNVVsoSVU/ljPpkJAY2Pn/morlXwKPhP9MTPNQMlWosqHL4w==", + "dependencies": { + "@popperjs/core": "^2.6.0", + "chart.js": "^3.7.1", + "chartjs-plugin-datalabels": "^2.0.0", + "deepmerge": "^4.2.2", + "detect-autofill": "^1.1.3", + "perfect-scrollbar": "^1.5.5", + "tailwindcss": "3.3.0" + } + }, + "node_modules/tw-elements/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tw-elements/node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/tw-elements/node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tw-elements/node_modules/postcss-nested": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/tw-elements/node_modules/tailwindcss": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.0.tgz", + "integrity": "sha512-hOXlFx+YcklJ8kXiCAfk/FMyr4Pm9ck477G0m/us2344Vuj355IpoEDB5UmGAsSpTBmr+4ZhjzW04JuFXkb/fw==", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/tw-elements/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uppy": { + "version": "2.13.8", + "resolved": "https://registry.npmjs.org/uppy/-/uppy-2.13.8.tgz", + "integrity": "sha512-qsEvSil1ebnBj+WgkCKn3GLNCKN4xyGKjtrjz6BUlGWyaw6kv47Kb8q1VmBl85z17tkedA/OLfPd0pXZ8RfQNg==", + "dependencies": { + "@uppy/audio": "^0.3.3", + "@uppy/aws-s3": "^2.2.4", + "@uppy/aws-s3-multipart": "^2.4.3", + "@uppy/box": "^1.0.8", + "@uppy/companion-client": "^2.2.2", + "@uppy/compressor": "^0.3.3", + "@uppy/core": "^2.3.4", + "@uppy/dashboard": "^2.4.3", + "@uppy/drag-drop": "^2.1.2", + "@uppy/drop-target": "^1.1.4", + "@uppy/dropbox": "^2.0.8", + "@uppy/facebook": "^2.0.8", + "@uppy/file-input": "^2.1.2", + "@uppy/form": "^2.0.7", + "@uppy/golden-retriever": "^2.1.3", + "@uppy/google-drive": "^2.1.2", + "@uppy/image-editor": "^1.4.2", + "@uppy/informer": "^2.1.1", + "@uppy/instagram": "^2.1.2", + "@uppy/onedrive": "^2.1.2", + "@uppy/progress-bar": "^2.1.2", + "@uppy/provider-views": "^2.1.3", + "@uppy/redux-dev-tools": "^2.1.1", + "@uppy/remote-sources": "^0.1.2", + "@uppy/screen-capture": "^2.1.2", + "@uppy/status-bar": "^2.2.2", + "@uppy/store-default": "^2.1.1", + "@uppy/store-redux": "^2.1.1", + "@uppy/thumbnail-generator": "^2.2.2", + "@uppy/transloadit": "^2.3.7", + "@uppy/tus": "^2.4.6", + "@uppy/unsplash": "^2.1.1", + "@uppy/url": "^2.2.1", + "@uppy/webcam": "^2.2.2", + "@uppy/xhr-upload": "^2.1.3", + "@uppy/zoom": "^1.1.2" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/vite": { + "version": "2.9.18", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.18.tgz", + "integrity": "sha512-sAOqI5wNM9QvSEE70W3UGMdT8cyEn0+PmJMTFvTB8wB0YbYUWw3gUbY62AOyrXosGieF2htmeLATvNxpv/zNyQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.14.27", + "postcss": "^8.4.13", + "resolve": "^1.22.0", + "rollup": ">=2.59.0 <2.78.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": ">=12.2.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "less": "*", + "sass": "*", + "stylus": "*" + }, + "peerDependenciesMeta": { + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + } + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "optional": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "optional": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "optional": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", + "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "optional": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==" + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "optional": true + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "optional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "optional": true + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yup": { + "version": "0.32.11", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", + "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/lodash": "^4.14.175", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "nanoclone": "^0.2.1", + "property-expr": "^2.0.4", + "toposort": "^2.0.2" + }, + "engines": { + "node": ">=10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b72c6a3 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "adminportal", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "tw": "npx tailwindcss -i ./src/index.css -o ./src/output.css --watch", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@fontsource/rajdhani": "^4.5.10", + "@heroicons/react": "^2.0.12", + "@hookform/resolvers": "^2.8.10", + "@stripe/react-stripe-js": "^1.9.0", + "@stripe/stripe-js": "^1.32.0", + "@uppy/aws-s3": "^2.1.0", + "@uppy/core": "^2.2.0", + "@uppy/dashboard": "^2.1.4", + "@uppy/drag-drop": "^2.1.0", + "@uppy/dropbox": "^2.0.5", + "@uppy/google-drive": "^2.0.5", + "@uppy/onedrive": "^2.0.6", + "@uppy/react": "^2.2.0", + "@uppy/tus": "^2.3.0", + "@uppy/xhr-upload": "^2.1.0", + "bootstrap": "^5.2.2", + "fabric": "5.2.4", + "fabricjs-react": "1.0.8", + "framer-motion": "^10.12.4", + "moment": "^2.29.3", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "react-hook-form": "^7.34.2", + "react-loading-skeleton": "^3.1.0", + "react-router": "^6.2.2", + "react-router-dom": "^6.2.2", + "tw-elements": "^1.0.0-alpha12", + "uppy": "^2.9.1", + "xlsx": "^0.18.5", + "yup": "^0.32.11" + }, + "devDependencies": { + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^1.3.0", + "autoprefixer": "^10.4.7", + "postcss": "^8.4.14", + "tailwindcss": "^3.0.24", + "vite": "^2.9.9" + } +} diff --git a/pg.js b/pg.js new file mode 100644 index 0000000..acb9be0 --- /dev/null +++ b/pg.js @@ -0,0 +1,281 @@ +const a = { + authentication: { + login: true, + register: false, + forgot: true, + reset: true, + lambdaLogin: true, + lambdaRegister: true, + lambdatwofa: true, + lambdaFacebook: true, + lambdaGoogle: true, + lambdaPreference: true, + lambdaProfile: true, + lambdaRealtime: true, + lambdaReset: true, + lambdaSend_Mail: true, + lambdaUpdate_Email: false, + lambdaUpdate_Password: true, + lambdaUpload: true, + lambdaForgot: true, + lambdaEmail: true, + "lambdaVerify-email": true, + lambdaVerify_user: true, + lambdaApple: true, + lambdaCaptcha: true + }, + models: { + user: { + POST: true, + PUT: true, + GET: true, + DELETE: true, + EXPORT: true, + AUTOCOMPLETE: true, + IMPORT: false, + GETALL: true, + PAGINATE: true + }, + token: { + POST: false, + PUT: false, + GET: false, + DELETE: false, + EXPORT: false, + AUTOCOMPLETE: false, + IMPORT: false, + GETALL: false + }, + photo: { + POST: true, + PUT: true, + GET: true, + DELETE: true, + EXPORT: true, + AUTOCOMPLETE: true, + IMPORT: true, + GETALL: true, + PUTWHERE: true, + PAGINATE: true + }, + email: { + POST: true, + PUT: true, + GET: true, + DELETE: true, + EXPORT: true, + AUTOCOMPLETE: true, + IMPORT: true, + GETALL: true, + PUTWHERE: true, + PAGINATE: true + }, + profile: { + POST: true, + PUT: true, + GET: true, + DELETE: true, + EXPORT: true, + AUTOCOMPLETE: true, + IMPORT: true, + GETALL: true, + PUTWHERE: true, + PAGINATE: true + }, + permission: { + POST: true, + PUT: true, + GET: true, + DELETE: true, + EXPORT: false, + AUTOCOMPLETE: false, + IMPORT: false, + GETALL: true + }, + room: { + POST: true, + PUT: true, + GET: true, + DELETE: false, + EXPORT: false, + AUTOCOMPLETE: false, + IMPORT: false, + GETALL: true + }, + chat: { + POST: true, + PUT: true, + GET: true, + DELETE: false, + EXPORT: false, + AUTOCOMPLETE: false, + IMPORT: false, + GETALL: true + }, + accessories: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + trigger_rules: { + AUTOCOMPLETE: false, + DELETE: false, + EXPORT: false, + GET: false, + GETALL: false, + IMPORT: false, + POST: false, + PUT: false, + PUTWHERE: false + }, + boat_lifts: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + dealers: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + docks: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + analytic_log: { + AUTOCOMPLETE: false, + DELETE: false, + EXPORT: false, + GET: false, + GETALL: false, + IMPORT: false, + POST: false, + PUT: false, + PUTWHERE: false + }, + cms: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + trigger_type: { + AUTOCOMPLETE: false, + DELETE: false, + EXPORT: false, + GET: false, + GETALL: false, + IMPORT: false, + POST: false, + PUT: false, + PUTWHERE: false + }, + instructions: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + quotes: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + wedges: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + ramps: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + quotes_mail_recipients: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + }, + reference_items: { + AUTOCOMPLETE: true, + DELETE: true, + EXPORT: true, + GET: true, + GETALL: true, + IMPORT: true, + POST: true, + PUT: true, + PUTWHERE: true, + PAGINATE: true + } + } +}; diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..6c4cc91 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..e69de29 diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..1356677 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,41 @@ +import React, { useEffect } from "react"; +import AuthProvider from "./authContext"; +import GlobalProvider from "./globalContext"; +import Main from "./main"; +import "@uppy/core/dist/style.css"; +import "@uppy/dashboard/dist/style.css"; +import { BrowserRouter as Router } from "react-router-dom"; +import "react-loading-skeleton/dist/skeleton.css"; +import { loadStripe } from "@stripe/stripe-js"; +import { Elements } from "@stripe/react-stripe-js"; + +const stripePromise = loadStripe( "pk_test_51Ll5ukBgOlWo0lDUrBhA2W7EX2MwUH9AR5Y3KQoujf7PTQagZAJylWP1UOFbtH4UwxoufZbInwehQppWAq53kmNC00UIKSmebO" ); + +function App () { + + useEffect( () => { + const handleTabReload = ( e ) => { + e.preventDefault() + localStorage.removeItem( "token" ) + } + + window.addEventListener( 'beforeunload', handleTabReload ) + + return () => { + window.removeEventListener( 'beforeunload', handleTabReload ) + } + }, [] ) + return ( + + + + +
+ + + + + ); +} + +export default App; diff --git a/src/assets/images/BrandLogo.png b/src/assets/images/BrandLogo.png new file mode 100644 index 0000000..c2b5bd3 Binary files /dev/null and b/src/assets/images/BrandLogo.png differ diff --git a/src/assets/images/gray.png b/src/assets/images/gray.png new file mode 100644 index 0000000..abea248 Binary files /dev/null and b/src/assets/images/gray.png differ diff --git a/src/assets/images/index.js b/src/assets/images/index.js new file mode 100644 index 0000000..db3b2d0 --- /dev/null +++ b/src/assets/images/index.js @@ -0,0 +1,4 @@ +export { default as BrandLogo } from './BrandLogo.png' +export { default as GrayMaterial } from './gray.png' +export { default as WoodgrainMaterial } from './woodgrain.png' +export { default as PerforatedMaterial } from './perforated.png' \ No newline at end of file diff --git a/src/assets/images/perforated.png b/src/assets/images/perforated.png new file mode 100644 index 0000000..9acf2f7 Binary files /dev/null and b/src/assets/images/perforated.png differ diff --git a/src/assets/images/woodgrain.png b/src/assets/images/woodgrain.png new file mode 100644 index 0000000..50c90a0 Binary files /dev/null and b/src/assets/images/woodgrain.png differ diff --git a/src/assets/svgs/ArrowLeftIcon.tsx b/src/assets/svgs/ArrowLeftIcon.tsx new file mode 100644 index 0000000..012275c --- /dev/null +++ b/src/assets/svgs/ArrowLeftIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const ArrowLeftIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/ArrowRrightIcon.tsx b/src/assets/svgs/ArrowRrightIcon.tsx new file mode 100644 index 0000000..6caad51 --- /dev/null +++ b/src/assets/svgs/ArrowRrightIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const ArrowRrightIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/Chevron.jsx b/src/assets/svgs/Chevron.jsx new file mode 100644 index 0000000..dd299ad --- /dev/null +++ b/src/assets/svgs/Chevron.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const Chevron = ( { active } ) => { + return ( + + + + ) +} diff --git a/src/assets/svgs/CloseIcon.tsx b/src/assets/svgs/CloseIcon.tsx new file mode 100644 index 0000000..c48bd56 --- /dev/null +++ b/src/assets/svgs/CloseIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const CloseIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/CopyIcon.jsx b/src/assets/svgs/CopyIcon.jsx new file mode 100644 index 0000000..77cd19f --- /dev/null +++ b/src/assets/svgs/CopyIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const CopyIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/DeleteIcon.svg b/src/assets/svgs/DeleteIcon.svg new file mode 100644 index 0000000..350ce01 --- /dev/null +++ b/src/assets/svgs/DeleteIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/DownloadIcon.tsx b/src/assets/svgs/DownloadIcon.tsx new file mode 100644 index 0000000..a037645 --- /dev/null +++ b/src/assets/svgs/DownloadIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const DownloadIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/GreenTickIcon.tsx b/src/assets/svgs/GreenTickIcon.tsx new file mode 100644 index 0000000..a85d46a --- /dev/null +++ b/src/assets/svgs/GreenTickIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const GreenTickIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/HandIcon.jsx b/src/assets/svgs/HandIcon.jsx new file mode 100644 index 0000000..9da0349 --- /dev/null +++ b/src/assets/svgs/HandIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const HandIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/Loader.jsx b/src/assets/svgs/Loader.jsx new file mode 100644 index 0000000..27ff8ab --- /dev/null +++ b/src/assets/svgs/Loader.jsx @@ -0,0 +1,16 @@ +import React from 'react' + +export const Loader = ( { fill, stroke, className } ) => { + return ( + + + + + ) +} + +Loader.defaultProps = { + className: "h-5 w-5", + fill: "none", + stroke: "currentColor", +} \ No newline at end of file diff --git a/src/assets/svgs/MinusSquareIcon.jsx b/src/assets/svgs/MinusSquareIcon.jsx new file mode 100644 index 0000000..9dd1dff --- /dev/null +++ b/src/assets/svgs/MinusSquareIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const MinusSquareIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/PasteIcon.jsx b/src/assets/svgs/PasteIcon.jsx new file mode 100644 index 0000000..0340174 --- /dev/null +++ b/src/assets/svgs/PasteIcon.jsx @@ -0,0 +1,15 @@ + +import React from 'react' + +export const PasteIcon = () => { + return ( + + + + ) +} + + + // + // + // \ No newline at end of file diff --git a/src/assets/svgs/PlusSquareIcon.jsx b/src/assets/svgs/PlusSquareIcon.jsx new file mode 100644 index 0000000..f380659 --- /dev/null +++ b/src/assets/svgs/PlusSquareIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const PlusSquareIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/PrinterIcon.jsx b/src/assets/svgs/PrinterIcon.jsx new file mode 100644 index 0000000..ea24e8f --- /dev/null +++ b/src/assets/svgs/PrinterIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const PrinterIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/ReverseLeftIcon.jsx b/src/assets/svgs/ReverseLeftIcon.jsx new file mode 100644 index 0000000..50a35eb --- /dev/null +++ b/src/assets/svgs/ReverseLeftIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const ReverseLeftIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/ReverseRightIcon.jsx b/src/assets/svgs/ReverseRightIcon.jsx new file mode 100644 index 0000000..5a74b70 --- /dev/null +++ b/src/assets/svgs/ReverseRightIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const ReverseRightIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/RotateIcon.svg b/src/assets/svgs/RotateIcon.svg new file mode 100644 index 0000000..eae13be --- /dev/null +++ b/src/assets/svgs/RotateIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svgs/TrashIcon.jsx b/src/assets/svgs/TrashIcon.jsx new file mode 100644 index 0000000..94283a5 --- /dev/null +++ b/src/assets/svgs/TrashIcon.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const TrashIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/UploadIcon.tsx b/src/assets/svgs/UploadIcon.tsx new file mode 100644 index 0000000..7f07813 --- /dev/null +++ b/src/assets/svgs/UploadIcon.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +export const UploadIcon = () => { + return ( + + + + ) +} diff --git a/src/assets/svgs/index.js b/src/assets/svgs/index.js new file mode 100644 index 0000000..889ae9f --- /dev/null +++ b/src/assets/svgs/index.js @@ -0,0 +1,19 @@ +export { UploadIcon } from './UploadIcon' +export { DownloadIcon } from './DownloadIcon' +export { Chevron } from './Chevron' +export { HandIcon } from './HandIcon' +export { PlusSquareIcon } from './PlusSquareIcon' +export { MinusSquareIcon } from './MinusSquareIcon' +export { ReverseLeftIcon } from './ReverseLeftIcon' +export { ReverseRightIcon } from './ReverseRightIcon' +export { CopyIcon } from './CopyIcon' +export { TrashIcon } from './TrashIcon' +export { PasteIcon } from './PasteIcon' +export { Loader } from './Loader' +export { CloseIcon } from './CloseIcon' +export { ArrowRrightIcon } from './ArrowRrightIcon' +export { ArrowLeftIcon } from './ArrowLeftIcon' +export { GreenTickIcon } from './GreenTickIcon' +export { PrinterIcon } from './PrinterIcon' +export { default as DeleteIcon } from './DeleteIcon.svg' +export { default as RotateIcon } from './RotateIcon.svg' \ No newline at end of file diff --git a/src/authContext.jsx b/src/authContext.jsx new file mode 100644 index 0000000..f6d6784 --- /dev/null +++ b/src/authContext.jsx @@ -0,0 +1,104 @@ +import React, { useReducer } from "react"; +import MkdSDK from "./utils/MkdSDK"; + +export const AuthContext = React.createContext(); + +const initialState = { + isAuthenticated: false, + user: null, + token: null, + role: null, +}; + +const reducer = (state, action) => { + switch (action.type) { + case "LOGIN": + localStorage.setItem("user", Number(action.payload.user_id)); + localStorage.setItem("token", action.payload.token); + localStorage.setItem("role", action.payload.role); + return { + ...state, + isAuthenticated: true, + user: Number(localStorage.getItem("user")), + token: localStorage.getItem("token"), + role: localStorage.getItem("role"), + }; + case "LOGOUT": + localStorage.removeItem("user"); + localStorage.removeItem("token"); + return { + ...state, + isAuthenticated: false, + user: null, + }; + default: + return state; + } +}; + +let sdk = new MkdSDK(); + +export const tokenExpireError = (dispatch, errorMessage) => { + /** + * either this or we pass the role as a parameter + */ + const role = localStorage.getItem("role"); + if (errorMessage === "TOKEN_EXPIRED") { + dispatch({ + type: "LOGOUT", + }); + + location.href = "/" + role + "/login"; + } +}; + +const AuthProvider = ({ children }) => { + const [state, dispatch] = useReducer(reducer, initialState); + + React.useEffect(() => { + const user = localStorage.getItem("user"); + const token = localStorage.getItem("token"); + const role = localStorage.getItem("role"); + + if (token) { + (async function () { + try { + const result = await sdk.check(role); + dispatch({ + type: "LOGIN", + payload: { + user_id: user, + token, + role: role, + }, + }); + } catch (error) { + if (role) { + dispatch({ + type: "LOGOUT", + }); + window.location.href = "/" + role + "/login"; + } else { + dispatch({ + type: "LOGOUT", + }); + window.location.href = "/"; + } + } + })(); + } + }, []); + + return ( + + {children} + + ); +}; + +export default AuthProvider; diff --git a/src/components/ActionButtons/ActionButtons.jsx b/src/components/ActionButtons/ActionButtons.jsx new file mode 100644 index 0000000..b414569 --- /dev/null +++ b/src/components/ActionButtons/ActionButtons.jsx @@ -0,0 +1,85 @@ + +import React, { useCallback, useState } from 'react' +// import { GrayMaterial, PerforatedMaterial, WoodgrainMaterial } from 'Assets/images' +// import { MaterialType } from 'Utils/constants' +import { CopyIcon, HandIcon, PasteIcon, PrinterIcon, ReverseLeftIcon, ReverseRightIcon, TrashIcon } from 'Assets/svgs' +import { CanvasModes } from 'Utils/constants' + + + +export const ActionButtons = ( { className, onRedoClick, onUndoClick, onCopy, onPaste, onDeleteSelection, onPrintScreen } ) => { + const [ mode, setMode ] = useState( CanvasModes.Still ) + // const [ activeMaterial, setActiveMaterial ] = useState( MaterialType.Gray ) + + // const changeMode = useCallback( () => { + // if ( mode === CanvasModes.Pan ) { + // setMode( CanvasModes.Still ) + // onCanvasModeChange( CanvasModes.Still ) + // } else if ( mode === CanvasModes.Still ) { + // setMode( CanvasModes.Pan ) + // onCanvasModeChange( CanvasModes.Pan ) + // } + // }, [ mode ] ) + + return ( +
+ + + + {/* */} + + + + + + + + + + + +
+ ) +} \ No newline at end of file diff --git a/src/components/ActionButtons/index.js b/src/components/ActionButtons/index.js new file mode 100644 index 0000000..d6114b8 --- /dev/null +++ b/src/components/ActionButtons/index.js @@ -0,0 +1 @@ +export { ActionButtons } from './ActionButtons' \ No newline at end of file diff --git a/src/components/AddButton.jsx b/src/components/AddButton.jsx new file mode 100644 index 0000000..7a5df95 --- /dev/null +++ b/src/components/AddButton.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +const AddButton = ({ link }) => { + return ( + <> + + + {" "} + {" "} + + + + ); +}; + +export default AddButton; diff --git a/src/components/AdminHeader.jsx b/src/components/AdminHeader.jsx new file mode 100644 index 0000000..e3d75ed --- /dev/null +++ b/src/components/AdminHeader.jsx @@ -0,0 +1,205 @@ +import React from "react"; +import { AuthContext } from "../authContext"; +import { NavLink } from "react-router-dom"; +import { GlobalContext } from "../globalContext"; +export const AdminHeader = () => { + const { dispatch } = React.useContext(AuthContext); + const { state } = React.useContext(GlobalContext); + + return ( + <> +
+
+
+
+ Admin +
+
+
+
    +
  • + + Dashboard + +
  • + +
  • + + Accessories + +
  • + +
  • + + Email + +
  • + +
  • + + Photo + +
  • + +
  • + + Boat Lifts + +
  • + +
  • + + Dealers + +
  • + +
  • + + Docks + +
  • + +
  • + + Cms + +
  • + +
  • + + Instructions + +
  • + +
  • + + User + +
  • + +
  • + + Quotes + +
  • + +
  • + + Wedges + +
  • +
  • + + Ramps + +
  • + +
  • + + Quotes Mail Recipients + +
  • + +
  • + + Profile + +
  • +
  • + + dispatch({ + type: "LOGOUT", + }) + } + > + Logout + +
  • +
+
+
+
+ + ); +}; + +export default AdminHeader; diff --git a/src/components/BuildCanvasFromLocalModal/BuildCanvasFromLocalModal.jsx b/src/components/BuildCanvasFromLocalModal/BuildCanvasFromLocalModal.jsx new file mode 100644 index 0000000..a80ec40 --- /dev/null +++ b/src/components/BuildCanvasFromLocalModal/BuildCanvasFromLocalModal.jsx @@ -0,0 +1,82 @@ +import React, { memo, useState, useCallback } from 'react'; +import { Modal } from 'Components/Modal'; +import { InteractiveButton } from 'Components/InteractiveButton'; +// import { ArrowLeftIcon, ArrowRrightIcon, GreenTickIcon } from 'Assets/svgs'; +// import { dock_image, EstimateSteps, Tables, Truthy } from 'Utils/constants'; +// import { ContactInformation } from 'Components/ContactInformation'; +// import { LakeSurroundings } from 'Components/LakeSurroundings'; +// import { Comments } from 'Components/Comments'; +import MkdSDK from 'Utils/MkdSDK'; + +const sdk = new MkdSDK() +const classes = { + modal: 'string', + modalDialog: 'relative bg-white w-[500px]', + modalContent: 'string', + modalHeader: 'string', + modalTitle: 'string', + modalBody: 'string', + modalFooter: 'string', + closeButtonClass: 'string', + saveButtonClass: 'string', +} + +const BuildCanvasFromLocalModal = ( { + showBuildCanvasFromLocalModal, + modalCloseClick, + editor +} ) => { + // const [ step, setStep ] = useState( EstimateSteps.ContactInformation ) + // const [ submitLoading, setSubmitLoading ] = useState( false ) + // const [ errorMessage, setErrorMessage ] = useState( null ) + // const [ hasDealer, setHasDealer ] = useState( Truthy.False ) + + + const onConfirm = useCallback( () => { + const json = JSON.parse( localStorage.getItem( "dock" ) ) + editor.loadFromJSON( json, () => { + editor.renderAll() + }, ( o ) => { + // console.log( o ) + } ) + modalCloseClick() + }, [ editor ] ) + + return ( + +
+
+ Would You Like to Continue Building Dock From Last Save? +
+ +
+ + + +
+
+ + + +
+ ); +} + + +const BuildCanvasFromLocalModalMemo = memo( BuildCanvasFromLocalModal ); + +export { BuildCanvasFromLocalModalMemo as BuildCanvasFromLocalModal }; diff --git a/src/components/BuildCanvasFromLocalModal/index.js b/src/components/BuildCanvasFromLocalModal/index.js new file mode 100644 index 0000000..74b74de --- /dev/null +++ b/src/components/BuildCanvasFromLocalModal/index.js @@ -0,0 +1 @@ +export { BuildCanvasFromLocalModal } from './BuildCanvasFromLocalModal' \ No newline at end of file diff --git a/src/components/Builder/Builder.jsx b/src/components/Builder/Builder.jsx new file mode 100644 index 0000000..67d72e6 --- /dev/null +++ b/src/components/Builder/Builder.jsx @@ -0,0 +1,758 @@ +import React, { useCallback, useEffect, useState } from "react"; +// import { Tabs } from 'Components/Tabs' +// import { TabNames } from 'Utils' +import { fabric } from "fabric"; +import { + GrayMaterial, + PerforatedMaterial, + WoodgrainMaterial +} from "Assets/images"; +import { + DockPanelCategories, + MaterialType, + DockPanelCategoryMap, + CylinderType +} from "Utils/constants"; +import { Chevron } from "Assets/svgs"; +import MkdSDK from "Utils/MkdSDK"; +import { oneFeet, scaleFactor, Tables } from "Utils/constants"; +import { + getCategory, + getMaterial, + getRampsCategory, + getWedgesAndRampsMaterial, + getWedgesCategory +} from "Utils/utils"; + +const sdk = new MkdSDK(); +export const Builder = ({ editor }) => { + // let scaleFactor = 0.2; + const [activeMaterial, setActiveMaterial] = useState(MaterialType.Gray); + const [activeDockCategory, setActiveDockCategory] = useState( + DockPanelCategories.RollIn + ); + const rampsInitialState = { + data: [] + }; + // const [ramps, setRamps] = useState(null); + const [activeLiftRange, setActiveLiftRange] = useState(null); + const [dock, setDock] = useState([]); + const [docks, setDocks] = useState([]); + const [accessories, setAccessories] = useState([]); + const [boatlifts, setBoatlifts] = useState([]); + const [wedgesAndRamps, setWedgesAndRamps] = useState({ + wedges: [], + ramps: [], + selectedRamps: [], + selectedWedges: [] + }); + const [boatLift, setBoatLift] = useState([]); + const [liftRanges, setLiftRanges] = useState([]); + const [left, setLeft] = useState(300); + // const [ rollinDock, setRollinDock ] = useState( null ) + // const [ floatingDock, setFloatingDock ] = useState( null ) + // const [ sectionalDock, setSectionalDock ] = useState( null ) + + const onMaterialClick = useCallback( + (material) => { + setActiveMaterial(material); + }, + [activeMaterial] + ); + + const onDockSelect = useCallback((dock) => { + if (!editor) { + return; + } + const editorHeight = editor.getHeight(); + const division = editorHeight / oneFeet - 4; + + let imageTopViewURL; + let materials; + let category; + if (["wedges", "ramps"].includes(dock?.type)) { + imageTopViewURL = (dock?.top_view).replace("%20", "+"); + + materials = getWedgesAndRampsMaterial(dock?.material); + } else { + imageTopViewURL = dock?.top_view; + materials = getMaterial(dock?.materials); + } + + if (["ramps"].includes(dock?.type)) { + category = getRampsCategory(dock?.category); + } else if (["wedges"].includes(dock?.type)) { + category = getWedgesCategory(dock?.category); + } else { + category = getCategory(dock?.category); + } + + const dockData = { + itemName: activeDockCategory, + image: dock?.image, + category: category, + length: dock?.length, + materials: materials, + top_view: dock?.top_view, + width: dock?.width, + lift_range: dock?.lift_range, + model: dock?.model, + no_of_cylinders: dock?.no_of_cylinders, + name: dock?.name, + thumbnail: dock?.thumbnail, + weight_capacity: dock?.weight_capacity + }; + + // TODO: Add dock to editor + // TODO: object which is the image should have the dockData, snapAngle of 45, snapThreshold of 5 + // TODO: image should be scaled down by scaleFactor + // TODO: image should be positioned at the top left of the editor + // TODO: image should be added to the editor + // TODO: render the editor + }, []); + + const getItems = useCallback((table) => { + // console.log( category, materials ); + (async () => { + try { + // sdk.setTable( table ); + const result = await sdk.getItems(table); + // console.log( result ) + switch (table) { + case Tables.Docks: + return setDocks(() => + result?.model + ? [...result?.model.map((item) => ({ ...item, type: "docks" }))] + : [] + ); + + case Tables.Boat_lifts: + // return console.log( result ) + const liftRanges = result?.model + .filter((boatLift, index, self) => { + return ( + index === + self.findIndex( + (selfItem) => selfItem.lift_range === boatLift.lift_range + ) + ); + }) + .map((item) => item.lift_range); + setLiftRanges(liftRanges.sort()); + setActiveLiftRange(liftRanges.sort()[0]); + return setBoatlifts(() => + result?.model + ? [ + ...result?.model.map((item) => ({ + ...item, + type: "boatlifts" + })) + ] + : [] + ); + + case Tables.Accessories: + // return console.log( result ) + return setAccessories(() => + result?.model + ? [ + ...result?.model.map((item) => ({ + ...item, + type: "accessories" + })) + ] + : [] + ); + case Tables.Wedges: + // return console.log( result ) + return setWedgesAndRamps((prev) => ({ + ...prev, + wedges: result?.model + ? [ + ...result?.model.map((item) => ({ + ...item, + type: "wedges" + })) + ] + : [] + })); + case Tables.Ramps: + // return console.log( result ) + return setWedgesAndRamps((prev) => ({ + ...prev, + ramps: result?.model + ? [...result?.model.map((item) => ({ ...item, type: "ramps" }))] + : [] + })); + // return setRamps(() => [...result?.model]); + } + } catch (error) { + console.log(error.message); + } + })(); + }, []); + + const onDockPanelClick = useCallback( + (dockCategory) => { + if (dockCategory !== activeDockCategory) { + setActiveDockCategory(dockCategory); + } else { + setActiveDockCategory(""); + } + }, + [activeDockCategory] + ); + + useEffect(() => { + if (!docks.length) { + // console.log( "I ran Docks" ) + getItems(Tables.Docks); + } + if (!accessories.length) { + // console.log( "I ran Accessories" ) + getItems(Tables.Accessories); + } + if (!wedgesAndRamps?.wedges?.length) { + // console.log( "I ran Wedges" ) + getItems(Tables.Wedges); + } + if (!wedgesAndRamps?.ramps?.length) { + // console.log( "I ran Ramps" ) + getItems(Tables.Ramps); + } + if (!boatlifts.length) { + // console.log( "I ran Boat_lifts" ) + getItems(Tables.Boat_lifts); + } + }, [docks, accessories, boatlifts]); + + useEffect(() => { + if ( + [ + DockPanelCategories.RollIn, + DockPanelCategories.Floating, + DockPanelCategories.Sectional + ].includes(activeDockCategory) + ) { + // console.log( activeDockCategory, activeMaterial ) + const category = + activeDockCategory === DockPanelCategories.RollIn + ? DockPanelCategoryMap.RollIn + : activeDockCategory === DockPanelCategories.Floating + ? DockPanelCategoryMap.Floating + : activeDockCategory === DockPanelCategories.Sectional + ? DockPanelCategoryMap.Sectional + : null; + + const dockObj = docks + .map((dock) => { + if (dock.category === category && dock.materials === activeMaterial) { + return dock; + } + }) + .filter(Boolean); + // console.log( dockObj ) + setDock(() => [...dockObj]); + } + if (DockPanelCategories.Wedges === activeDockCategory) { + } + }, [activeMaterial, activeDockCategory, docks, wedgesAndRamps]); + + useEffect(() => { + if ( + [DockPanelCategories.BoatLift2, DockPanelCategories.BoatLift4].includes( + activeDockCategory + ) + ) { + // console.log( activeDockCategory, activeLiftRange ) + const cylinder = CylinderType[activeDockCategory]; + + const boatliftsObj = boatlifts + .map((boatlift) => { + if (boatlift.no_of_cylinders === cylinder) { + return boatlift; + } + }) + .filter(Boolean); + // console.log( boatliftsObj ) + setBoatLift(() => [...boatliftsObj]); + } + }, [activeLiftRange, boatlifts, activeDockCategory]); + // useEffect(() => { + // (async () => { + // await sdk.projectHealth(); + // })(); + // }, []); + + return ( +
+
+
onMaterialClick(MaterialType.Gray)} + className={`grow h-full px-[12px] py-[5px] flex justify-center items-center cursor-pointer + ${ + activeMaterial === MaterialType.Gray + ? " bg-white border-transparent" + : "bg-gray-200" + }`} + > + GreyMaterial +
+ +
onMaterialClick(MaterialType.Perforated)} + className={`grow h-full px-[12px] py-[5px] flex justify-center items-center cursor-pointer + ${ + activeMaterial === MaterialType.Perforated + ? " bg-white border-transparent" + : "bg-gray-200" + }`} + > + PerforatedMaterial +
+ +
onMaterialClick(MaterialType.Woodgrain)} + className={`grow h-full px-[12px] py-[5px] flex justify-center items-center cursor-pointer + ${ + activeMaterial === MaterialType.Woodgrain + ? " bg-white border-transparent" + : "bg-gray-200" + }`} + > + WoodgrainMaterial +
+
+
+
+
onDockPanelClick(DockPanelCategories.RollIn)} + className={`w-full h-[67px] z-30 flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.RollIn} +
+
+ {dock.length ? ( + <> + +
+ {dock?.map((dockItem, index) => ( + + ))} +
+ + ) : null} +
+ +
onDockPanelClick(DockPanelCategories.Floating)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.Floating} +
+
+ {dock.length ? ( + <> + +
+ {dock?.map((dockItem, index) => ( + + ))} +
+ + ) : null} +
+ +
onDockPanelClick(DockPanelCategories.Sectional)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.Sectional} +
+
+ {dock.length ? ( + <> + +
+ {dock?.map((dockItem, index) => ( + + ))} +
+ + ) : null} +
+
onDockPanelClick(DockPanelCategories.Wedges)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.Wedges} +
+
+ {wedgesAndRamps?.wedges.length ? ( + <> + +
+ {wedgesAndRamps?.wedges?.map((dockItem, index) => ( + + ))} +
+ + ) : null} +
+
onDockPanelClick(DockPanelCategories.Ramps)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.Ramps} +
+
+ {wedgesAndRamps.ramps.length ? ( + <> + +
+ {wedgesAndRamps.ramps?.map((dockItem, index) => ( + + ))} +
+ + ) : null} +
+
onDockPanelClick(DockPanelCategories.BoatLift2)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.BoatLift2} +
+
+ {boatLift.length ? ( + <> +
+
+ Lift Range +
+
+ {liftRanges.map((liftRange) => ( + + ))} +
+
+ +
+ {boatLift?.map((dockItem, index) => { + if (dockItem?.lift_range === activeLiftRange) { + return ( +
+ +
+ ); + } + })} +
+ + ) : null} +
+ +
onDockPanelClick(DockPanelCategories.BoatLift4)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.BoatLift4} +
+
+ {boatLift.length ? ( + <> +
+
+ Lift Range +
+
+ {liftRanges.map((liftRange) => ( + + ))} +
+
+ +
+ {boatLift?.map((dockItem, index) => { + if (dockItem?.lift_range === activeLiftRange) { + return ( +
+ +
+ ); + } + })} +
+ + ) : null} +
+ +
onDockPanelClick(DockPanelCategories.Accessories)} + className={`w-full h-[67px] z-30 border-b-2 border-b-[#B9C0D4] flex items-center pl-3 gap-x-1 font-bold text-[18px] leading-[150%] tracking-tight text-[#111322] cursor-pointer`} + > + + {DockPanelCategories.Accessories} +
+
+ {accessories.length ? ( + <> +
+ {accessories?.map((dockItem, index) => ( +
onDockSelect(dockItem)} + className={`h-fit rounded mx-1 mt-1 border border-[#B9C0D4] cursor-pointer`} + > + {/*
+ { dockItem.width }' + x + { dockItem.length }' */} + + {/*
*/} +
+ ))} +
+ + ) : null} +
+
+
+
+ ); +}; + +{ + /*
+ +
*/ +} diff --git a/src/components/Builder/index.js b/src/components/Builder/index.js new file mode 100644 index 0000000..e0effd9 --- /dev/null +++ b/src/components/Builder/index.js @@ -0,0 +1 @@ +export { Builder } from './Builder' \ No newline at end of file diff --git a/src/components/Comments/Comments.jsx b/src/components/Comments/Comments.jsx new file mode 100644 index 0000000..17f1b7d --- /dev/null +++ b/src/components/Comments/Comments.jsx @@ -0,0 +1,80 @@ +import React, { memo } from 'react'; +import { ArrowLeftIcon, ArrowRrightIcon, } from 'Assets/svgs'; +import { EstimateSteps, } from 'Utils/constants'; + +const Comments = ( { step, onStepChange, onUpdateComment, onSubmit, errorMessage, submitLoading, comments } ) => { + + {/* Comments */ } + + return ( + +
+ +
+ +
+

Comments

+ (3 of 3) +
+
+
+
+ +
+
+ {/* */} +
+ + +
+
+
+
+ +
+

{ errorMessage }

+
+ ); +} + + +const CommentsMemo = memo( Comments ); + +export { CommentsMemo as Comments }; diff --git a/src/components/Comments/index.js b/src/components/Comments/index.js new file mode 100644 index 0000000..25cf78d --- /dev/null +++ b/src/components/Comments/index.js @@ -0,0 +1 @@ +export { Comments } from './Comments' \ No newline at end of file diff --git a/src/components/ContactInformation/ContactInformation.jsx b/src/components/ContactInformation/ContactInformation.jsx new file mode 100644 index 0000000..cf9dcce --- /dev/null +++ b/src/components/ContactInformation/ContactInformation.jsx @@ -0,0 +1,324 @@ +import React, { memo, useState, useCallback, useEffect } from 'react'; +import { ArrowRrightIcon } from 'Assets/svgs'; +import { EstimateSteps, Tables, Truthy } from 'Utils/constants'; +import MkdSDK from 'Utils/MkdSDK'; + +const sdk = new MkdSDK() +const ContactInformation = ( { + step, + onStepChange, + hasDealer, + onHasDealerChange, + onDealerChange, + setFirstName, + setLastName, + setEmail, + setPhone, + setLake, + setCity, + setCountry, +} ) => { + + const [ TC, setTC ] = useState( false ) + const [ dealers, setDealers ] = useState( [] ) + + const getDealers = useCallback( ( table ) => { + ( async () => { + try { + const result = await sdk.getItems( table ) + setDealers( result?.model ) + } catch ( error ) { + console.log( error.message ) + } + } )() + }, [ dealers ] ) + + useEffect( () => { + if ( !dealers.length ) { + getDealers( Tables.Dealers ) + } + }, [ dealers ] ) + + {/* ContactInformation */ } + return ( +
+ +
+
+

Contact information

+ (1 of 3) +
+
+
+
+
+ +
+ {/*
+ +
*/} + setFirstName( e.target.value ) } + /> +
+
+
+ +
+
+ {/* */} +
+ setLastName( e.target.value ) } + /> +
+
+
+
+ +
+
+ {/* */} +
+ setEmail( e.target.value ) } + /> +
+
+
+ +
+
+ {/* */} +
+ setPhone( e.target.value ) } + /> +
+
+
+
+ +
+
+ {/* */} +
+ setLake( e.target.value ) } + /> +
+
+
+ +
+
+ {/* */} +
+ setCity( e.target.value ) } + /> +
+
+
+ +
+ {/*
+ +
*/} + +
+
+
+
+ +
+ onHasDealerChange( Truthy.True ) } + /> + + onHasDealerChange( Truthy.False ) } + /> + +
+
+ { hasDealer ? +
+ +
+ {/*
+ +
*/} + +
+
+ : null + } +
+
+ + setTC( e.target.checked ) } + /> + +
+
+
+
+ +
+
+ ); +} + + +const ContactInformationMemo = memo( ContactInformation ); + +export { ContactInformationMemo as ContactInformation }; diff --git a/src/components/ContactInformation/index.js b/src/components/ContactInformation/index.js new file mode 100644 index 0000000..9fb2f0f --- /dev/null +++ b/src/components/ContactInformation/index.js @@ -0,0 +1 @@ +export { ContactInformation } from './ContactInformation' \ No newline at end of file diff --git a/src/components/DockBuilder/DockBuilder.jsx b/src/components/DockBuilder/DockBuilder.jsx new file mode 100644 index 0000000..2392660 --- /dev/null +++ b/src/components/DockBuilder/DockBuilder.jsx @@ -0,0 +1,823 @@ +import React, { + useEffect, + useMemo, + useCallback, + useRef, + useState, + useContext +} from "react"; +import { FabricJSCanvas, useFabricJSEditor } from "fabricjs-react"; +import { fabric } from "fabric"; +import { DockSidebar } from "Components/DockSidebar"; +import { ActionButtons } from "Components/ActionButtons"; +import MkdSDK from "Utils/MkdSDK"; +import { Stack } from "Utils/utils"; +import { EstimateModal } from "Components/EstimateModal"; +import * as XLSX from "xlsx"; +import { BuildCanvasFromLocalModal } from "Components/BuildCanvasFromLocalModal"; +import { GlobalContext } from "../../globalContext"; +import { clearClone, clone } from "Utils/DockBuilderUtils/clone"; +import { + edgeDetection, + handleEdgeDetection, + handleIntersection +} from "Utils/DockBuilderUtils"; +import { + CanvasModes, + deleteIcon, + DockPanelCategories, + edgeSnapThreshold, + nintyDeg, + oneEightyDeg, + oneFeet, + rotateIcon, + scaleFactor, + twoSeventyDeg +} from "Utils/constants"; +import { + reScaleXY, + resolveHeight, + resolveWidth +} from "Utils/DockBuilderUtils/edgeDetection"; +import { DeleteIcon, RotateIcon } from "Assets/svgs"; +import { capitalize } from "Utils/helper"; + +const sdk = new MkdSDK(); +const stack = new Stack(); + +export const DockBuilder = () => { + let clipboard = null; + let mouseDownPoint = null; + let shiftKeyDown = false; + window.counter = 0; + let prevPointer = null; + let isDragging = false; + let isZoomed = false; + let startX, startY; + + const { dispatch } = useContext(GlobalContext); + const { editor, onReady } = useFabricJSEditor({ selection: true }); + + const canvasModeRef = useRef(null); + const fileRef = useRef(); + const imageRef = useRef(); + + const editorMemo = useMemo(() => editor?.canvas, [editor?.canvas]); + // const { dispatch } = React.useContext( AuthContext ); + const [objHovered, setObjHovered] = useState(false); + const [selectedItems, setSelectedItems] = useState([]); + const [estimateLoading, setEstimateLoading] = useState(false); + const [showEstimateModal, setShowEstimateModal] = useState(false); + const [showBuildCanvasFromLocalModal, setShowBuildCanvasFromLocalModal] = + useState(false); + const [initialLoad, setInitialLoad] = useState(true); + const [linesAdded, setLinesAdded] = useState(false); + const [dockImage, setDockImage] = useState(null); + const [editorReady, setEditorReady] = useState(false); + const [dockLabel, setDockLabel] = useState(null); + const [dockDimensions, setDockDimensions] = useState(null); + + const deleteImg = document.createElement("img"); + deleteImg.src = deleteIcon; + const rotateImg = document.createElement("img"); + rotateImg.src = rotateIcon; + + const onEstimateModalClose = useCallback(() => { + setShowEstimateModal(false); + }, [showEstimateModal]); + + const onEstimateModalOpen = useCallback(() => { + const ext = "png"; + const base64 = editorMemo.toDataURL({ + format: ext, + enableRetinaScaling: true + }); + setDockImage(base64); + setShowEstimateModal(true); + }, [showEstimateModal, editorMemo, dockImage]); + + // const onAddRect = useCallback( () => { + // editor?.canvas?.add( rect ); + // window.counter++; + // // newleft += 200; + // }, [ editor ] ); + + const toJSON = () => { + // TODO: download the json file + // TODO: get json of editor content + // TODO: Ensure dockData is included in the json + // TODO: save the json to the local storage as dock + // TODO: name the file as paradise_dock_.dock + }; + + const uploadFile = (e) => { + // TODO: Our own upload the file we must have downloaded previously + // TODO: extract the json from the file + // TODO: load the json to the editor + // TODO: render all + }; + + const downloadImage = useCallback(() => { + // // console.log( 'Download' ) + const ext = "png"; + + // TODO: download the image + // TODO: get the json of the editor content + // TODO: extract the dockData from the json + // TODO: filter the dockData to ensure it does not contain snapClone + // TODO: generate the base64 image + // TODO: download the image and name it as paradise_dock_snapshot_.${ext} + // TODO: download the excel file of the dockData you extracted + + // TODO: check if dockData is empty + // TODO: generate the base64 image + + // TODO: trigger download of the dockData you extracted in excel format + }, [editorMemo]); + + const renderBg = useCallback(() => { + const imageURL = + "https://s3.us-east-2.amazonaws.com/com.nds.images/download.png"; + + new fabric.Image.fromURL( + imageURL, + function (img) { + img.set({ + scaleX: editorMemo.width / img.width, + scaleY: editorMemo.height / img.height + }); + editorMemo.setBackgroundImage(img); + editorMemo.renderAll(); + // updateModifications( true, ) + }, + { + crossOrigin: "anonymous" + } + ); + }, [editorMemo]); + + const downloadExcel = useCallback((data) => { + const worksheet = XLSX.utils.json_to_sheet(data); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, "Selected Items"); + XLSX.writeFile(workbook, "Paradise_dock_selected_items.xlsx"); + }, []); + + function updateZoom(opt) { + let delta = opt.e.deltaY; + let pointer = editorMemo.getPointer(opt.e); + let zoom = editorMemo.getZoom(); + + if (delta > 0) { + zoom *= 1.1; + } else { + zoom /= 1.1; + } + if (zoom > 5) zoom = 5; + if (zoom < 1) zoom = 1; + // console.log( zoom ) + // editorMemo.setBackgroundImageStretch=false + var vpt = editorMemo.viewportTransform; + if (zoom === 1) { + vpt[4] = 0; + vpt[5] = 0; + editorMemo.selection = true; + this.isZoomed = false; + } + if (zoom > 1) { + this.isZoomed = true; + } + + fabric.util.animate({ + startValue: editorMemo.getZoom(), + endValue: zoom, + // duration: 0, + onChange: function (value) { + editorMemo.zoomToPoint({ x: pointer.x, y: pointer.y }, value); + }, + fps: 1080 + }); + opt.e.preventDefault(); + opt.e.stopPropagation(); + } + + function handleZoomMouseDown(options) { + var pointer = editorMemo.getPointer(options.e, true); + mouseDownPoint = new fabric.Point(pointer.x, pointer.y); + if (options.target === null && this.isZoomed) { + editorMemo.upperCanvasEl.style.cursor = "grabbing"; + editorMemo.selection = false; + // this.lastPosX = options.e.movementX; + // this.lastPosY = options.e.movementY; + this.lastPosX = options.e.clientX; + this.lastPosY = options.e.clientY; + + // + } + // else if ( options.target !== null && this.isZoomed ) { + // var activeObject = editorMemo.getActiveObject(); + // if ( activeObject ) { + // activeObject.lockMovementX = true; + // activeObject.lockMovementY = true; + // activeObject.lockScalingX = true; + // activeObject.lockScalingY = true; + // } + // } + } + + const handleZoomMouseUp = useCallback(() => { + editorMemo.defaultCursor = "default"; + mouseDownPoint = null; + editorMemo.selection = true; + }, [editor]); + + function handleZoomMouseMove(options) { + if (options.target === null && mouseDownPoint && this.isZoomed) { + editorMemo.selection = false; + editorMemo.upperCanvasEl.style.cursor = "grabbing"; + + var delta = new fabric.Point(options.e.movementX, options.e.movementY); + editorMemo.relativePan(delta); + editorMemo.viewportTransform[4] = Math.max( + Math.min(editorMemo.viewportTransform[4], 0), + editorMemo.getWidth() - editorMemo.getWidth() * editorMemo.getZoom() + ); + editorMemo.viewportTransform[5] = Math.max( + Math.min(editorMemo.viewportTransform[5], 0), + editorMemo.getHeight() - editorMemo.getHeight() * editorMemo.getZoom() + ); + + // var vpt = this.viewportTransform; + // vpt[ 4 ] += options.e.clientX - this.lastPosX; + // vpt[ 5 ] += options.e.clientY - this.lastPosY; + requestAnimationFrame(function () { + editorMemo.renderAll(); + this.requestRenderAll(); + }); + // this.lastPosX = options.e.movementX; + // this.lastPosY = options.e.movementY; + // this.lastPosX = options.e.clientX; + // this.lastPosY = options.e.clientY; + } + } + + const addEdgeDetectionClone = useCallback( + (options) => { + objectMoving = true; + if (options) { + const selectedObj = options.target.setCoords(); + editorMemo.defaultCursor = "grabbing"; + if ( + selectedObj.dockData && + selectedObj.dockData.itemName === DockPanelCategories.Accessories + ) { + return; + } + + editorMemo.forEachObject((obj) => { + const pointer = { x: options.e.clientX, y: options.e.clientY }; + + if (obj === selectedObj) return; + // canvas.setCursor('grabbing'); + // // console.log(pointer.x, pointer.y); + if (!obj.snapClone && obj.type === "image") { + // // console.log( pointer, prevPointer ) + if ( + prevPointer && + (prevPointer.x !== pointer.x || prevPointer.y !== pointer.y) + ) { + switch (true) { + case edgeDetection(selectedObj, obj, "left"): + clone(selectedObj, editorMemo, obj, "left"); + break; + case edgeDetection(selectedObj, obj, "right"): + clone(selectedObj, editorMemo, obj, "right"); + break; + case edgeDetection(selectedObj, obj, "top"): + clone(selectedObj, editorMemo, obj, "top"); + break; + case edgeDetection(selectedObj, obj, "bottom"): + clone(selectedObj, editorMemo, obj, "bottom"); + break; + case edgeDetection(selectedObj, obj, "neutral"): + clearClone(editorMemo); + break; + default: + // console.log( "edge detection switch default" ) + } + // prevPointer = null; + } + prevPointer = pointer; + // // console.log( pointer, prevPointer ) + } + // if ( edgeDetection( selectedObj, obj, "left" ) ) { + // clone( selectedObj, editorMemo, obj, "left" ) + // } else { + // // clearClone( editorMemo ) + // } + + // if ( edgeDetection( selectedObj, obj, 'right' ) ) { + // clone( selectedObj, editorMemo, obj, "right" ) + + // } else { + // // clearClone( editorMemo ) + // } + + // if ( edgeDetection( selectedObj, obj, 'top' ) ) { + // clone( selectedObj, editorMemo, obj, "top" ) + + // } else { + // // clearClone( editorMemo ) + // } + + // if ( edgeDetection( selectedObj, obj, 'bottom' ) ) { + // clone( selectedObj, editorMemo, obj, "bottom" ) + // } else { + // // clearClone( editorMemo ) + // } + }); + } + }, + [editor, editorMemo] + ); + + const horizontalIndicatorLines = (newTop, objTop) => { + editorMemo.getObjects("line").forEach((obj) => { + if (obj.testLine) { + editorMemo.remove(obj); + } + }); + + let line = new fabric.Line([0, newTop, editorMemo.getWidth(), newTop], { + stroke: "#AAAAAA", + testLine: true + // strokeDashArray: [ 5 ], + }); + let line2 = new fabric.Line([0, objTop, editorMemo.getWidth(), objTop], { + stroke: "#AAAAAA", + testLine: true + // strokeDashArray: [ 5 ], + }); + editorMemo.add(line); + editorMemo.add(line2); + editorMemo.renderAll(); + }; + const verticleIndicatorLines = (newLeft, objLeft) => { + editorMemo.getObjects("line").forEach((obj) => { + if (obj.testLine) { + editorMemo.remove(obj); + } + }); + + let line = new fabric.Line([newLeft, 0, newLeft, editorMemo.getHeight()], { + stroke: "#AAAAAA", + testLine: true + // strokeDashArray: [ 5 ], + }); + let line2 = new fabric.Line([objLeft, 0, objLeft, editorMemo.getWidth()], { + stroke: "#AAAAAA", + testLine: true + // strokeDashArray: [ 5 ], + }); + editorMemo.add(line); + editorMemo.add(line2); + editorMemo.renderAll(); + }; + + function edgeDetectionAndSnap(options) { + if (this.isZoomed) { + return; + } + + // TODO: Edge detection and snap to object within snap range + // TODO: Detect if the object is within the snap range of the selected object + // TODO: detect if the selected object contains dockData and dockData contains itemName of DockPanelCategories.Accessories || DockPanelCategories.BoatLift2 || DockPanelCategories.BoatLift4 + // TODO: handle rotation of 0, 90, 180, 270 degrees + + editorMemo.defaultCursor = "default"; + prevPointer = null; + clearClone(editorMemo); + } + + const showHighlight = useCallback( + (event) => { + if (event.target) { + if (event.target.type === "image") { + setObjHovered(true); + // console.log(event.target.dockData) + if ( + event.target && + event.target.dockData && + event.target.dockData.image + ) { + imageRef.current.src = event.target.dockData.image; + setDockLabel( + `${ + event.target.dockData.materials + ? capitalize(event.target.dockData.itemName) + : event.target.dockData.itemName + } (${ + event.target.dockData.materials + ? event.target.dockData.materials + : event.target.dockData.model + })` + ); + setDockDimensions( + `${event.target.dockData.width}' x ${event.target.dockData.length}'` + ); + } else if ( + event.target && + event.target.dockData && + event.target.dockData.thumbnail + ) { + setDockLabel( + `${capitalize(event.target.dockData.itemName)} (${ + event.target.dockData.name + })` + ); + setDockDimensions( + `${event.target.dockData.width}' x ${event.target.dockData.length}'` + ); + imageRef.current.src = event.target.dockData.thumbnail; + } + } + } + if (!event.target && objHovered) { + setObjHovered(false); + setDockLabel(null); + setDockDimensions(null); + setDockDimensions(null); + imageRef.current.src = ""; + } + }, + [objHovered] + ); + + const hideHighlight = useCallback(() => { + if (objHovered) { + setObjHovered(false); + setDockLabel(null); + setDockDimensions(null); + imageRef.current.src = ""; + } + }, [objHovered]); + + const updateModifications = useCallback( + (savehistory, event) => { + if (savehistory === true) { + if ((event && event === "update") || event.target.dockData) { + const json = editor?.canvas?.toJSON(["dockData", "snapClone"]); + const data = JSON.stringify(json); + stack.updateStack(data); + + updateLocalstore(); + } + } + }, + [selectedItems, editor] + ); + + const updateLocalstore = useCallback(() => { + const json = editor?.canvas?.toJSON(["dockData", "snapClone"]); + const newObjects = json.objects + .filter((object) => !object.snapClone) + .filter(Boolean); + json.objects = newObjects; + const items = json.objects + .map((object) => { + if (object.dockData && !object.snapClone) { + return object.dockData; + } + }) + .filter(Boolean); + setSelectedItems(() => [...items]); + + const data = JSON.stringify(json); + localStorage.setItem("dock", data); + }, [editor, selectedItems]); + + const onUndoClick = useCallback(() => { + // TODO: Undo + }, [editorMemo]); + + const onRedoClick = useCallback(() => { + // TODO: Redo + }, [editorMemo]); + + const onPrintScreen = useCallback(() => { + // convert the canvas to a data url and download it. + // TODO: Print screen + // TODO: print screen without background image and background color, the background image should be white + // TODO: after printing, the background image and background color should be restored + }, [editorMemo]); + + const CopySelection = () => { + // TODO: Copy selection + }; + + const PasteSelection = () => { + // TODO: Paste selection + }; + + const onDeleteSelection = () => { + // TODO: Delete selection + }; + + const addLines = useCallback(() => { + // Initiate a line instance + const editorHeight = editorMemo.getHeight(); + const division = editorHeight / oneFeet; + + if (!linesAdded) { + let initialFt = 8; + let multiplier = 1; + for (let i = division - 3; i > 0; i--) { + if (multiplier > division - 4) { + break; + } + let line = new fabric.Line( + [0, oneFeet * i, editorMemo.getWidth(), oneFeet * i], + { + stroke: "#AAAAAA", + strokeDashArray: [5] + } + ); + + let text = new fabric.Text(`${initialFt * multiplier}ft`, { + // stroke: '#000000', + fill: "#AAAAAA", + fontSize: 18, + left: editorMemo.getWidth() - 40, + top: oneFeet * i + }); + + multiplier++; + // Render the rectangle in canvas + editorMemo.add(line).sendToBack(line); + editorMemo.add(text).sendToBack(text); + editorMemo.renderAll(); + } + setLinesAdded(true); + } + }, [editorMemo, linesAdded]); + + const removeLines = useCallback(() => { + editorMemo.getObjects("line").forEach((line) => { + editorMemo.remove(line); + }); + editorMemo.getObjects("text").forEach((text) => { + editorMemo.remove(text); + }); + setLinesAdded(false); + }, [editorMemo, linesAdded]); + + const onCloseBuildFromLocalModal = useCallback(() => { + setShowBuildCanvasFromLocalModal(false); + + dispatch({ + type: "DOCK_LOADING", + payload: false + }); + setInitialLoad(false); + }, [editorMemo, showBuildCanvasFromLocalModal, dispatch, initialLoad]); + function renderIcon(icon) { + return function renderIcon(ctx, left, top, styleOverride, fabricObject) { + var size = this.cornerSize; + ctx.save(); + ctx.translate(left, top); + ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle)); + ctx.drawImage(icon, -size / 2, -size / 2, size, size); + ctx.restore(); + }; + } + function deleteObject(eventData, transform) { + var target = transform.target; + var canvas = target.canvas; + canvas.remove(target); + canvas.requestRenderAll(); + } + + useEffect(() => { + if (editor) { + editorMemo.backgroundColor = "#011e23"; + editorMemo.enableRetinaScaling = false; + + // Use hardware acceleration + // editorMemo.renderOnAddRemove = false; + editorMemo.skipOffscreen = true; + // Lower render quality setting + fabric.devicePixelRatio = 1; + fabric.Group.prototype.hasControls = true; + fabric.Group.prototype.snapAngle = 45; + fabric.Group.prototype.snapThreshold = 5; + fabric.Group.prototype.stroke = "#0f75bc"; + fabric.Object.prototype.snapAngle = 45; + // Optimize object rendering + fabric.Object.prototype.objectCaching = true; + + fabric.Object.prototype.snapThreshold = 5; + fabric.Object.prototype.setControlsVisibility({ + tl: false, //top-left + mt: false, // middle-top + tr: true, //top-right + ml: false, //middle-left + mr: false, //middle-right + bl: false, // bottom-left + mb: false, //middle-bottom + br: false, //bottom-right + mtr: false // rotate icon + }); + // fabric.Object.prototype.controls.deleteControl = new fabric.Control( { + // x: -0.8, + // y: -1, + // offsetY: 16, + // offsetX: 16, + // cursorStyle: 'pointer', + // mouseUpHandler: deleteObject, + // render: renderIcon( deleteImg ), + // cornerPadding: 0, + // cornerSize: 24 + // } ); + fabric.Object.prototype.controls.tr = new fabric.Control({ + x: 0.5, + y: -0.5, + cursorStyle: "rotate", + offsetY: -16, + offsetX: 16, + cornerPadding: 0, + actionHandler: fabric.controlsUtils.rotationWithSnapping, + cursorStyleHandler: fabric.controlsUtils.rotationStyleHandler, + withConnection: true, + render: renderIcon(rotateImg), + cornerSize: 20, + actionName: "rotate", + sizeX: 40, + sizeY: 40, + touchSizeX: 40, + touchSizeY: 40 + }); + fabric.Object.prototype.hasControls = true; + fabric.Object.prototype.lockScalingX = true; + fabric.Object.prototype.lockScalingY = true; + fabric.Object.prototype.cornerSize = 5; + fabric.Line.prototype.hasBorders = false; + fabric.Line.prototype.cornerSize = 0; + fabric.Line.prototype.borderColor = "transparent"; + fabric.Line.prototype.hasRotatingPoint = false; + fabric.Line.prototype.hasControls = false; + fabric.Line.prototype.lockRotation = true; + fabric.Line.prototype.hoverCursor = "default"; + fabric.Line.prototype.selectable = false; + fabric.Line.prototype.lockMovementX = true; + fabric.Line.prototype.lockMovementY = true; + fabric.Text.prototype.hasBorders = false; + fabric.Text.prototype.cornerSize = 0; + fabric.Text.prototype.borderColor = "transparent"; + fabric.Text.prototype.hasRotatingPoint = false; + fabric.Text.prototype.hoverCursor = "default"; + fabric.Text.prototype.selectable = false; + fabric.Text.prototype.hasControls = false; + fabric.Text.prototype.lockRotation = true; + fabric.Text.prototype.lockMovementX = true; + fabric.Text.prototype.lockMovementY = true; + + // fabric.Text.prototype.viewportCenter = true + setEditorReady(true); + editorMemo.setHeight(window.innerHeight); + editorMemo.setWidth(window.innerWidth); + fabric.Object.prototype.cornerColor = "#B9C0D4"; + + renderBg(); + addLines(); + + // Intersection + // TODO: Edge detection and snap to object within snap range + editorMemo.on("object:moving", edgeDetectionAndSnap); + + editorMemo.on("mouse:over", showHighlight); + editorMemo.on("mouse:out", hideHighlight); + editorMemo.on("object:modified", (e) => updateModifications(true, e)); + editorMemo.on("object:added", (e) => updateModifications(true, e)); + + // Listen for the delete key event + document.onkeydown = (event) => { + if (event.keyCode === 46) { + // 46 is the keyCode for the delete key + onDeleteSelection(); + } + }; + + const savedDock = localStorage.getItem("dock") + ? JSON.parse(localStorage.getItem("dock")) + : null; + if (savedDock) { + if (initialLoad) { + setShowBuildCanvasFromLocalModal(true); + } + } else if (initialLoad) { + setInitialLoad(false); + dispatch({ + type: "DOCK_LOADING", + payload: false + }); + } + } + }, [editor]); + + useEffect(() => { + if (editor) { + const handleResize = () => { + // let canvas = canvasRef.current; + editorMemo.setWidth(window.innerWidth); + editorMemo.setHeight(window.innerHeight); + editorMemo.setBackgroundImage(editorMemo.backgroundImage, (bgImage) => { + bgImage.set({ + scaleX: editorMemo.width / bgImage.width, + scaleY: editorMemo.height / bgImage.height + }); + }); + removeLines(); + addLines(); + editorMemo.renderAll(); + }; + window.addEventListener("resize", handleResize); + handleResize(); + return () => { + window.removeEventListener("resize", handleResize); + }; + } + }, []); + + return ( +
+ <> + + + + + + +
+ {dockLabel ? ( +
+ {dockLabel} +
+ ) : null} + + + + {dockDimensions ? ( +
+ {dockDimensions} +
+ ) : null} +
+ + + + +
+ ); +}; diff --git a/src/components/DockBuilder/index.js b/src/components/DockBuilder/index.js new file mode 100644 index 0000000..879ff23 --- /dev/null +++ b/src/components/DockBuilder/index.js @@ -0,0 +1 @@ +export { DockBuilder } from './DockBuilder' \ No newline at end of file diff --git a/src/components/DockSidebar/DockSidebar.jsx b/src/components/DockSidebar/DockSidebar.jsx new file mode 100644 index 0000000..e447940 --- /dev/null +++ b/src/components/DockSidebar/DockSidebar.jsx @@ -0,0 +1,73 @@ +import React, { useCallback, useContext } from 'react' +import { SidebarLogo } from 'Components/SidebarLogo' +import { GlobalContext } from '../../globalContext' +import { SidebarFoot } from 'Components/SidebarFoot' +import { SidebarBuilder } from 'Components/SidebarBuilder' + +export const DockSidebar = ( { onAddItem, onDownloadImage, onDownloadFile, onUploadFile, fileRef, editor, updateModifications, selectedItems, onEstimateModalOpen } ) => { + const { state, dispatch } = useContext( GlobalContext ) + const { dockSideBarOpen } = state + let toggleOpen = ( open ) => + dispatch( { + type: "TOGGLE_DOCK_SIDEBAR", + payload: { dockSideBarOpen: open }, + } ); + + const onWheel = useCallback( ( e ) => { + if ( e.ctrlKey ) { + return e.preventDefault();//prevent zoom + } + + }, [] ); + + return ( +
+
+ + + + +
+ toggleOpen( !dockSideBarOpen ) }> + { !dockSideBarOpen ? ( + + ) : ( + + ) } + +
+ ) +} diff --git a/src/components/DockSidebar/index.js b/src/components/DockSidebar/index.js new file mode 100644 index 0000000..e46adcf --- /dev/null +++ b/src/components/DockSidebar/index.js @@ -0,0 +1 @@ +export { DockSidebar } from './DockSidebar' \ No newline at end of file diff --git a/src/components/DynamicContentType.jsx b/src/components/DynamicContentType.jsx new file mode 100644 index 0000000..e8cb43f --- /dev/null +++ b/src/components/DynamicContentType.jsx @@ -0,0 +1,464 @@ +import React from "react"; +import MkdSDK from "../utils/MkdSDK"; +import {empty} from "../utils/utils"; + +const sdk = new MkdSDK(); +const defaultImage = 'https://via.placeholder.com/150?text=%20'; +const DynamicContentType = ({contentType, contentValue, setContentValue}) => { + const [previewUrl, setPreviewUrl] = React.useState(defaultImage); + const handleImageChange = async (e) => { + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setPreviewUrl(result.url); + setContentValue(result.url); + }catch(err) { + console.error(err); + } + + } + switch (contentType) { + case "text": + return ( + <> + + + ) + + case "image": + return ( + <> + preview + + + ) + + case "number": + return ( + setContentValue(e.target.value)} + defaultValue={contentValue} + /> + ) + + case "team-list": + return ( + + ) + + case "image-list": + return ( + + ) + + case "captioned-image-list": + return ( + + ) + + case "kvp": + return ( + + ) + + default: + break; + } +} + +export default DynamicContentType; + +const ImageList = ({contentValue, setContentValue}) => { + let itemsObj = [ + {key: '', value_type: 'image', value: null} + ]; + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + }catch(err) { + console.error(err); + } + } + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + + } + + return ( +
+ {items.map( (item, index) =>
+ preview +
+ + +
+ +
) + } + +
+ + ) +} + +const CaptionedImageList = ({setContentValue, contentValue}) => { + let itemsObj = [ + {key: '', value_type: 'image', value: null, caption: ''} + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + }catch(err) { + console.error(err); + } + } + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleCaptionChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.caption = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map( (item, index) =>
+ preview +
+ + +
+ + +
) + } + +
+ + ) +} +const TeamList = ({setContentValue, contentValue}) => { + let itemsObj = [ + {name: '', image: null, title: ''} + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + const [items, setItems] = React.useState(itemsObj); + + const handleImageChange = async (e) => { + const listKey = e.target.getAttribute('listkey'); + const formData = new FormData(); + formData.append('file', e.target.files[0]); + try { + const result = await sdk.uploadImage(formData); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.image = result.url; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + }catch(err) { + console.error(err); + } + } + + const handleNameChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.name = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleTitleChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.title = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map( (item, index) =>
+ + {/*
*/} + + + preview + + {/*
*/} + + +
) + } + +
+ + ) +} +const KeyValuePair = ({setContentValue, contentValue}) => { + let itemsObj = [ + {key: '', value_type: 'text', value: ''} + ] + + if (!empty(contentValue)) { + itemsObj = JSON.parse(contentValue); + } + + const [items, setItems] = React.useState(itemsObj); + const valueTypeMap = [ + { + key: "text", + value: "Text" + }, + { + key: "number", + value: "Number" + }, + { + key: "json", + value: "JSON Object" + }, + { + key: "url", + value: "URL" + } + ] + + + const handleKeyChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.key = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleValueChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + const handleValueTypeChange = (e) => { + const listKey = e.target.getAttribute('listkey'); + setItems(oldItems => { + let updatedItems = oldItems.map((item, index) => { + if (index == listKey) { + item.value_type = e.target.value; + return item; + } + return item; + }); + return updatedItems; + }) + setContentValue(JSON.stringify(items)) + } + + return ( +
+ {items.map( (item, index) =>
+ + + + + +
) + } + +
+ + ) +} + \ No newline at end of file diff --git a/src/components/EstimateModal/EstimateModal.jsx b/src/components/EstimateModal/EstimateModal.jsx new file mode 100644 index 0000000..d5a8958 --- /dev/null +++ b/src/components/EstimateModal/EstimateModal.jsx @@ -0,0 +1,168 @@ +import React, { memo, useState, useCallback } from 'react'; +import { Modal } from 'Components/Modal'; +import { InteractiveButton } from 'Components/InteractiveButton'; +import { ArrowLeftIcon, ArrowRrightIcon, GreenTickIcon } from 'Assets/svgs'; +import { dock_image, EstimateSteps, Tables, Truthy } from 'Utils/constants'; +import { ContactInformation } from 'Components/ContactInformation'; +import { LakeSurroundings } from 'Components/LakeSurroundings'; +import { Comments } from 'Components/Comments'; +import MkdSDK from 'Utils/MkdSDK'; + +const sdk = new MkdSDK() +const classes = { + modal: 'string', + modalDialog: 'relative bg-white w-[500px]', + modalContent: 'string', + modalHeader: 'string', + modalTitle: 'string', + modalBody: 'string', + modalFooter: 'string', + closeButtonClass: 'string', + saveButtonClass: 'string', +} + +const EstimateModal = ( { + showEstimateModal, + modalCloseClick, + selectedItems, + dockImage, +} ) => { + const [ step, setStep ] = useState( EstimateSteps.ContactInformation ) + const [ submitLoading, setSubmitLoading ] = useState( false ) + const [ errorMessage, setErrorMessage ] = useState( null ) + const [ hasDealer, setHasDealer ] = useState( Truthy.False ) + + // Contact Information + const [ dealer, setDealer ] = useState( 0 ) + const [ firstName, setFirstName ] = useState( '' ) + const [ lastName, setLastName ] = useState( '' ) + const [ email, setEmail ] = useState( '' ) + const [ phone, setPhone ] = useState( '' ) + const [ lake, setLake ] = useState( '' ) + const [ city, setCity ] = useState( '' ) + const [ country, setCountry ] = useState( '' ) + + // Lake Surroundings + const [ dockConnection, setDockConnection ] = useState( '' ) + const [ lakeBottom, setLakeBottom ] = useState( '' ) + const [ willDockBoat, setWillDockBoat ] = useState( Truthy.False ) + + // Comments + const [ comments, setComments ] = useState( "" ) + + const onStepChange = useCallback( ( next ) => { + setStep( next ) + }, [ step ] ) + + const onUpdateComment = useCallback( ( comment ) => { + setComments( comment ) + }, [ comments ] ) + + const onSubmit = useCallback( () => { + ( async () => { + try { + setSubmitLoading( true ) + const quoteBody = { + first_name: firstName, + last_name: lastName, + email: email, + phone: phone, + lake: lake, + city: city, + dock_connection: dockConnection, + lake_bottom: lakeBottom, + country: country, + dock_image: dockImage, + has_dealer: hasDealer, + dealer_id: dealer, + will_dock_boat: willDockBoat, + comments: comments, + selected_items: JSON.stringify( selectedItems ) + } + const result = await sdk.requestQuote( quoteBody ) + if ( !result?.error ) { + setSubmitLoading( false ) + setStep( EstimateSteps.InquirySubmitted ) + } + } catch ( error ) { + setErrorMessage( error.message ) + setSubmitLoading( false ) + } + } )() + }, [ step, submitLoading, errorMessage, comments, hasDealer, dealer, firstName, lastName, email, phone, lake, city, country, dockConnection, lakeBottom, willDockBoat, selectedItems, dockImage ] ) + + const onClose = useCallback( () => { + setStep( EstimateSteps.ContactInformation ) + modalCloseClick() + }, [ step ] ) + + return ( + + {/* ContactInformation */ } + + + {/* LakeSurroundings */ } + + + {/* Comments */ } + + + {/* InquirySubmitted */ } +
+ +
+
+ +

Inquiry Submitted

+
+
+
+ +
+
+
+ ); +} + + +const EstimateModalMemo = memo( EstimateModal ); + +export { EstimateModalMemo as EstimateModal }; diff --git a/src/components/EstimateModal/index.js b/src/components/EstimateModal/index.js new file mode 100644 index 0000000..9d43703 --- /dev/null +++ b/src/components/EstimateModal/index.js @@ -0,0 +1 @@ +export { EstimateModal } from './EstimateModal' \ No newline at end of file diff --git a/src/components/FabricObjects/Rect/Rect.jsx b/src/components/FabricObjects/Rect/Rect.jsx new file mode 100644 index 0000000..dd96bfe --- /dev/null +++ b/src/components/FabricObjects/Rect/Rect.jsx @@ -0,0 +1,63 @@ +import React from "react"; +import { fabric } from "fabric"; + +function Rect({ left, top, width, height, fill }) { + const rectRef = React.useRef(null); + + React.useEffect(() => { + const rect = new fabric.Rect({ + left, + top, + width, + height, + fill, + }); + + rectRef.current = rect; + }, [left, top, width, height, fill]); + + return <>; +} + +export default Rect; + +// const addTestRect = () => { +// if (editor) { +// const rect = new fabric.Rect({ +// left: 200, +// top: 50, +// width: 500, +// height: 50, +// fill: "red", +// }); + +// editorMemo.add(rect); +// const rect2 = new fabric.Rect({ +// left: 250, +// top: 100, +// width: 200, +// height: 50, +// fill: "red", +// }); + +// editorMemo.add(rect2); +// const rect3 = new fabric.Rect({ +// left: 300, +// top: 150, +// width: 200, +// height: 50, +// fill: "red", +// }); + +// editorMemo.add(rect3); +// const rect4 = new fabric.Rect({ +// left: 350, +// top: 200, +// width: 200, +// height: 50, +// fill: "red", +// }); + +// editorMemo.add(rect4); +// } +// } diff --git a/src/components/InteractiveButton/InteractiveButton.jsx b/src/components/InteractiveButton/InteractiveButton.jsx new file mode 100644 index 0000000..9bea1eb --- /dev/null +++ b/src/components/InteractiveButton/InteractiveButton.jsx @@ -0,0 +1,48 @@ +import React from "react"; + +export const InteractiveButton = ({ + loading, + children, + type = "button", + className, + backgroundColor, + onClick, +}) => { + return ( + + ); +}; diff --git a/src/components/InteractiveButton/index.js b/src/components/InteractiveButton/index.js new file mode 100644 index 0000000..a0a4dd1 --- /dev/null +++ b/src/components/InteractiveButton/index.js @@ -0,0 +1 @@ +export { InteractiveButton } from './InteractiveButton' \ No newline at end of file diff --git a/src/components/LakeSurroundings/LakeSurroundings.jsx b/src/components/LakeSurroundings/LakeSurroundings.jsx new file mode 100644 index 0000000..082b1dc --- /dev/null +++ b/src/components/LakeSurroundings/LakeSurroundings.jsx @@ -0,0 +1,141 @@ +import React, { memo } from 'react'; +import { ArrowLeftIcon, ArrowRrightIcon } from 'Assets/svgs'; +import { EstimateSteps, Truthy } from 'Utils/constants'; + +const LakeSurroundings = ( { step, onStepChange, setWillDockBoat, setDockConnection, setLakeBottom } ) => { + + const dockConnectionMap = [ 'Resting', 'Bolted', 'Other' ] + const lakeBottomMap = [ 'Rocky', 'Silty', 'Sandy' ] + // const dock_connection = { 0: 'Resting', 1: 'Bolted', 2: 'Other' } + // const lake_bottom = { 0: 'Rocky', 1: 'Silty', 2: 'Sandy' } + // const has_dealer = { 0: 'No', 1: 'Yes' } + // const will_dock_boat = { 0: 'No', 1: 'Yes' } + {/* LakeSurroundings */ } + + return ( + +
+ +
+ +
+

Lake Surroundings

+ (2 of 3) +
+
+
+
+ +
+
+ {/* */} +
+ +
+
+
+ +
+
+ {/* */} +
+ +
+
+
+ +
+ setWillDockBoat( Truthy.True ) } + /> + + setWillDockBoat( Truthy.False ) } + /> + +
+
+ + +
+
+ +
+
+ ); +} + + +const LakeSurroundingsMemo = memo( LakeSurroundings ); + +export { LakeSurroundingsMemo as LakeSurroundings }; diff --git a/src/components/LakeSurroundings/index.js b/src/components/LakeSurroundings/index.js new file mode 100644 index 0000000..53b7ed3 --- /dev/null +++ b/src/components/LakeSurroundings/index.js @@ -0,0 +1 @@ +export { LakeSurroundings } from './LakeSurroundings' \ No newline at end of file diff --git a/src/components/Loader.jsx b/src/components/Loader.jsx new file mode 100644 index 0000000..6270200 --- /dev/null +++ b/src/components/Loader.jsx @@ -0,0 +1,22 @@ + +import Indicator from "./LoadingIndicator"; + +const Loader = ({ style }) => { + return ( +
+ +
+ ); +}; + +export default Loader; + diff --git a/src/components/LoadingIndicator.jsx b/src/components/LoadingIndicator.jsx new file mode 100644 index 0000000..8990358 --- /dev/null +++ b/src/components/LoadingIndicator.jsx @@ -0,0 +1,58 @@ + + +import React from "react"; + +import { motion } from "framer-motion"; + +const containerVariant = { + start: { + transition: { staggerChildren: 0.2 } + }, + end: { + transition: { staggerChildren: 0.2 } + } +}; + +const dotsVariants = { + start: { + y: "0%" + }, + end: { + y: "100%" + } +}; + +const loadingTransition = { + duration: 0.4, + yoyo: Infinity, + ease: "easeIn" +}; + +export default function Indicator({ dotsClasses, size, style }) { + const dotsStyles = "block w-[9px] h-[9px] bg-slate-900 rounded-md shrink-0 " + dotsClasses; + return ( + + + + + + ); +} diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx new file mode 100644 index 0000000..e1a1527 --- /dev/null +++ b/src/components/Modal/Modal.jsx @@ -0,0 +1,38 @@ +import React, { useEffect, useRef, useState, memo } from 'react'; +import { CloseIcon } from 'Assets/svgs'; + +const Modal = ( { + children, + title, + isOpen = false, + modalCloseClick, + modalHeader, + classes +} ) => { + + + return ( +
+
+ { modalHeader && +
+
{ title }
+
+ +
+
+ } + +
+ { children } +
+
+
+ ); +}; + + +const ModalMemo = memo( Modal ); +export { ModalMemo as Modal }; diff --git a/src/components/Modal/index.js b/src/components/Modal/index.js new file mode 100644 index 0000000..3d80065 --- /dev/null +++ b/src/components/Modal/index.js @@ -0,0 +1 @@ +export { Modal } from './Modal' \ No newline at end of file diff --git a/src/components/PaginationBar.jsx b/src/components/PaginationBar.jsx new file mode 100644 index 0000000..bd3d0a3 --- /dev/null +++ b/src/components/PaginationBar.jsx @@ -0,0 +1,41 @@ +import React from "react"; +const PaginationBar = ({ currentPage, pageCount, pageSize, canPreviousPage, canNextPage, updatePageSize, previousPage, nextPage }) => { + return ( + <> +
+
+ + Page{" "} + + {+currentPage} of {pageCount} + {" "} + + +
+ {/* */} +
+ {" "} + {" "} +
+
+ + ); +}; + +export default PaginationBar; diff --git a/src/components/PublicHeader.jsx b/src/components/PublicHeader.jsx new file mode 100644 index 0000000..47f83e2 --- /dev/null +++ b/src/components/PublicHeader.jsx @@ -0,0 +1,15 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router"; +import { AuthContext } from "../authContext"; + +export const PublicHeader = () => { + const { state, dispatch } = React.useContext(AuthContext); + const [isOpen, setIsOpen] = useState(false); + const navigate = useNavigate(); + + return
+ +
; +}; + +export default PublicHeader; diff --git a/src/components/SelectedItems/Field.jsx b/src/components/SelectedItems/Field.jsx new file mode 100644 index 0000000..3c39caa --- /dev/null +++ b/src/components/SelectedItems/Field.jsx @@ -0,0 +1,18 @@ +import React from 'react' +import { capitalize } from 'Utils/helper' + +export const Field = ( { item, property } ) => { + + return ( + <> + { item[ property ] ? ( +
+
{ capitalize( property ) }:
+
{ item[ property ] }{ " " }{ [ "length", "width" ].includes( property ) ? 'ft' : '' }
+
) + + : null + } + + ) +} diff --git a/src/components/SelectedItems/SelectedItem.jsx b/src/components/SelectedItems/SelectedItem.jsx new file mode 100644 index 0000000..059ec0a --- /dev/null +++ b/src/components/SelectedItems/SelectedItem.jsx @@ -0,0 +1,48 @@ +import { Chevron } from 'Assets/svgs' +import React from 'react' +import { Field } from './Field' + +export const SelectedItem = ( { selectedItem } ) => { + const itemRef = React.useRef( null ) + + const [ open, setOpen ] = React.useState( false ) + + const onOpen = React.useCallback( ( isTrue ) => { + if ( isTrue ) { + itemRef.current.style.maxHeight = null + } else { + itemRef.current.style.maxHeight = `${ itemRef.current.scrollHeight }px` + } + setOpen( !isTrue ) + }, [ open, itemRef ] ) + + return ( +
+ + + +
+ + + + + + + + + +
+ +
+ ) +} diff --git a/src/components/SelectedItems/SelectedItems.jsx b/src/components/SelectedItems/SelectedItems.jsx new file mode 100644 index 0000000..23adfde --- /dev/null +++ b/src/components/SelectedItems/SelectedItems.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import { SelectedItem } from './SelectedItem' + +export const SelectedItems = ( { selectedItems } ) => { + + return ( +
+ { selectedItems?.length ? selectedItems?.map( ( item, index ) => ( + + ) ) + + : null } +
+ ) +} diff --git a/src/components/SelectedItems/index.js b/src/components/SelectedItems/index.js new file mode 100644 index 0000000..d4761d6 --- /dev/null +++ b/src/components/SelectedItems/index.js @@ -0,0 +1,3 @@ +export { SelectedItems } from './SelectedItems' +export { SelectedItem } from './SelectedItem' +export { Field } from './Field' \ No newline at end of file diff --git a/src/components/SidebarBuilder/SidebarBuilder.jsx b/src/components/SidebarBuilder/SidebarBuilder.jsx new file mode 100644 index 0000000..77c7e70 --- /dev/null +++ b/src/components/SidebarBuilder/SidebarBuilder.jsx @@ -0,0 +1,51 @@ +import React, { useCallback, useState } from "react"; +import { Tabs } from "Components/Tabs"; +import { Builder } from "Components/Builder"; +import { SelectedItems } from "Components/SelectedItems"; +import { TabNames } from "Utils/constants"; + +export const SidebarBuilder = ({ + editor, + updateModifications, + selectedItems, +}) => { + const [activeTab, setActiveTab] = useState(TabNames.Builder); + // const [ramps, setRamps] = useState([]); + + const onTabClick = useCallback( + (tab) => { + setActiveTab(tab); + }, + [activeTab] + ); + + return ( +
+ + + {activeTab === TabNames.Builder ? ( + + ) : null} + {activeTab === TabNames.SelectedItems ? ( + + ) : null} +
+ ); +}; + +{ + /*
+ +
*/ +} diff --git a/src/components/SidebarBuilder/index.js b/src/components/SidebarBuilder/index.js new file mode 100644 index 0000000..830750c --- /dev/null +++ b/src/components/SidebarBuilder/index.js @@ -0,0 +1 @@ +export { SidebarBuilder } from './SidebarBuilder' \ No newline at end of file diff --git a/src/components/SidebarFoot/SidebarFoot.jsx b/src/components/SidebarFoot/SidebarFoot.jsx new file mode 100644 index 0000000..8a15148 --- /dev/null +++ b/src/components/SidebarFoot/SidebarFoot.jsx @@ -0,0 +1,38 @@ +import React from 'react' +import { DownloadIcon, UploadIcon } from 'Assets/svgs' + +export const SidebarFoot = ( { onDownloadImage, onDownloadFile, fileRef, onUploadFile, onEstimateModalOpen } ) => { + + return ( +
+ + + + + + + +
+ ) +} \ No newline at end of file diff --git a/src/components/SidebarFoot/index.js b/src/components/SidebarFoot/index.js new file mode 100644 index 0000000..c40b167 --- /dev/null +++ b/src/components/SidebarFoot/index.js @@ -0,0 +1 @@ +export { SidebarFoot } from './SidebarFoot' \ No newline at end of file diff --git a/src/components/SidebarLogo/SidebarLogo.jsx b/src/components/SidebarLogo/SidebarLogo.jsx new file mode 100644 index 0000000..7aeb9e1 --- /dev/null +++ b/src/components/SidebarLogo/SidebarLogo.jsx @@ -0,0 +1,15 @@ +import { BrandLogo } from 'Assets/images' +import React from 'react' + +export const SidebarLogo = () => +{ + return ( +
+ Brand Logo +
+
Paradise Dock & Lift Inc.
+
Dock builder tool
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/SidebarLogo/index.js b/src/components/SidebarLogo/index.js new file mode 100644 index 0000000..5cd5197 --- /dev/null +++ b/src/components/SidebarLogo/index.js @@ -0,0 +1 @@ +export { SidebarLogo } from './SidebarLogo' \ No newline at end of file diff --git a/src/components/SnackBar.jsx b/src/components/SnackBar.jsx new file mode 100644 index 0000000..26aa222 --- /dev/null +++ b/src/components/SnackBar.jsx @@ -0,0 +1,32 @@ +import React from "react"; +import { GlobalContext } from "../globalContext"; +const SnackBar = () => { + const { state, dispatch } = React.useContext(GlobalContext); + const show = state.globalMessage.length > 0; + return show ? ( + + ) : null; +}; + +export default SnackBar; diff --git a/src/components/Tab/Tab.jsx b/src/components/Tab/Tab.jsx new file mode 100644 index 0000000..7ab518f --- /dev/null +++ b/src/components/Tab/Tab.jsx @@ -0,0 +1,10 @@ + +import React from 'react' + +export const Tab = ( { name, className, active, onTabClick } ) => { + return ( + + ) +} \ No newline at end of file diff --git a/src/components/Tab/index.js b/src/components/Tab/index.js new file mode 100644 index 0000000..ddacd77 --- /dev/null +++ b/src/components/Tab/index.js @@ -0,0 +1 @@ +export { Tab } from './Tab' \ No newline at end of file diff --git a/src/components/Table/Table.jsx b/src/components/Table/Table.jsx new file mode 100644 index 0000000..20d25be --- /dev/null +++ b/src/components/Table/Table.jsx @@ -0,0 +1,95 @@ +import React from 'react' + +export const Table = ( { className, tableColumns, tableData } ) => { + return ( +
+ + + + { tableColumns.map( ( column, i ) => ( + + ) ) } + + + + { tableData.map( ( row, i ) => { + return ( + + { tableColumns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ {/* */} + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { [ "image", "top_view", "thumbnail" ].includes( cell.accessor ) ? : row[ cell.accessor ] } +
+
+ + ) +} \ No newline at end of file diff --git a/src/components/Table/index.js b/src/components/Table/index.js new file mode 100644 index 0000000..0eb36c2 --- /dev/null +++ b/src/components/Table/index.js @@ -0,0 +1 @@ +export { Table } from './Table' \ No newline at end of file diff --git a/src/components/Tabs/Tabs.jsx b/src/components/Tabs/Tabs.jsx new file mode 100644 index 0000000..28b0cc0 --- /dev/null +++ b/src/components/Tabs/Tabs.jsx @@ -0,0 +1,25 @@ +import React from 'react' +import { Tab } from 'Components/Tab' +import { TabNames } from 'Utils/constants' + + + +export const Tabs = ( { activeTab, className, onTabClick } ) => { + return ( +
+ + + +
+ ) +} \ No newline at end of file diff --git a/src/components/Tabs/index.js b/src/components/Tabs/index.js new file mode 100644 index 0000000..d82601c --- /dev/null +++ b/src/components/Tabs/index.js @@ -0,0 +1 @@ +export { Tabs } from './Tabs' \ No newline at end of file diff --git a/src/components/TopHeader.jsx b/src/components/TopHeader.jsx new file mode 100644 index 0000000..3f6b264 --- /dev/null +++ b/src/components/TopHeader.jsx @@ -0,0 +1,52 @@ +import React from "react"; +import { GlobalContext } from "../globalContext"; +const TopHeader = () => { + const { state, dispatch } = React.useContext(GlobalContext); + let { isOpen } = state; + let toggleOpen = (open) => + dispatch({ + type: "OPEN_SIDEBAR", + payload: { isOpen: open }, + }); + return ( +
+ toggleOpen(!isOpen)}> + {!isOpen ? ( + + ) : ( + + )} + +
+ ); +}; + +export default TopHeader; diff --git a/src/components/ViewDockImageModal/ViewDockImageModal.jsx b/src/components/ViewDockImageModal/ViewDockImageModal.jsx new file mode 100644 index 0000000..77c80de --- /dev/null +++ b/src/components/ViewDockImageModal/ViewDockImageModal.jsx @@ -0,0 +1,77 @@ +import React, { memo, useState, useCallback } from 'react'; +import { Modal } from 'Components/Modal'; +import { InteractiveButton } from 'Components/InteractiveButton'; +// import { ArrowLeftIcon, ArrowRrightIcon, GreenTickIcon } from 'Assets/svgs'; +// import { dock_image, EstimateSteps, Tables, Truthy } from 'Utils/constants'; +// import { ContactInformation } from 'Components/ContactInformation'; +// import { LakeSurroundings } from 'Components/LakeSurroundings'; +// import { Comments } from 'Components/Comments'; +import MkdSDK from 'Utils/MkdSDK'; + +const sdk = new MkdSDK() +const classes = { + modal: 'string', + modalDialog: 'relative bg-white w-[800px]', + modalContent: 'string', + modalHeader: 'string', + modalTitle: 'string', + modalBody: 'string', + modalFooter: 'string', + closeButtonClass: 'string', + saveButtonClass: 'string', +} + +const ViewDockImageModal = ( { + showViewDockImageModal, + modalCloseClick, + dockImage +} ) => { + // const [ step, setStep ] = useState( EstimateSteps.ContactInformation ) + // const [ submitLoading, setSubmitLoading ] = useState( false ) + // const [ errorMessage, setErrorMessage ] = useState( null ) + // const [ hasDealer, setHasDealer ] = useState( Truthy.False ) + + + const onDownloadClick = useCallback( () => { + const Anchor = document.createElement( "a" ) + // console.log( "viewDockImageModal", dockImage ) + Anchor.href = dockImage; + Anchor.download = `dock_image_snapshot.png`; + Anchor.click(); + // modalCloseClick() + }, [ dockImage ] ) + + return ( + +
+
+ dock_image +
+ +
+ + Download + +
+
+ + + +
+ ); +} + + +const ViewDockImageModalMemo = memo( ViewDockImageModal ); + +export { ViewDockImageModalMemo as ViewDockImageModal }; diff --git a/src/components/ViewDockImageModal/index.js b/src/components/ViewDockImageModal/index.js new file mode 100644 index 0000000..b169e63 --- /dev/null +++ b/src/components/ViewDockImageModal/index.js @@ -0,0 +1 @@ +export { ViewDockImageModal } from './ViewDockImageModal' \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js new file mode 100644 index 0000000..74ee0cc --- /dev/null +++ b/src/components/index.js @@ -0,0 +1,6 @@ +export { default as AddButton } from './AddButton' +export { default as AdminHeader } from './AdminHeader' +export { default as PaginationBar } from './PaginationBar' +export { default as PublicHeader } from './PublicHeader' +export { default as SnackBar } from './SnackBar' +export { default as TopHeader } from './TopHeader' \ No newline at end of file diff --git a/src/data.js b/src/data.js new file mode 100644 index 0000000..37d3570 --- /dev/null +++ b/src/data.js @@ -0,0 +1,1963 @@ +export const dealers = { + error: false, + model: [ + { + id: 11, + create_at: "2022-11-01", + update_at: "2022-11-01T20:08:25.000Z", + name: "Rumman", + address: "street 1" + }, + { + id: 10, + create_at: "2022-11-01", + update_at: "2022-11-01T19:41:36.000Z", + name: "Rumman Mohsin", + address: "street 3" + } + ], + mapping: null +}; +export const wedges = { + error: false, + model: [ + { + id: 12, + create_at: "2023-04-21", + update_at: "2024-02-29T23:02:47.000Z", + category: 1, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20SS.png", + material: 2 + }, + { + id: 11, + create_at: "2023-04-21", + update_at: "2024-02-29T23:02:28.000Z", + category: 1, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20Grey.png", + material: 1 + }, + { + id: 10, + create_at: "2023-04-21", + update_at: "2024-02-29T23:01:59.000Z", + category: 1, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20Wood.png", + material: 0 + }, + { + id: 9, + create_at: "2023-04-21", + update_at: "2024-02-29T23:01:42.000Z", + category: 0, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Floating-Sectional%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20SS.png", + material: 2 + }, + { + id: 8, + create_at: "2023-04-21", + update_at: "2024-02-29T23:01:10.000Z", + category: 0, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Floating-Sectional%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20Grey.png", + material: 1 + }, + { + id: 7, + create_at: "2023-04-21", + update_at: "2024-02-29T23:00:40.000Z", + category: 0, + length: 4, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wedge%20Floating-Sectional%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x4%20Wedge%20Wood.png", + material: 0 + } + ], + mapping: { + category: { + 0: "Floating Wedge", + 1: "Roll-In Wedge" + }, + material: { + 0: "Wood Grain", + 1: "Grey Aluminium", + 2: "Perforated" + } + } +}; + +export const docks = { + error: false, + model: [ + { + id: 92, + create_at: "2022-11-08", + update_at: "2024-03-05T20:06:21.000Z", + category: 2, + materials: 1, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x16%20RI%20SS.png" + }, + { + id: 91, + create_at: "2022-11-08", + update_at: "2024-03-05T20:05:56.000Z", + category: 2, + materials: 1, + length: 12, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x12%20RI%20SS.png" + }, + { + id: 90, + create_at: "2022-11-08", + update_at: "2024-03-05T20:05:37.000Z", + category: 2, + materials: 1, + length: 8, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x8%20RI%20SS.png" + }, + { + id: 89, + create_at: "2022-11-08", + update_at: "2024-03-05T20:05:16.000Z", + category: 2, + materials: 1, + length: 12, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x12%20RI%20SS.png" + }, + { + id: 88, + create_at: "2022-11-08", + update_at: "2024-03-05T20:04:52.000Z", + category: 2, + materials: 1, + length: 16, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20RI%20SS.png" + }, + { + id: 87, + create_at: "2022-11-08", + update_at: "2024-03-05T20:04:14.000Z", + category: 2, + materials: 1, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20RI%20SS.png" + }, + { + id: 86, + create_at: "2022-11-08", + update_at: "2024-03-05T20:03:23.000Z", + category: 2, + materials: 1, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20RI%20SS.png" + }, + { + id: 85, + create_at: "2022-11-08", + update_at: "2024-03-05T19:57:24.000Z", + category: 2, + materials: 2, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x16%20RI%20Grey.png" + }, + { + id: 84, + create_at: "2022-11-08", + update_at: "2024-03-05T19:57:05.000Z", + category: 2, + materials: 2, + length: 12, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x12%20RI%20Grey.png" + }, + { + id: 83, + create_at: "2022-11-08", + update_at: "2024-03-05T19:56:42.000Z", + category: 2, + materials: 2, + length: 8, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x8%20RI%20Grey.png" + }, + { + id: 82, + create_at: "2022-11-08", + update_at: "2024-03-05T19:56:04.000Z", + category: 2, + materials: 2, + length: 12, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x12%20RI%20Grey.png" + }, + { + id: 81, + create_at: "2022-11-08", + update_at: "2024-03-05T19:55:00.000Z", + category: 2, + materials: 2, + length: 16, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20RI%20Grey.png" + }, + { + id: 80, + create_at: "2022-11-08", + update_at: "2024-03-05T19:54:42.000Z", + category: 2, + materials: 2, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20RI%20Grey.png" + }, + { + id: 79, + create_at: "2022-11-08", + update_at: "2024-03-05T19:54:25.000Z", + category: 2, + materials: 2, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20RI%20Grey.png" + }, + { + id: 78, + create_at: "2022-11-08", + update_at: "2024-03-05T19:50:50.000Z", + category: 2, + materials: 0, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x16%20RI%20Wood.png" + }, + { + id: 77, + create_at: "2022-11-08", + update_at: "2024-03-05T19:50:34.000Z", + category: 2, + materials: 0, + length: 12, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x12%20RI%20Wood.png" + }, + { + id: 76, + create_at: "2022-11-08", + update_at: "2024-03-05T19:50:16.000Z", + category: 2, + materials: 0, + length: 8, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x8%20RI%20Wood.png" + }, + { + id: 75, + create_at: "2022-11-08", + update_at: "2024-03-05T19:49:59.000Z", + category: 2, + materials: 0, + length: 12, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x12%20RI%20Wood.png" + }, + { + id: 74, + create_at: "2022-11-08", + update_at: "2024-03-05T19:49:41.000Z", + category: 2, + materials: 0, + length: 16, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20RI%20Wood.png" + }, + { + id: 73, + create_at: "2022-11-08", + update_at: "2024-03-05T19:49:26.000Z", + category: 2, + materials: 0, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20RI%20Wood.png" + }, + { + id: 72, + create_at: "2022-11-08", + update_at: "2024-03-05T19:48:00.000Z", + category: 2, + materials: 0, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Roll-in%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20RI%20Wood.png" + }, + { + id: 71, + create_at: "2022-11-04", + update_at: "2024-03-05T19:46:49.000Z", + category: 1, + materials: 1, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20S%20SS.png" + }, + { + id: 70, + create_at: "2022-11-04", + update_at: "2024-03-05T19:46:22.000Z", + category: 1, + materials: 1, + length: 10, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x10%20S%20SS.png" + }, + { + id: 69, + create_at: "2022-11-04", + update_at: "2024-03-05T19:45:55.000Z", + category: 1, + materials: 1, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20RI%20SS.png" + }, + { + id: 68, + create_at: "2022-11-04", + update_at: "2024-03-05T19:45:34.000Z", + category: 1, + materials: 2, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20S%20Grey.png" + }, + { + id: 67, + create_at: "2022-11-04", + update_at: "2024-03-05T19:45:11.000Z", + category: 1, + materials: 2, + length: 10, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x10%20S%20Grey.png" + }, + { + id: 66, + create_at: "2022-11-04", + update_at: "2024-03-05T19:44:49.000Z", + category: 1, + materials: 2, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20S%20Grey.png" + }, + { + id: 65, + create_at: "2022-11-04", + update_at: "2024-03-05T19:44:28.000Z", + category: 1, + materials: 0, + length: 12, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20S%20Wood.png" + }, + { + id: 64, + create_at: "2022-11-04", + update_at: "2024-03-05T19:43:23.000Z", + category: 1, + materials: 0, + length: 10, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x10%20S%20Wood.png" + }, + { + id: 63, + create_at: "2022-11-04", + update_at: "2024-03-05T19:43:00.000Z", + category: 1, + materials: 0, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Sectional%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20S%20Wood.png" + }, + { + id: 62, + create_at: "2022-11-04", + update_at: "2024-03-05T19:42:20.000Z", + category: 0, + materials: 1, + length: 24, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x24%20F%20SS.png" + }, + { + id: 61, + create_at: "2022-11-04", + update_at: "2024-03-05T19:42:01.000Z", + category: 0, + materials: 1, + length: 20, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x20%20F%20SS.png" + }, + { + id: 60, + create_at: "2022-11-04", + update_at: "2024-03-05T19:41:39.000Z", + category: 0, + materials: 1, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x16%20F%20SS.png" + }, + { + id: 59, + create_at: "2022-11-04", + update_at: "2024-03-05T19:40:39.000Z", + category: 0, + materials: 1, + length: 8, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x8%20F%20SS.png" + }, + { + id: 58, + create_at: "2022-11-04", + update_at: "2024-03-05T19:40:15.000Z", + category: 0, + materials: 1, + length: 24, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x24%20F%20Grey.png" + }, + { + id: 57, + create_at: "2022-11-04", + update_at: "2024-03-05T19:39:23.000Z", + category: 0, + materials: 1, + length: 20, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x20%20F%20SS.png" + }, + { + id: 56, + create_at: "2022-11-04", + update_at: "2024-03-05T19:39:00.000Z", + category: 0, + materials: 1, + length: 16, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x16%20F%20SS.png" + }, + { + id: 55, + create_at: "2022-11-04", + update_at: "2024-03-05T19:38:32.000Z", + category: 0, + materials: 1, + length: 24, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x24%20F%20SS.png" + }, + { + id: 54, + create_at: "2022-11-04", + update_at: "2024-03-05T19:38:09.000Z", + category: 0, + materials: 1, + length: 20, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x20%20F%20SS.png" + }, + { + id: 53, + create_at: "2022-11-04", + update_at: "2024-03-05T19:37:42.000Z", + category: 0, + materials: 1, + length: 16, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x16%20F%20SS.png" + }, + { + id: 52, + create_at: "2022-11-04", + update_at: "2024-03-05T19:36:17.000Z", + category: 0, + materials: 1, + length: 24, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x24%20F%20SS.png" + }, + { + id: 51, + create_at: "2022-11-04", + update_at: "2024-03-05T19:36:00.000Z", + category: 0, + materials: 1, + length: 20, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x20%20F%20SS.png" + }, + { + id: 50, + create_at: "2022-11-04", + update_at: "2024-03-05T19:35:42.000Z", + category: 0, + materials: 1, + length: 16, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20F%20SS.png" + }, + { + id: 49, + create_at: "2022-11-04", + update_at: "2024-03-05T19:35:20.000Z", + category: 0, + materials: 1, + length: 24, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x24%20F%20SS.png" + }, + { + id: 48, + create_at: "2022-11-04", + update_at: "2024-03-05T19:34:58.000Z", + category: 0, + materials: 1, + length: 20, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x20%20F%20SS.png" + }, + { + id: 47, + create_at: "2022-11-04", + update_at: "2024-03-05T19:34:38.000Z", + category: 0, + materials: 1, + length: 16, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Perforated.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x16%20F%20SS.png" + }, + { + id: 46, + create_at: "2022-11-04", + update_at: "2024-03-05T19:34:15.000Z", + category: 0, + materials: 2, + length: 24, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x24%20F%20Grey.png" + }, + { + id: 45, + create_at: "2022-11-04", + update_at: "2024-03-05T19:33:54.000Z", + category: 0, + materials: 2, + length: 20, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x20%20F%20Grey.png" + }, + { + id: 44, + create_at: "2022-11-04", + update_at: "2024-03-05T19:33:30.000Z", + category: 0, + materials: 2, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x20%20F%20Grey.png" + }, + { + id: 43, + create_at: "2022-11-04", + update_at: "2024-03-05T19:32:32.000Z", + category: 0, + materials: 2, + length: 8, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x8%20F%20Grey.png" + }, + { + id: 42, + create_at: "2022-11-04", + update_at: "2024-03-05T19:31:50.000Z", + category: 0, + materials: 2, + length: 24, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x24%20F%20Grey.png" + }, + { + id: 41, + create_at: "2022-11-04", + update_at: "2024-03-05T19:31:35.000Z", + category: 0, + materials: 2, + length: 20, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x20%20F%20Grey.png" + }, + { + id: 40, + create_at: "2022-11-04", + update_at: "2024-03-05T19:31:19.000Z", + category: 0, + materials: 2, + length: 16, + width: 6, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426x16%20F%20Grey.png" + }, + { + id: 39, + create_at: "2022-11-04", + update_at: "2024-03-05T19:31:01.000Z", + category: 0, + materials: 2, + length: 24, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x24%20F%20Grey.png" + }, + { + id: 38, + create_at: "2022-11-04", + update_at: "2024-03-05T19:30:43.000Z", + category: 0, + materials: 2, + length: 20, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x20%20F%20Grey.png" + }, + { + id: 37, + create_at: "2022-11-04", + update_at: "2024-03-05T19:30:14.000Z", + category: 0, + materials: 2, + length: 16, + width: 5, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887425x16%20F%20Grey.png" + }, + { + id: 36, + create_at: "2022-11-04", + update_at: "2024-03-05T19:29:24.000Z", + category: 0, + materials: 2, + length: 24, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x20%20F%20Grey.png" + }, + { + id: 35, + create_at: "2022-11-04", + update_at: "2024-03-05T19:25:26.000Z", + category: 0, + materials: 2, + length: 20, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x20%20F%20Grey.png" + }, + { + id: 34, + create_at: "2022-11-04", + update_at: "2024-03-05T19:25:08.000Z", + category: 0, + materials: 2, + length: 16, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20F%20Grey.png" + }, + { + id: 33, + create_at: "2022-11-04", + update_at: "2024-03-05T19:24:27.000Z", + category: 0, + materials: 2, + length: 8, + width: 4, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x8%20F%20Grey.png" + }, + { + id: 32, + create_at: "2022-11-04", + update_at: "2024-03-05T19:23:38.000Z", + category: 0, + materials: 2, + length: 24, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x24%20F%20Grey.png" + }, + { + id: 31, + create_at: "2022-11-04", + update_at: "2024-03-05T19:23:12.000Z", + category: 0, + materials: 2, + length: 20, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x20%20F%20Grey.png" + }, + { + id: 30, + create_at: "2022-11-04", + update_at: "2024-03-05T19:22:46.000Z", + category: 0, + materials: 2, + length: 16, + width: 3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423x16%20F%20Grey.png" + }, + { + id: 29, + create_at: "2022-11-04", + update_at: "2024-03-05T19:21:31.000Z", + category: 0, + materials: 0, + length: 24, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x24%20F%20Wood.png" + }, + { + id: 28, + create_at: "2022-11-04", + update_at: "2024-03-04T21:44:39.000Z", + category: 0, + materials: 0, + length: 20, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x20%20F%20Wood.png" + }, + { + id: 27, + create_at: "2022-11-04", + update_at: "2024-03-04T21:43:40.000Z", + category: 0, + materials: 0, + length: 16, + width: 8, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428x16%20F%20Wood.png" + }, + { + id: 26, + create_at: "2022-11-04", + update_at: "2022-11-04T16:28:13.000Z", + category: 0, + materials: 0, + length: 8, + width: 8, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/8x8%20F%20Wood.png" + }, + { + id: 25, + create_at: "2022-11-04", + update_at: "2022-11-04T16:27:58.000Z", + category: 0, + materials: 0, + length: 24, + width: 6, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/6x24%20F%20Wood.png" + }, + { + id: 24, + create_at: "2022-11-04", + update_at: "2022-11-04T16:27:44.000Z", + category: 0, + materials: 0, + length: 20, + width: 6, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/6x20%20F%20Wood.png" + }, + { + id: 23, + create_at: "2022-11-04", + update_at: "2022-11-04T16:27:25.000Z", + category: 0, + materials: 0, + length: 16, + width: 6, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/6x16%20F%20Wood.png" + }, + { + id: 22, + create_at: "2022-11-04", + update_at: "2022-11-04T16:27:03.000Z", + category: 0, + materials: 0, + length: 24, + width: 5, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/5x24%20F%20Wood.png" + }, + { + id: 21, + create_at: "2022-11-04", + update_at: "2022-11-04T16:26:41.000Z", + category: 0, + materials: 0, + length: 20, + width: 5, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/5x20%20F%20Wood.png" + }, + { + id: 20, + create_at: "2022-11-04", + update_at: "2022-11-04T16:26:27.000Z", + category: 0, + materials: 0, + length: 16, + width: 5, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/5x16%20F%20Wood.png" + }, + { + id: 19, + create_at: "2022-11-04", + update_at: "2022-11-04T16:26:04.000Z", + category: 0, + materials: 0, + length: 24, + width: 4, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/4x24%20F%20Wood.png" + }, + { + id: 18, + create_at: "2022-11-04", + update_at: "2022-11-04T16:25:43.000Z", + category: 0, + materials: 0, + length: 20, + width: 4, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/4x20%20F%20Wood.png" + }, + { + id: 17, + create_at: "2022-11-04", + update_at: "2022-11-04T16:25:23.000Z", + category: 0, + materials: 0, + length: 16, + width: 4, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/4x16%20F%20Wood.png" + }, + { + id: 16, + create_at: "2022-11-04", + update_at: "2022-11-04T16:24:55.000Z", + category: 0, + materials: 0, + length: 8, + width: 4, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/4x8%20F%20Wood.png" + }, + { + id: 15, + create_at: "2022-11-04", + update_at: "2022-11-04T16:24:34.000Z", + category: 0, + materials: 0, + length: 24, + width: 3, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/3x24%20F%20Wood.png" + }, + { + id: 14, + create_at: "2022-11-04", + update_at: "2022-11-04T16:23:40.000Z", + category: 0, + materials: 0, + length: 20, + width: 3, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/3x20%20F%20Wood.png" + }, + { + id: 11, + create_at: "2022-11-04", + update_at: "2022-11-04T16:22:47.000Z", + category: 0, + materials: 0, + length: 16, + width: 3, + image: + "https://s3.us-east-2.amazonaws.com/com.nds.images/Floating%20Woodgrain-min.png", + top_view: + "https://s3.us-east-2.amazonaws.com/com.nds.images/3x16%20F%20Wood.png" + } + ], + mapping: { + category: { + 0: "Floating Dock", + 1: "Sectional Dock", + 2: "Roll-In Dock" + }, + materials: { + 0: "Wood Grain", + 1: "Perforated", + 2: "Grey Aluminium" + } + } +}; + +export const accessories = { + error: false, + model: [ + { + id: 38, + create_at: "2022-11-14", + update_at: "2024-03-04T21:40:12.000Z", + name: "8 Step Stairs -Woodgrain", + length: 6.91, + width: 3.15, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20WG%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428%20Step%20Stairs%20-Woodgrain.png" + }, + { + id: 37, + create_at: "2022-11-14", + update_at: "2024-03-04T21:39:38.000Z", + name: "8 Step Stairs -Grey", + length: 6.91, + width: 3.15, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20Grey%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887428%20Step%20Stairs%20-Grey.png" + }, + { + id: 36, + create_at: "2022-11-14", + update_at: "2024-03-04T21:38:55.000Z", + name: "6 Step Stairs -Woodgrain", + length: 5.42, + width: 3.15, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20WG%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426%20Step%20Stairs%20-Woodgrain.png" + }, + { + id: 35, + create_at: "2022-11-14", + update_at: "2024-03-04T21:38:19.000Z", + name: "6 Step Stairs -Grey", + length: 5.42, + width: 3.15, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20Grey%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887426%20Step%20Stairs%20-Grey.png" + }, + { + id: 34, + create_at: "2022-11-14", + update_at: "2024-03-04T21:37:46.000Z", + name: "4 Step Stairs -Woodgrain", + length: 4.02, + width: 3.2, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20WG%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Step%20Stairs%20-Woodgrain.png" + }, + { + id: 33, + create_at: "2022-11-14", + update_at: "2024-03-04T21:37:23.000Z", + name: "4 Step Stairs -Grey", + length: 4.02, + width: 3.2, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Accesories%20Stairs%20Grey%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Step%20Stairs%20-Grey.png" + }, + { + id: 32, + create_at: "2022-11-14", + update_at: "2024-03-04T21:36:16.000Z", + name: "Wheel Kit-8ft Wide Dock", + length: 9.63, + width: 1.67, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Wheel%20Kit%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wheel%20Kit-8ft%20Wide%20Dock.png" + }, + { + id: 31, + create_at: "2022-11-14", + update_at: "2024-03-04T21:35:57.000Z", + name: "Wheel Kit-6ft Wide Dock", + length: 7.57, + width: 1.69, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Wheel%20Kit%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wheel%20Kit-6ft%20Wide%20Dock.png" + }, + { + id: 30, + create_at: "2022-11-14", + update_at: "2024-03-04T21:35:40.000Z", + name: "Wheel Kit-4ft Wide Dock", + length: 5.61, + width: 1.64, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Wheel%20Kit%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Wheel%20Kit-4ft%20Wide%20Dock.png" + }, + { + id: 29, + create_at: "2022-11-14", + update_at: "2024-03-04T21:35:08.000Z", + name: "Vertical Bumper", + length: 0.29, + width: 0.34, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Vertical%20Bumper%20Render%202.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Vertical%20Bumper.png" + }, + { + id: 28, + create_at: "2022-11-14", + update_at: "2024-03-04T21:34:47.000Z", + name: "Tie Down Cleat", + length: 0.21, + width: 0.71, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Cleat%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Tie%20Down%20Cleat.png" + }, + { + id: 27, + create_at: "2022-11-14", + update_at: "2024-03-04T21:34:17.000Z", + name: "Table and Chair Set", + length: 2.25, + width: 5.95, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Table%20and%20Chair%20Set.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Table%20and%20Chair%20Set.png" + }, + { + id: 26, + create_at: "2022-11-14", + update_at: "2024-03-04T21:33:51.000Z", + name: "PWC Catwalk-Woodgrain", + length: 1.32, + width: 16.01, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742WD2223.jpg", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PWC.png" + }, + { + id: 25, + create_at: "2022-11-14", + update_at: "2024-03-04T21:32:15.000Z", + name: "PWC Catwalk-Grey", + length: 1.32, + width: 16.01, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742snapport-1-768x768.jpg", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PWC.png" + }, + { + id: 24, + create_at: "2022-11-14", + update_at: "2024-03-04T20:53:42.000Z", + name: "Power Pack Box-With Solar", + length: 1.88, + width: 2.73, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Basta-Dock-Box-with-Solar-Panel.jpg", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Power%20Pack%20Box-With%20Solar.png" + }, + { + id: 23, + create_at: "2022-11-14", + update_at: "2024-03-04T20:53:18.000Z", + name: "Power Pack Box-No Solar", + length: 1.88, + width: 2.73, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887421-titanstor_35-15000-WW_opened_lowres.jpg", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Power%20Pack%20Box-No%20Solar.png" + }, + { + id: 22, + create_at: "2022-11-14", + update_at: "2024-03-04T20:42:01.000Z", + name: "Ladder", + length: 1.72, + width: 0.21, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%204%20Step%20Ladder%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Ladder.png" + }, + { + id: 20, + create_at: "2022-11-14", + update_at: "2024-03-04T20:41:29.000Z", + name: "Kayak Rack", + length: 2.94, + width: 2.86, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Kayak%20Rack%20Render%201.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Kayak%20Rack.png" + }, + { + id: 19, + create_at: "2022-11-14", + update_at: "2024-03-04T20:40:52.000Z", + name: "Fishing Rod Holder", + length: 0.77, + width: 0.5, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Fishing%20Rod%20Holder%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Fishing%20Rod%20Holder.png" + }, + { + id: 18, + create_at: "2022-11-14", + update_at: "2024-03-04T20:33:47.000Z", + name: "Box Mount", + length: 1.53, + width: 1.83, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Dock-Sides-Dock-Box-Bracket-08000011-2-Giant.jpg", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Box%20Mount.png" + }, + { + id: 16, + create_at: "2022-11-14", + update_at: "2024-03-04T20:39:34.000Z", + name: "Boarding Step -Woodgrain", + length: 2.04, + width: 1.53, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Woodgrain.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Boarding%20Step%20-Woodgrain.png" + }, + { + id: 15, + create_at: "2022-11-14", + update_at: "2024-03-04T20:39:15.000Z", + name: "Boarding Step -Grey", + length: 2.04, + width: 1.53, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Floating%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Boarding%20Step%20-Grey.png" + }, + { + id: 14, + create_at: "2022-11-14", + update_at: "2024-03-04T20:07:57.000Z", + name: "Bench-Woodgrain", + length: 1.98, + width: 4.37, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20WG%20Bench%20render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Bench-Woodgrain.png" + }, + { + id: 13, + create_at: "2022-11-14", + update_at: "2024-03-04T20:07:20.000Z", + name: "Bench-Grey", + length: 1.98, + width: 4.37, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Grey%20Bench%20Render.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Bench-Grey.png" + }, + { + id: 12, + create_at: "2022-11-14", + update_at: "2024-03-04T20:06:46.000Z", + name: "4ft Horizontal Bumper", + length: 0.32, + width: 4.02, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Horizontal%20Bumper%20Render%2048.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424ft%20Horizontal%20Bumper.png" + }, + { + id: 11, + create_at: "2022-11-14", + update_at: "2024-03-04T20:06:13.000Z", + name: "3ft Horizontal Bumper", + length: 0.32, + width: 3.02, + thumbnail: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742Paradise%20Roll%20In%20Dock%20Horizontal%20Bumper%20Render%2048.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887423ft%20Horizontal%20Bumper.png" + } + ], + mapping: null +}; + +export const ramps = { + error: false, + model: [ + { + id: 8, + create_at: "2023-05-01", + update_at: "2024-02-29T23:21:04.000Z", + category: 1, + length: 4, + width: 16, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20Wood.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20Wood.png", + material: 0 + }, + { + id: 7, + create_at: "2023-05-01", + update_at: "2024-02-29T23:20:51.000Z", + category: 1, + length: 4, + width: 16, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20SS.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20SS.png", + material: 2 + }, + { + id: 6, + create_at: "2023-05-01", + update_at: "2024-02-29T23:20:37.000Z", + category: 1, + length: 4, + width: 16, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x16%20TP%20Grey.png", + material: 1 + }, + { + id: 5, + create_at: "2023-05-01", + update_at: "2024-02-29T23:20:03.000Z", + category: 0, + length: 4, + width: 12, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20Wood.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20Wood.png", + material: 0 + }, + { + id: 4, + create_at: "2023-05-01", + update_at: "2024-02-29T23:19:52.000Z", + category: 0, + length: 4, + width: 12, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20SS.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20SS.png", + material: 2 + }, + { + id: 3, + create_at: "2023-05-01", + update_at: "2024-02-29T23:19:39.000Z", + category: 0, + length: 4, + width: 12, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20Grey.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424x12%20PR%20Grey.png", + material: 1 + } + ], + mapping: null +}; + +export const boat_lifts = { + error: false, + model: [ + { + id: 34, + create_at: "2022-11-17", + update_at: "2024-02-29T22:57:59.000Z", + model: "PH-24K-6", + weight_capacity: 24000, + lift_range: 6, + no_of_cylinders: 4, + length: 25.03, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-24K-4%2C5%2C6.png" + }, + { + id: 33, + create_at: "2022-11-17", + update_at: "2024-02-29T22:56:30.000Z", + model: "PH-24K-5", + weight_capacity: 24000, + lift_range: 5, + no_of_cylinders: 4, + length: 25.03, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-24K-4%2C5%2C6.png" + }, + { + id: 32, + create_at: "2022-11-17", + update_at: "2024-02-29T22:56:03.000Z", + model: "PH-24K-4", + weight_capacity: 24000, + lift_range: 4, + no_of_cylinders: 4, + length: 25.03, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-24K-4%2C5%2C6.png" + }, + { + id: 31, + create_at: "2022-11-17", + update_at: "2024-02-29T22:55:48.000Z", + model: "PH-20K-6", + weight_capacity: 20000, + lift_range: 6, + no_of_cylinders: 4, + length: 22.86, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-20K-4%2C5%2C6.png" + }, + { + id: 30, + create_at: "2022-11-17", + update_at: "2024-02-29T22:55:16.000Z", + model: "PH-20K-5", + weight_capacity: 20000, + lift_range: 5, + no_of_cylinders: 4, + length: 22.86, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-20K-4%2C5%2C6.png" + }, + { + id: 29, + create_at: "2022-11-17", + update_at: "2024-02-29T22:54:59.000Z", + model: "PH-20K-4", + weight_capacity: 20000, + lift_range: 4, + no_of_cylinders: 4, + length: 22.86, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-20K-4%2C5%2C6.png" + }, + { + id: 28, + create_at: "2022-11-17", + update_at: "2024-02-29T22:54:36.000Z", + model: "PH-15K-6", + weight_capacity: 15000, + lift_range: 6, + no_of_cylinders: 4, + length: 20.95, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-15K-4%2C5%2C6.png" + }, + { + id: 27, + create_at: "2022-11-17", + update_at: "2024-02-29T22:53:56.000Z", + model: "PH-15K-5", + weight_capacity: 15000, + lift_range: 5, + no_of_cylinders: 4, + length: 20.95, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-15K-4%2C5%2C6.png" + }, + { + id: 26, + create_at: "2022-11-17", + update_at: "2024-02-29T22:54:18.000Z", + model: "PH-15K-4", + weight_capacity: 15000, + lift_range: 4, + no_of_cylinders: 4, + length: 20.95, + width: 12.41, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-15K-4%2C5%2C6.png" + }, + { + id: 25, + create_at: "2022-11-17", + update_at: "2024-02-29T22:52:44.000Z", + model: "PH-12K-6", + weight_capacity: 12000, + lift_range: 6, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 24, + create_at: "2022-11-17", + update_at: "2024-02-29T22:52:30.000Z", + model: "PH-12K-5", + weight_capacity: 12000, + lift_range: 5, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 23, + create_at: "2022-11-17", + update_at: "2024-02-29T22:52:16.000Z", + model: "PH-13K-4", + weight_capacity: 13000, + lift_range: 4, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 22, + create_at: "2022-11-17", + update_at: "2024-02-29T22:52:00.000Z", + model: "PH-10K-6", + weight_capacity: 10000, + lift_range: 6, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 21, + create_at: "2022-11-17", + update_at: "2024-02-29T22:47:24.000Z", + model: "PH-10K-5", + weight_capacity: 10000, + lift_range: 5, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 20, + create_at: "2022-11-17", + update_at: "2024-02-29T22:47:08.000Z", + model: "PH-11K-4", + weight_capacity: 11000, + lift_range: 4, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 17, + create_at: "2022-11-17", + update_at: "2024-02-29T22:45:55.000Z", + model: "PH-11K-4S", + weight_capacity: 1100, + lift_range: 4, + no_of_cylinders: 4, + length: 16.85, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 16, + create_at: "2022-11-17", + update_at: "2024-02-29T22:45:38.000Z", + model: "PH-8K-6", + weight_capacity: 8000, + lift_range: 6, + no_of_cylinders: 4, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887424%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-10%2C12K-4%2C5%2C6.png" + }, + { + id: 15, + create_at: "2022-11-17", + update_at: "2024-02-28T20:45:35.000Z", + model: "PH-8K-5", + weight_capacity: 8000, + lift_range: 5, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 14, + create_at: "2022-11-17", + update_at: "2024-02-28T20:45:21.000Z", + model: "PH-8.5K-4", + weight_capacity: 8500, + lift_range: 4, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 13, + create_at: "2022-11-17", + update_at: "2024-02-28T20:45:03.000Z", + model: "PH-6K-6", + weight_capacity: 6000, + lift_range: 6, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 12, + create_at: "2022-11-17", + update_at: "2024-02-28T20:44:49.000Z", + model: "PH-6K-5", + weight_capacity: 6000, + lift_range: 5, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 11, + create_at: "2022-11-17", + update_at: "2024-02-28T20:44:33.000Z", + model: "PH-6.5K-4", + weight_capacity: 6500, + lift_range: 4, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 10, + create_at: "2022-11-17", + update_at: "2024-02-28T20:44:20.000Z", + model: "PH-2K-6", + weight_capacity: 2000, + lift_range: 6, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 9, + create_at: "2022-11-17", + update_at: "2024-02-28T20:41:32.000Z", + model: "PH-2K-5", + weight_capacity: 2000, + lift_range: 5, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + }, + { + id: 8, + create_at: "2022-11-17", + update_at: "2024-02-28T20:13:22.000Z", + model: "PH-2K-4", + weight_capacity: 2000, + lift_range: 4, + no_of_cylinders: 2, + length: 14.84, + width: 11.3, + image: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/0112854887422%20Cylinder%20Boat%20Lift.png", + top_view: + "https://dockbuilderapp.s3.us-west-2.amazonaws.com/baas/paralift/011285488742PH-6%2C8K-4%2C5%2C6.png" + } + ], + mapping: { + no_of_cylinders: { + 2: "2", + 4: "4" + } + } +}; diff --git a/src/favicon.svg b/src/favicon.svg new file mode 100644 index 0000000..de4aedd --- /dev/null +++ b/src/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/globalContext.jsx b/src/globalContext.jsx new file mode 100644 index 0000000..86c8b55 --- /dev/null +++ b/src/globalContext.jsx @@ -0,0 +1,103 @@ +import React, { useReducer } from "react"; +export const GlobalContext = React.createContext(); + +const initialState = { + globalMessage: "", + isOpen: true, + dockSideBarOpen: true, + path: "", + dockLoading: true, + dockLeft: null, + dockTop: null, +}; + +const reducer = ( state, action ) => { + switch ( action.type ) { + case "SNACKBAR": + return { + ...state, + globalMessage: action.payload.message, + }; + case "SETPATH": + return { + ...state, + path: action.payload.path, + }; + case "OPEN_SIDEBAR": + return { + ...state, + isOpen: action.payload.isOpen, + }; + case "TOGGLE_DOCK_SIDEBAR": + return { + ...state, + dockSideBarOpen: action.payload.dockSideBarOpen, + }; + case "DOCK_LOADING": + return { + ...state, + dockLoading: action.payload, + }; + case "UPDATE_DOCK_TOP": + return { + ...state, + dockTop: action.payload, + }; + case "UPDATE_DOCK_LEFT": + return { + ...state, + dockLeft: action.payload, + }; + + default: + return state; + } +}; + +export const showToast = ( dispatch, message, timeout = 3000 ) => { + dispatch( { + type: "SNACKBAR", + payload: { + message, + }, + } ); + + setTimeout( () => { + dispatch( { + type: "SNACKBAR", + payload: { + message: "", + }, + } ); + }, timeout ); +}; + +export const toggleDockSideBar = ( dispatch, dockSideBarOpen ) => { + dispatch( { + type: "TOGGLE_DOCK_SIDEBAR", + payload: { + dockSideBarOpen + }, + } ); +}; + +const GlobalProvider = ( { children } ) => { + const [ state, dispatch ] = useReducer( reducer, initialState ); + + // React.useEffect(() => { + + // }, []); + + return ( + + { children } + + ); +}; + +export default GlobalProvider; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..2dbfdfb --- /dev/null +++ b/src/index.css @@ -0,0 +1,143 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + transition: all .5s ease; +} +*::-webkit-scrollbar { + width: 0; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + /* color: #ffffff65; */ +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.sidebar-holder { + width: 100%; + min-width: 240px; + max-width: 240px; + position: relative; + background: #151515; + z-index: 2; + transition: all 0.3s; + min-height: 100vh; + overflow: hidden; + transition: 0.2s; +} + +.open-nav { + min-width: 0px !important; + max-width: 0px !important; + width: 0 !important; + transition: 0.2s; + opacity: 0; +} + +.close-dock-panel { + min-height: 0px !important; + max-height: 0px !important; + height: 0 !important; + transition: 0.2s; + opacity: 0; + /* overflow: hidden; */ +} + +.sidebar-list ul li a { + padding: 10px; + display: block; + width: 100%; + font-size: 18px; + font-weight: 600; + transition: 0.2s ease-in; + text-transform: capitalize; +} + +.sidebar-list ul li a:hover { + color: #151515; + background: white; +} + +.page-header { + width: 100%; + padding: 20px; + background: white; +} + +.page-header span { + cursor: pointer; + display: block; + width: fit-content; + font-size: 20px; +} + +.center-svg { + aspect-ratio: 1/1; + align-items: center; + justify-content: center; + line-height: 1.2em !important; +} + +/* Custom BEN */ + +.modal-holder { + position: fixed; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.782); + backdrop-filter: blur(3px); + min-height: 100vh; + width: 100%; + z-index: 99999999; +} +.cus-m-close { + position: absolute; + right: 40px; + top: 40px; + cursor: pointer; +} + +.filter-close{ + position: absolute; + right: 20px; + top: 20px; + cursor: pointer; +} +.uppy-Dashboard-inner { + width: 100% !important; +} + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@media screen and (max-width: 767px) { + .sidebar-holder { + width: 100%; + min-width: 200px; + max-width: 200px; + position: fixed; + top: 0; + left: 0; + } + + .page-header span { + margin-left: auto; + } +} \ No newline at end of file diff --git a/src/index.jsx b/src/index.jsx new file mode 100644 index 0000000..8cf4fe2 --- /dev/null +++ b/src/index.jsx @@ -0,0 +1,14 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import "@fontsource/rajdhani"; +import "./index.css"; +import "./output.css"; +import App from "./App"; + +const root = ReactDOM.createRoot(document.getElementById("root")); + +root.render( + + + +); diff --git a/src/logo.svg b/src/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..579b427 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,310 @@ +import React from "react"; +import { AuthContext } from "./authContext"; +import { Routes, Route } from "react-router-dom"; + +import { AdminHeader, TopHeader, PublicHeader, SnackBar } from "./components"; + +import { NotFoundPage } from "Pages/404"; + +import { + AddAdminAccessoriesPage, + AddAdminBoatLiftsPage, + AddAdminCmsPage, + AddAdminDealersPage, + AddAdminDocksPage, + AddAdminEmailPage, + AddAdminInstructionsPage, + AddAdminPhotoPage, + AddAdminQuotesPage, + AddAdminUserPage, + AddAdminWedgesPage, + AddAdminQuotesMailRecipientsPage, + AdminQuotesMailRecipientsListPage, + AdminAccessoriesListPage, + AdminBoatLiftsListPage, + AdminCmsListPage, + AdminDashboardPage, + AdminDealersListPage, + AdminDocksListPage, + AdminEmailListPage, + AdminForgotPage, + AdminInstructionsListPage, + AdminLoginPage, + AdminPhotoListPage, + AdminProfilePage, + AdminQuotesListPage, + AdminResetPage, + AdminUserListPage, + AdminWedgesListPage, + EditAdminAccessoriesPage, + EditAdminBoatLiftsPage, + EditAdminCmsPage, + EditAdminDealersPage, + EditAdminDocksPage, + EditAdminEmailPage, + EditAdminInstructionsPage, + EditAdminQuotesPage, + EditAdminUserPage, + EditAdminWedgesPage, + EditAdminQuotesMailRecipientsPage, + ViewAdminAccessoriesPage, + ViewAdminBoatLiftsPage, + ViewAdminDealersPage, + ViewAdminDocksPage, + ViewAdminInstructionsPage, + ViewAdminQuotesPage, + ViewAdminWedgesPage, + ViewAdminQuotesMailRecipientsPage, + AdminRampsListPage, + AddAdminRampsPage, + ViewAdminRampsPage, + EditAdminRampsPage, +} from "Pages/admin"; + +import { DockBuilderPage } from "Pages/dock"; + +function renderHeader(role) { + switch (role) { + case "admin": + return ; + + default: + return ; + } +} + +function renderRoutes(role) { + switch (role) { + case "admin": + return ( + + }> + } + > + } + > + + } + > + } + > + } + > + } + > + + } + > + } + > + } + > + } + > + + }> + } + > + } + > + + }> + } + > + + } + > + } + > + } + > + } + > + + } + > + } + > + } + > + } + > + + }> + } + > + } + > + } + > + + }> + }> + } + > + + } + > + } + > + } + > + } + > + + }> + }> + } + > + + }> + } + > + } + > + } + > + + }> + } + > + } + > + } + > + + }> + } + > + } + > + } + > + + {/* || } + > */} + + ); + + default: + return ( + + }> + }> + } + > + }> + + }> + + ); + } +} + +function Main() { + const { state } = React.useContext(AuthContext); + + return ( +
+
+ {!state.isAuthenticated ? : renderHeader(state?.role)} +
+ {state.isAuthenticated ? : null} +
+ {!state.isAuthenticated + ? renderRoutes("none") + : renderRoutes(state?.role)} +
+
+
+ +
+ ); +} + +export default Main; diff --git a/src/output.css b/src/output.css new file mode 100644 index 0000000..676d34b --- /dev/null +++ b/src/output.css @@ -0,0 +1,5097 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; +} + +.scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.sidebar-holder { + width: 100%; + min-width: 240px; + max-width: 240px; + position: relative; + background: #151515; + color: #fff; + z-index: 2; + transition: all 0.3s; + min-height: 100vh; + overflow: hidden; + transition: 0.2s; +} + +.open-nav { + min-width: 0px !important; + max-width: 0px !important; + width: 0 !important; + transition: 0.2s; + opacity: 0; +} + +.sidebar-list ul li a { + padding: 10px; + display: block; + width: 100%; + font-size: 18px; + font-weight: 600; + transition: 0.2s ease-in; + text-transform: capitalize; +} + +.sidebar-list ul li a:hover { + color: #151515; + background: white; +} + +.page-header { + width: 100%; + padding: 20px; + background: white; +} + +.page-header span { + cursor: pointer; + display: block; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; + font-size: 20px; +} + +.center-svg { + aspect-ratio: 1/1; + align-items: center; + justify-content: center; + line-height: 1.2em !important; +} + +.uppy-Dashboard-inner { + width: 100% !important; +} + +/* +! tailwindcss v3.0.24 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +*/ + +html { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: Inter, sans-serif; + /* 4 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input:-ms-input-placeholder, textarea:-ms-input-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* +Ensure the default browser behavior of the `hidden` attribute. +*/ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +:root { + --bs-blue: #0d6efd; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #d63384; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #198754; + --bs-teal: #20c997; + --bs-cyan: #0dcaf0; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #0d6efd; + --bs-secondary: #6c757d; + --bs-success: #198754; + --bs-info: #0dcaf0; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 13, 110, 253; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 25, 135, 84; + --bs-info-rgb: 13, 202, 240; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 33, 37, 41; + --bs-body-bg-rgb: 255, 255, 255; + --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #212529; + --bs-body-bg: #fff; +} + +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.is-invalid ~ .invalid-feedback { + display: block; +} + +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.form-control.is-invalid { + border-color: #dc3545; + padding-right: calc(1.5em + 0.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.375em + 0.1875rem) center; + background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} + +textarea.form-control.is-invalid { + padding-right: calc(1.5em + 0.75rem); + background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); +} + +.form-select.is-invalid { + border-color: #dc3545; +} + +.form-select.is-invalid:not([multiple]):not([size]) { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.form-select.is-invalid:not([multiple])[size="1"] { + padding-right: 4.125rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); + background-position: right 0.75rem center, center right 2.25rem; + background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); +} + +.form-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} + +.form-check-input.is-invalid { + border-color: #dc3545; +} + +.form-check-input.is-invalid:checked { + background-color: #dc3545; +} + +.form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); +} + +.form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.input-group .form-control.is-invalid { + z-index: 2; +} + +.input-group .form-select.is-invalid { + z-index: 2; +} + +.input-group .form-control.is-invalid:focus { + z-index: 3; +} + +.input-group .form-select.is-invalid:focus { + z-index: 3; +} + +.btn.active { + box-shadow: none; +} + +.btn.active:focus { + box-shadow: none; +} + +.fade { + transition: opacity 0.15s linear; +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} + +.dropdown-menu { + z-index: 1000; +} + +.dropdown-item.active { + color: #1f2937; + -webkit-text-decoration: none; + text-decoration: none; + background-color: #0d6efd; +} + +.dropdown-item:active { + color: #1f2937; + -webkit-text-decoration: none; + text-decoration: none; + background-color: #0d6efd; +} + +.dropdown-item:disabled { + color: #adb5bd; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-menu-dark .dropdown-item.active { + color: #fff; + background-color: #0d6efd; +} + +.dropdown-menu-dark .dropdown-item:active { + color: #fff; + background-color: #0d6efd; +} + +.dropdown-menu-dark .dropdown-item.disabled { + color: #adb5bd; +} + +.dropdown-menu-dark .dropdown-item:disabled { + color: #adb5bd; +} + +.nav-tabs .nav-link { + color: #4b5563; +} + +.nav-tabs .nav-link:hover { + isolation: isolate; +} + +.nav-tabs .nav-link:focus { + isolation: isolate; +} + +.nav-tabs .nav-link.disabled { + color: #9ca3af; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active { + color: #2563eb; + border-color: #2563eb; +} + +.nav-tabs .nav-item.show .nav-link { + color: #2563eb; + border-color: #2563eb; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + background: #f3f4f6; + color: #4b5563; + box-shadow: none; +} + +.nav-pills .nav-link.active { + background: #2563eb; + color: #fff; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +.nav-pills .show > .nav-link { + background: #2563eb; + color: #fff; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +.nav-pills .disabled { + color: #9ca3af; + background-color: rgba(243, 244, 246, 0.5); +} + +.nav-pills.menu-sidebar .nav-link { + background-color: transparent; + box-shadow: none; + padding: 0 5px; + border-radius: 0; +} + +.nav-pills.menu-sidebar .nav-link.active { + color: #1266f1; + font-weight: 600; + border-left: 0.125rem solid #1266f1; +} + +.nav-justified > .nav-link { + -ms-flex-basis: 0; + flex-basis: 0; +} + +.nav-justified .nav-item { + -ms-flex-basis: 0; + flex-basis: 0; +} + +.tab-content > .active { + display: block; +} + +.navbar-expand .navbar-nav { + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: calc(0.5rem - 1px); + border-bottom-left-radius: calc(0.5rem - 1px); +} + +.btn-close.disabled { + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + opacity: 0.25; +} + +.modal { + z-index: 1055; +} + +.modal-dialog { + margin: 0.5rem; +} + +.modal.fade .modal-dialog { + transition: transform 0.3s ease-out; + transform: translate(0, -50px); +} + +.modal.show .modal-dialog { + transform: none; +} + +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-body { + flex: 1 1 auto; +} + +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +.tooltip { + position: absolute; + z-index: 1080; + display: block; + margin: 0; + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + -webkit-text-align: start; + text-align: start; + -webkit-text-decoration: none; + text-decoration: none; + -webkit-text-shadow: none; + text-shadow: none; + -webkit-text-transform: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + opacity: 0; +} + +.tooltip.show { + opacity: 1; +} + +.bs-tooltip-top .tooltip-arrow { + bottom: 0; +} + +.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { + bottom: 0; +} + +.bs-tooltip-top .tooltip-arrow::before { + top: -1px; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { + top: -1px; + border-width: 0.4rem 0.4rem 0; + border-top-color: #000; +} + +.bs-tooltip-end .tooltip-arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { + left: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-end .tooltip-arrow::before { + right: -1px; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { + right: -1px; + border-width: 0.4rem 0.4rem 0.4rem 0; + border-right-color: #000; +} + +.bs-tooltip-bottom .tooltip-arrow { + top: 0; +} + +.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { + top: 0; +} + +.bs-tooltip-bottom .tooltip-arrow::before { + bottom: -1px; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { + bottom: -1px; + border-width: 0 0.4rem 0.4rem; + border-bottom-color: #000; +} + +.bs-tooltip-start .tooltip-arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { + right: 0; + width: 0.4rem; + height: 0.8rem; +} + +.bs-tooltip-start .tooltip-arrow::before { + left: -1px; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { + left: -1px; + border-width: 0.4rem 0 0.4rem 0.4rem; + border-left-color: #000; +} + +.tooltip-inner { + max-width: 200px; + font-size: 14px; + padding: 6px 16px; + color: #fff; + -webkit-text-align: center; + text-align: center; + background-color: #6d6d6d; + border-radius: 0.25rem; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1070; + display: block; + max-width: 276px; + font-family: var(--bs-font-sans-serif); + font-style: normal; + font-weight: 400; + line-height: 1.5; + -webkit-text-align: start; + text-align: start; + -webkit-text-decoration: none; + text-decoration: none; + -webkit-text-shadow: none; + text-shadow: none; + -webkit-text-transform: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + font-size: 0.875rem; + word-wrap: break-word; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-radius: 0.5rem; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); +} + +.bs-popover-top > .popover-arrow { + bottom: calc(-0.5rem - 1px); +} + +.bs-popover-auto[data-popper-placement^=top] > .popover-arrow { + bottom: calc(-0.5rem - 1px); +} + +.bs-popover-top > .popover-arrow::before { + bottom: 0; + border-width: 0.5rem 0.5rem 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { + bottom: 0; + border-width: 0.5rem 0.5rem 0; + border-top-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-top > .popover-arrow::after { + bottom: 1px; + border-width: 0.5rem 0.5rem 0; + border-top-color: #fff; +} + +.bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + bottom: 1px; + border-width: 0.5rem 0.5rem 0; + border-top-color: #fff; +} + +.bs-popover-end > .popover-arrow { + left: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; +} + +.bs-popover-auto[data-popper-placement^=right] > .popover-arrow { + left: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; +} + +.bs-popover-end > .popover-arrow::before { + left: 0; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { + left: 0; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-end > .popover-arrow::after { + left: 1px; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: #fff; +} + +.bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + left: 1px; + border-width: 0.5rem 0.5rem 0.5rem 0; + border-right-color: #fff; +} + +.bs-popover-bottom > .popover-arrow { + top: calc(-0.5rem - 1px); +} + +.bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { + top: calc(-0.5rem - 1px); +} + +.bs-popover-bottom > .popover-arrow::before { + top: 0; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { + top: 0; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-bottom > .popover-arrow::after { + top: 1px; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: #fff; +} + +.bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + top: 1px; + border-width: 0 0.5rem 0.5rem 0.5rem; + border-bottom-color: #fff; +} + +.bs-popover-bottom .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f0f0f0; +} + +.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: 1rem; + margin-left: -0.5rem; + content: ""; + border-bottom: 1px solid #f0f0f0; +} + +.bs-popover-start > .popover-arrow { + right: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; +} + +.bs-popover-auto[data-popper-placement^=left] > .popover-arrow { + right: calc(-0.5rem - 1px); + width: 0.5rem; + height: 1rem; +} + +.bs-popover-start > .popover-arrow::before { + right: 0; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { + right: 0; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: rgba(0, 0, 0, 0.25); +} + +.bs-popover-start > .popover-arrow::after { + right: 1px; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: #fff; +} + +.bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + right: 1px; + border-width: 0.5rem 0 0.5rem 0.5rem; + border-left-color: #fff; +} + +.popover-header { + padding: 0.5rem 1rem; + margin-bottom: 0; + font-size: 1rem; + background-color: #fff; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); + border-top-left-radius: 0.5rem; + border-top-right-radius: 0.5rem; + font-weight: 500; +} + +.popover-header:empty { + display: none; +} + +.popover-body { + padding: 1rem 1rem; + color: #212529; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-item { + display: none; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: transform 0.6s ease-in-out; +} + +.carousel-item.active { + display: block; +} + +.carousel-item-next { + display: block; +} + +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start) { + transform: translateX(100%); +} + +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end) { + transform: translateX(-100%); +} + +.active.carousel-item-start { + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; +} + +.carousel-fade .carousel-item.active { + z-index: 1; + opacity: 1; +} + +.carousel-fade .carousel-item-next.carousel-item-start { + z-index: 1; + opacity: 1; +} + +.carousel-fade .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; +} + +.carousel-fade .active.carousel-item-start { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} + +.carousel-fade .active.carousel-item-end { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} + +.carousel-indicators { + z-index: 2; + margin-right: 15%; + margin-left: 15%; + list-style: none; +} + +.carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + -webkit-text-indent: -999px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: 0.5; + transition: opacity 0.6s ease; +} + +.carousel-indicators .active { + opacity: 1; +} + +.carousel-dark .carousel-indicators [data-bs-target] { + background-color: #000; +} + +.offcanvas { + z-index: 1045; +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.offcanvas-backdrop.fade { + opacity: 0; +} + +.offcanvas-backdrop.show { + opacity: 0.5; +} + +.offcanvas.show { + transform: none; +} + +.sticky-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentColor; + opacity: 0.25; +} + +.animation { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + padding: auto; +} + +.fade-in { + -webkit-animation-name: _fade-in; + animation-name: _fade-in; +} + +.fade-out { + -webkit-animation-name: _fade-out; + animation-name: _fade-out; +} + +.animation.infinite { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} + +.animation.delay-1s { + -webkit-animation-delay: 1s; + animation-delay: 1s; +} + +.animation.delay-2s { + -webkit-animation-delay: 2s; + animation-delay: 2s; +} + +.animation.delay-3s { + -webkit-animation-delay: 3s; + animation-delay: 3s; +} + +.animation.delay-4s { + -webkit-animation-delay: 4s; + animation-delay: 4s; +} + +.animation.delay-5s { + -webkit-animation-delay: 5s; + animation-delay: 5s; +} + +.animation.fast { + -webkit-animation-duration: 800ms; + animation-duration: 800ms; +} + +.animation.faster { + -webkit-animation-duration: 500ms; + animation-duration: 500ms; +} + +.animation.slow { + -webkit-animation-duration: 2s; + animation-duration: 2s; +} + +.animation.slower { + -webkit-animation-duration: 3s; + animation-duration: 3s; +} + +.slide-in-left { + -webkit-animation-name: _slide-in-left; + animation-name: _slide-in-left; +} + +.slide-in-right { + -webkit-animation-name: _slide-in-right; + animation-name: _slide-in-right; +} + +.slide-out-left { + -webkit-animation-name: _slide-out-left; + animation-name: _slide-out-left; +} + +.slide-out-right { + -webkit-animation-name: _slide-out-right; + animation-name: _slide-out-right; +} + +.ripple-surface { + position: relative; + overflow: hidden; + display: inline-block; + vertical-align: bottom; +} + +.ripple-surface-unbound { + overflow: visible; +} + +.ripple-wave { + background-image: radial-gradient(circle, rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, transparent 70%); + border-radius: 50%; + opacity: 0.5; + pointer-events: none; + position: absolute; + touch-action: none; + transform: scale(0); + transition-property: transform, opacity; + transition-timing-function: cubic-bezier(0, 0, 0.15, 1), cubic-bezier(0, 0, 0.15, 1); + z-index: 999; +} + +.ripple-wave.active { + transform: scale(1); + opacity: 0; +} + +.btn .ripple-wave { + background-image: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); +} + +.ripple-surface-primary .ripple-wave { + background-image: radial-gradient(circle, rgba(18, 102, 241, 0.2) 0, rgba(18, 102, 241, 0.3) 40%, rgba(18, 102, 241, 0.4) 50%, rgba(18, 102, 241, 0.5) 60%, rgba(18, 102, 241, 0) 70%); +} + +.ripple-surface-secondary .ripple-wave { + background-image: radial-gradient(circle, rgba(178, 60, 253, 0.2) 0, rgba(178, 60, 253, 0.3) 40%, rgba(178, 60, 253, 0.4) 50%, rgba(178, 60, 253, 0.5) 60%, rgba(178, 60, 253, 0) 70%); +} + +.ripple-surface-success .ripple-wave { + background-image: radial-gradient(circle, rgba(0, 183, 74, 0.2) 0, rgba(0, 183, 74, 0.3) 40%, rgba(0, 183, 74, 0.4) 50%, rgba(0, 183, 74, 0.5) 60%, rgba(0, 183, 74, 0) 70%); +} + +.ripple-surface-info .ripple-wave { + background-image: radial-gradient(circle, rgba(57, 192, 237, 0.2) 0, rgba(57, 192, 237, 0.3) 40%, rgba(57, 192, 237, 0.4) 50%, rgba(57, 192, 237, 0.5) 60%, rgba(57, 192, 237, 0) 70%); +} + +.ripple-surface-warning .ripple-wave { + background-image: radial-gradient(circle, rgba(255, 169, 0, 0.2) 0, rgba(255, 169, 0, 0.3) 40%, rgba(255, 169, 0, 0.4) 50%, rgba(255, 169, 0, 0.5) 60%, rgba(255, 169, 0, 0) 70%); +} + +.ripple-surface-danger .ripple-wave { + background-image: radial-gradient(circle, rgba(249, 49, 84, 0.2) 0, rgba(249, 49, 84, 0.3) 40%, rgba(249, 49, 84, 0.4) 50%, rgba(249, 49, 84, 0.5) 60%, rgba(249, 49, 84, 0) 70%); +} + +.ripple-surface-light .ripple-wave { + background-image: radial-gradient(circle, rgba(251, 251, 251, 0.2) 0, rgba(251, 251, 251, 0.3) 40%, rgba(251, 251, 251, 0.4) 50%, rgba(251, 251, 251, 0.5) 60%, rgba(251, 251, 251, 0) 70%); +} + +.ripple-surface-dark .ripple-wave { + background-image: radial-gradient(circle, rgba(38, 38, 38, 0.2) 0, rgba(38, 38, 38, 0.3) 40%, rgba(38, 38, 38, 0.4) 50%, rgba(38, 38, 38, 0.5) 60%, rgba(38, 38, 38, 0) 70%); +} + +.ripple-surface-white .ripple-wave { + background-image: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%); +} + +.ripple-surface-black .ripple-wave { + background-image: radial-gradient(circle, rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, transparent 70%); +} + +.datepicker-toggle-button { + position: absolute; + outline: none; + border: none; + background-color: transparent; + right: 10px; + top: 50%; + transform: translate(-50%, -50%); +} + +.datepicker-toggle-button:focus { + color: #2979ff; +} + +.datepicker-toggle-button:hover { + color: #2979ff; +} + +.datepicker-backdrop { + width: 100%; + height: 100%; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 1065; +} + +.datepicker-dropdown-container { + width: 328px; + height: 380px; + background-color: #fff; + border-radius: 0.5rem; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.07), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + z-index: 1066; +} + +.datepicker-modal-container { + display: flex; + flex-direction: column; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 328px; + height: 512px; + background-color: #fff; + border-radius: 0.6rem 0.6rem 0.5rem 0.5rem; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.07), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + z-index: 1066; +} + +.datepicker-header { + height: 120px; + padding-right: 24px; + padding-left: 24px; + background-color: #2979ff; + display: flex; + flex-direction: column; + border-radius: 0.5rem 0.5rem 0 0; +} + +.datepicker-title { + height: 32px; + display: flex; + flex-direction: column; + justify-content: flex-end; +} + +.datepicker-title-text { + font-size: 10px; + font-weight: 400; + -webkit-text-transform: uppercase; + text-transform: uppercase; + letter-spacing: 1.7px; + color: #fff; +} + +.datepicker-date { + height: 72px; + display: flex; + flex-direction: column; + justify-content: flex-end; +} + +.datepicker-date-text { + font-size: 34px; + font-weight: 400; + color: #fff; +} + +.datepicker-main { + position: relative; + height: 100%; +} + +.datepicker-date-controls { + padding: 10px 12px 0 12px; + display: flex; + justify-content: space-between; + color: rgba(0, 0, 0, 0.64); +} + +.datepicker-view-change-button { + padding: 10px; + color: #666; + font-weight: 500; + font-size: 0.9rem; + border-radius: 10px; + box-shadow: none; + background-color: transparent; + margin: 0; + border: none; +} + +.datepicker-view-change-button:hover { + background-color: #eee; +} + +.datepicker-view-change-button:focus { + background-color: #eee; +} + +.datepicker-view-change-button:after { + content: ""; + display: inline-block; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top-width: 5px; + border-top-style: solid; + margin: 0 0 0 5px; + vertical-align: middle; +} + +.datepicker-arrow-controls { + margin-top: 10px; +} + +.datepicker-previous-button { + position: relative; + padding: 0; + width: 40px; + height: 40px; + line-height: 40px; + border: none; + outline: none; + margin: 0; + color: rgba(0, 0, 0, 0.64); + background-color: transparent; + margin-right: 24px; +} + +.datepicker-previous-button:hover { + background-color: #eee; + border-radius: 50%; +} + +.datepicker-previous-button:focus { + background-color: #eee; + border-radius: 50%; +} + +.datepicker-previous-button::after { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: absolute; + content: ""; + margin: 15.5px; + border: 0 solid currentColor; + border-top-width: 2px; + border-left-width: 2px; + transform: translateX(2px) rotate(-45deg); +} + +.datepicker-next-button { + position: relative; + padding: 0; + width: 40px; + height: 40px; + line-height: 40px; + border: none; + outline: none; + margin: 0; + color: rgba(0, 0, 0, 0.64); + background-color: transparent; +} + +.datepicker-next-button:hover { + background-color: #eee; + border-radius: 50%; +} + +.datepicker-next-button:focus { + background-color: #eee; + border-radius: 50%; +} + +.datepicker-next-button::after { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: absolute; + content: ""; + margin: 15.5px; + border: 0 solid currentColor; + border-top-width: 2px; + border-right-width: 2px; + transform: translateX(-2px) rotate(45deg); +} + +.datepicker-view { + padding-left: 12px; + padding-right: 12px; + outline: none; +} + +.datepicker-table { + margin-right: auto; + margin-left: auto; + width: 304px; +} + +.datepicker-day-heading { + width: 40px; + height: 40px; + -webkit-text-align: center; + text-align: center; + font-size: 12px; + font-weight: 400; +} + +.datepicker-cell { + -webkit-text-align: center; + text-align: center; +} + +.datepicker-cell.disabled { + color: #ccc; + cursor: default; + pointer-events: none; +} + +.datepicker-cell.disabled:hover { + cursor: default; +} + +.datepicker-cell:hover { + cursor: pointer; +} + +.datepicker-cell:not(.disabled):not(.selected):hover .datepicker-cell-content { + background-color: #d3d3d3; +} + +.datepicker-cell.selected .datepicker-cell-content { + background-color: #2979ff; + color: #fff; +} + +.datepicker-cell:not(.selected).focused .datepicker-cell-content { + background-color: #eee; +} + +.datepicker-cell.focused .datepicker-cell-content.selected { + background-color: #2979ff; +} + +.datepicker-cell.current .datepicker-cell-content { + border: 1px solid #000; +} + +.datepicker-small-cell { + width: 40px; + height: 40px; +} + +.datepicker-small-cell-content { + width: 36px; + height: 36px; + line-height: 36px; + border-radius: 50%; + font-size: 13px; +} + +.datepicker-large-cell { + width: 76px; + height: 42px; +} + +.datepicker-large-cell-content { + width: 72px; + height: 40px; + line-height: 40px; + padding: 1px 2px; + border-radius: 999px; +} + +.datepicker-footer { + height: 56px; + display: flex; + position: absolute; + width: 100%; + bottom: 0; + justify-content: flex-end; + align-items: center; + padding-left: 12px; + padding-right: 12px; +} + +.datepicker-footer-btn { + background-color: #fff; + color: #2979ff; + border: none; + cursor: pointer; + padding: 0 10px; + -webkit-text-transform: uppercase; + text-transform: uppercase; + font-size: 0.8rem; + font-weight: 500; + height: 40px; + line-height: 40px; + letter-spacing: 0.1rem; + border-radius: 10px; + margin-bottom: 10px; +} + +.datepicker-footer-btn:hover { + background-color: #eee; +} + +.datepicker-footer-btn:focus { + background-color: #eee; +} + +.datepicker-clear-btn { + margin-right: auto; +} + +.timepicker-wrapper { + touch-action: none; + z-index: 1065; + opacity: 0; + right: 0; + bottom: 0; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.4); +} + +.timepicker-elements { + min-width: 310px; + min-height: 325px; + background: #fff; + border-top-right-radius: 0.6rem; + border-top-left-radius: 0.6rem; +} + +.timepicker-head { + background-color: #2979ff; + height: 100px; + border-top-right-radius: 0.5rem; + border-top-left-radius: 0.5rem; + padding: 10px 24px 10px 50px; +} + +.timepicker-button { + font-size: 0.8rem; + min-width: 64px; + box-sizing: border-box; + font-weight: 500; + line-height: 40px; + border-radius: 10px; + letter-spacing: 0.1rem; + -webkit-text-transform: uppercase; + text-transform: uppercase; + color: #2979ff; + border: none; + background-color: transparent; + transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + outline: none; + padding: 0 10px; + height: 40px; + margin-bottom: 10px; +} + +.timepicker-button:hover { + background-color: rgba(0, 0, 0, 0.08); +} + +.timepicker-button:focus { + outline: none; + background-color: rgba(0, 0, 0, 0.08); +} + +.timepicker-current { + font-size: 3.75rem; + font-weight: 300; + line-height: 1.2; + letter-spacing: -0.00833em; + color: #fff; + opacity: 0.54; + border: none; + background: transparent; + padding: 0; +} + +.timepicker-current.active { + opacity: 1; +} + +.timepicker-current-wrapper { + direction: ltr; +} + +.timepicker-mode-wrapper { + margin-left: 20px; + font-size: 18px; + color: rgba(255, 255, 255, 0.54); +} + +.timepicker-mode-wrapper.active { + opacity: 1; +} + +.timepicker-clock-wrapper { + min-width: 310px; + max-width: 325px; + min-height: 305px; + overflow-x: hidden; + height: 100%; +} + +.timepicker-clock { + position: relative; + border-radius: 100%; + width: 260px; + height: 260px; + cursor: default; + margin: 0 auto; + background-color: rgba(0, 0, 0, 0.07); +} + +.timepicker-time-tips-minutes.active { + color: #fff; + background-color: #2979ff; + font-weight: 400; +} + +.timepicker-time-tips-inner.active { + color: #fff; + background-color: #2979ff; + font-weight: 400; +} + +.timepicker-time-tips-hours.active { + color: #fff; + background-color: #2979ff; + font-weight: 400; +} + +.timepicker-time-tips-minutes.disabled { + color: #b3afaf; + pointer-events: none; + background-color: transparent; +} + +.timepicker-time-tips-inner.disabled { + color: #b3afaf; + pointer-events: none; + background-color: transparent; +} + +.timepicker-time-tips-hours.disabled { + color: #b3afaf; + pointer-events: none; + background-color: transparent; +} + +.timepicker-dot { + font-weight: 300; + line-height: 1.2; + letter-spacing: -0.00833em; + color: #fff; + font-size: 3.75rem; + opacity: 0.54; + border: none; + background: transparent; + padding: 0; +} + +.timepicker-middle-dot { + top: 50%; + left: 50%; + width: 6px; + height: 6px; + transform: translate(-50%, -50%); + border-radius: 50%; + background-color: #2979ff; +} + +.timepicker-hand-pointer { + background-color: #2979ff; + bottom: 50%; + height: 40%; + left: calc(50% - 1px); + transform-origin: center bottom 0; + width: 2px; +} + +.timepicker-time-tips.active { + color: #fff; +} + +.timepicker-circle { + top: -21px; + left: -15px; + width: 4px; + border: 14px solid #2979ff; + height: 4px; + box-sizing: content-box; + border-radius: 100%; +} + +.timepicker-hour-mode { + padding: 0; + background-color: transparent; + border: none; + color: #fff; + opacity: 0.54; + cursor: pointer; +} + +.timepicker-hour { + cursor: pointer; +} + +.timepicker-minute { + cursor: pointer; +} + +.timepicker-hour-mode:hover { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-hour-mode:focus { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-hour:hover { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-hour:focus { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-minute:hover { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-minute:focus { + background-color: rgba(0, 0, 0, 0.15); + outline: none; +} + +.timepicker-hour-mode.active { + color: #fff; + opacity: 1; +} + +.timepicker-hour.active { + color: #fff; + opacity: 1; +} + +.timepicker-minute.active { + color: #fff; + opacity: 1; +} + +.timepicker-footer { + border-bottom-left-radius: 0.5rem; + border-bottom-right-radius: 0.5rem; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + height: 56px; + padding-left: 12px; + padding-right: 12px; + background-color: #fff; +} + +.timepicker-container { + max-height: calc(100% - 64px); + overflow-y: auto; + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.07), 0 4px 6px -2px rgba(0, 0, 0, 0.05); +} + +.timepicker-icon-up.active { + opacity: 1; +} + +.timepicker-icon-down.active { + opacity: 1; +} + +.timepicker-toggle-button { + position: absolute; + outline: none; + border: none; + background-color: transparent; + right: 10px; + top: 50%; + transform: translate(-50%, -50%); + transition: all 0.3s ease; + cursor: pointer; +} + +.timepicker-toggle-button:hover { + color: #2979ff; +} + +.timepicker-toggle-button:focus { + color: #2979ff; +} + +.timepicker-input:focus + .timepicker-toggle-button { + color: #2979ff; +} + +.timepicker-input:focus + .timepicker-toggle-button i { + color: #2979ff; +} + +.timepicker a.timepicker-toggle-button { + right: 1px; +} + +.timepicker-toggle-button.timepicker-icon { + right: 1px; +} + +.timepicker-modal .fade.show { + opacity: 1; +} + +.stepper { + position: relative; + padding: 0; + margin: 0; + width: 100%; + list-style: none; + overflow: hidden; + transition: height 0.2s ease-in-out; +} + +.stepper:not(.stepper-vertical) { + display: flex; + justify-content: space-between; +} + +.stepper:not(.stepper-vertical) .stepper-content { + position: absolute; + width: 100%; + padding: 1rem; +} + +.stepper:not(.stepper-vertical) .stepper-step { + flex: auto; + height: 4.5rem; +} + +.stepper:not(.stepper-vertical) .stepper-step:first-child .stepper-head { + padding-left: 1.5rem; +} + +.stepper:not(.stepper-vertical) .stepper-step:last-child .stepper-head { + padding-right: 1.5rem; +} + +.stepper:not(.stepper-vertical) .stepper-step:not(:first-child) .stepper-head:before { + flex: 1; + height: 1px; + width: 100%; + margin-right: 0.5rem; + content: ""; + background-color: rgba(0, 0, 0, 0.1); +} + +.stepper:not(.stepper-vertical) .stepper-step:not(:last-child) .stepper-head:after { + flex: 1; + height: 1px; + width: 100%; + margin-left: 0.5rem; + content: ""; + background-color: rgba(0, 0, 0, 0.1); +} + +.stepper:not(.stepper-vertical) .stepper-head-icon { + margin: 1.5rem 0.5rem 1.5rem 0; +} + +.stepper.stepper-mobile { + justify-content: center; + align-items: flex-end; +} + +.stepper.stepper-mobile.stepper-progress-bar .stepper-head-icon { + display: none; +} + +.stepper.stepper-mobile .stepper-step { + flex: unset; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; + margin: 1rem 0 1rem 0; +} + +.stepper.stepper-mobile .stepper-step:not(:last-child) .stepper-head:after { + margin-left: 0; +} + +.stepper.stepper-mobile .stepper-step:not(:first-child) .stepper-head:before { + margin-right: 0; +} + +.stepper.stepper-mobile .stepper-step:not(:last-child):not(:first-child) .stepper-head { + padding-left: 0.25rem; + padding-right: 0.25rem; +} + +.stepper.stepper-mobile .stepper-head-icon { + font-size: 0; + margin: 0; + height: 0.5rem; + width: 0.5rem; + z-index: 1; +} + +.stepper.stepper-mobile .stepper-head-text { + display: none; +} + +.stepper.stepper-mobile .stepper-content { + top: 2.56rem; +} + +@media (prefers-reduced-motion: reduce) { + .form-control::-webkit-file-upload-button { + -webkit-transition: none; + transition: none; + } + .form-control::file-selector-button { + transition: none; + } + + .form-control::-webkit-file-upload-button { + -webkit-transition: none; + transition: none; + } + + .form-switch .form-check-input { + transition: none; + } + + .form-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } + + .form-range::-moz-range-thumb { + -moz-transition: none; + transition: none; + } + + .form-floating > label { + transition: none; + } + + .fade { + transition: none; + } + + .collapsing { + transition: none; + } + + .collapsing.collapse-horizontal { + transition: none; + } + + .accordion-button::after { + transition: none; + } + + .modal.fade .modal-dialog { + transition: none; + } + + .carousel-item { + transition: none; + } + + .carousel-fade .active.carousel-item-start { + transition: none; + } + + .carousel-fade .active.carousel-item-end { + transition: none; + } + + .carousel-control-prev { + transition: none; + } + + .carousel-control-next { + transition: none; + } + + .carousel-indicators [data-bs-target] { + transition: none; + } + + .spinner-border { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + } + + .spinner-grow { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + } +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + + .navbar-expand-sm .navbar-collapse { + display: flex !important; + -ms-flex-basis: auto; + flex-basis: auto; + } + + .navbar-expand-sm .navbar-toggler { + display: none; + } + + .navbar-expand-sm .offcanvas-header { + display: none; + } + + .navbar-expand-sm .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + + .navbar-expand-sm .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-sm .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-sm .offcanvas-body { + display: flex; + -ms-flex-grow: 0; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + + .modal-dialog { + max-width: 500px; + margin: 1.75rem auto; + } + + .modal-dialog-scrollable { + height: calc(100% - 3.5rem); + } + + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + + .modal-sm { + max-width: 300px; + } + + .sticky-sm-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + + .navbar-expand-md .navbar-collapse { + display: flex !important; + -ms-flex-basis: auto; + flex-basis: auto; + } + + .navbar-expand-md .navbar-toggler { + display: none; + } + + .navbar-expand-md .offcanvas-header { + display: none; + } + + .navbar-expand-md .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + + .navbar-expand-md .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-md .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-md .offcanvas-body { + display: flex; + -ms-flex-grow: 0; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + + .sticky-md-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + + .navbar-expand-lg .navbar-collapse { + display: flex !important; + -ms-flex-basis: auto; + flex-basis: auto; + } + + .navbar-expand-lg .navbar-toggler { + display: none; + } + + .navbar-expand-lg .offcanvas-header { + display: none; + } + + .navbar-expand-lg .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + + .navbar-expand-lg .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-lg .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-lg .offcanvas-body { + display: flex; + -ms-flex-grow: 0; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + + .modal-lg { + max-width: 800px; + } + + .modal-xl { + max-width: 800px; + } + + .sticky-lg-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + + .navbar-expand-xl .navbar-collapse { + display: flex !important; + -ms-flex-basis: auto; + flex-basis: auto; + } + + .navbar-expand-xl .navbar-toggler { + display: none; + } + + .navbar-expand-xl .offcanvas-header { + display: none; + } + + .navbar-expand-xl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + + .navbar-expand-xl .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-xl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-xl .offcanvas-body { + display: flex; + -ms-flex-grow: 0; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + + .modal-xl { + max-width: 1140px; + } + + .sticky-xl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1400px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + -ms-flex-basis: auto; + flex-basis: auto; + } + + .navbar-expand-xxl .navbar-toggler { + display: none; + } + + .navbar-expand-xxl .offcanvas-header { + display: none; + } + + .navbar-expand-xxl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + -ms-flex-grow: 1; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + + .navbar-expand-xxl .offcanvas-top { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-xxl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + + .navbar-expand-xxl .offcanvas-body { + display: flex; + -ms-flex-grow: 0; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + + .sticky-xxl-top { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + + .modal-fullscreen-sm-down .modal-header { + border-radius: 0; + } + + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } + + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + + .modal-fullscreen-md-down .modal-header { + border-radius: 0; + } + + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } + + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + + .modal-fullscreen-lg-down .modal-header { + border-radius: 0; + } + + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } + + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + + .modal-fullscreen-xl-down .modal-header { + border-radius: 0; + } + + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } + + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1399.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + + .modal-fullscreen-xxl-down .modal-header { + border-radius: 0; + } + + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } + + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } +} + +@media (prefers-reduced-motion) { + .animation { + transition: none !important; + -webkit-animation: unset !important; + animation: unset !important; + } +} + +@media screen and (min-width: 320px) and (max-width: 820px) and (orientation: landscape) { + .datepicker-modal-container .datepicker-header { + height: 100%; + } + + .datepicker-modal-container .datepicker-date { + margin-top: 100px; + } + + .datepicker-modal-container .datepicker-day-cell { + width: 32x; + height: 32x; + } + + .datepicker-modal-container { + flex-direction: row; + width: 475px; + height: 360px; + } + + .datepicker-modal-container.datepicker-day-cell { + width: 36px; + height: 36px; + } +} + +@media screen and (min-width: 320px) and (max-width: 825px) and (orientation: landscape) { + .timepicker-elements { + flex-direction: row !important; + border-bottom-left-radius: 0.5rem; + min-width: auto; + min-height: auto; + overflow-y: auto; + } + + .timepicker-head { + border-top-right-radius: 0; + border-bottom-left-radius: 0; + padding: 10px; + padding-right: 10px !important; + height: auto; + min-height: 305px; + } + + .timepicker-head-content { + flex-direction: column; + } + + .timepicker-mode-wrapper { + justify-content: space-around !important; + flex-direction: row !important; + } + + .timepicker-current { + font-size: 3rem; + font-weight: 400; + } + + .timepicker-dot { + font-size: 3rem; + font-weight: 400; + } +} + +@-webkit-keyframes _spinner-grow { + 0% { + transform: scale(0); + } + + 50% { + opacity: 1; + transform: none; + } +} + +@keyframes _spinner-grow { + 0% { + transform: scale(0); + } + + 50% { + opacity: 1; + transform: none; + } +} + +@-webkit-keyframes _fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes _fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@-webkit-keyframes _fade-out { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +@keyframes _fade-out { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +@-webkit-keyframes _fade-in-down { + from { + opacity: 0; + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@keyframes _fade-in-down { + from { + opacity: 0; + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _fade-in-left { + from { + opacity: 0; + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@keyframes _fade-in-left { + from { + opacity: 0; + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _fade-in-right { + from { + opacity: 0; + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@keyframes _fade-in-right { + from { + opacity: 0; + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _fade-in-up { + from { + opacity: 0; + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@keyframes _fade-in-up { + from { + opacity: 0; + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _fade-out-down { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(0, 100%, 0); + } +} + +@keyframes _fade-out-down { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(0, 100%, 0); + } +} + +@-webkit-keyframes _fade-out-left { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes _fade-out-left { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(-100%, 0, 0); + } +} + +@-webkit-keyframes _fade-out-right { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(100%, 0, 0); + } +} + +@keyframes _fade-out-right { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(100%, 0, 0); + } +} + +@-webkit-keyframes _fade-out-up { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(0, -100%, 0); + } +} + +@keyframes _fade-out-up { + from { + opacity: 1; + } + + to { + opacity: 0; + transform: translate3d(0, -100%, 0); + } +} + +@-webkit-keyframes _slide-in-down { + from { + visibility: visible; + transform: translate3d(0, -100%, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@keyframes _slide-in-down { + from { + visibility: visible; + transform: translate3d(0, -100%, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _slide-in-left { + from { + visibility: visible; + transform: translate3d(-100%, 0, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@keyframes _slide-in-left { + from { + visibility: visible; + transform: translate3d(-100%, 0, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _slide-in-right { + from { + visibility: visible; + transform: translate3d(100%, 0, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@keyframes _slide-in-right { + from { + visibility: visible; + transform: translate3d(100%, 0, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _slide-in-up { + from { + visibility: visible; + transform: translate3d(0, 100%, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@keyframes _slide-in-up { + from { + visibility: visible; + transform: translate3d(0, 100%, 0); + } + + to { + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes _slide-out-down { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(0, 100%, 0); + } +} + +@keyframes _slide-out-down { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(0, 100%, 0); + } +} + +@-webkit-keyframes _slide-out-left { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes _slide-out-left { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(-100%, 0, 0); + } +} + +@-webkit-keyframes _slide-out-right { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(100%, 0, 0); + } +} + +@keyframes _slide-out-right { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(100%, 0, 0); + } +} + +@-webkit-keyframes _slide-out-up { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(0, -100%, 0); + } +} + +@keyframes _slide-out-up { + from { + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + transform: translate3d(0, -100%, 0); + } +} + +@-webkit-keyframes _slide-down { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(0, 100%, 0); + } +} + +@keyframes _slide-down { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(0, 100%, 0); + } +} + +@-webkit-keyframes _slide-left { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes _slide-left { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(-100%, 0, 0); + } +} + +@-webkit-keyframes _slide-right { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(100%, 0, 0); + } +} + +@keyframes _slide-right { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(100%, 0, 0); + } +} + +@-webkit-keyframes _slide-up { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(0, -100%, 0); + } +} + +@keyframes _slide-up { + from { + transform: translate3d(0, 0, 0); + } + + to { + transform: translate3d(0, -100%, 0); + } +} + +@-webkit-keyframes _zoom-in { + from { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +@keyframes _zoom-in { + from { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +@-webkit-keyframes _zoom-out { + from { + opacity: 1; + } + + 50% { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +@keyframes _zoom-out { + from { + opacity: 1; + } + + 50% { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +@-webkit-keyframes _tada { + from { + transform: scale3d(1, 1, 1); + } + + 10% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 20% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 50% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 70% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 90% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + 60% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + 80% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + transform: scale3d(1, 1, 1); + } +} + +@keyframes _tada { + from { + transform: scale3d(1, 1, 1); + } + + 10% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 20% { + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 50% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 70% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 90% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + 60% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + 80% { + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + transform: scale3d(1, 1, 1); + } +} + +@-webkit-keyframes _pulse { + from { + transform: scale3d(1, 1, 1); + } + + 50% { + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + transform: scale3d(1, 1, 1); + } +} + +@keyframes _pulse { + from { + transform: scale3d(1, 1, 1); + } + + 50% { + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + transform: scale3d(1, 1, 1); + } +} + +@-webkit-keyframes _show-up-clock { + 0% { + opacity: 0; + transform: scale(0.7); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes _show-up-clock { + 0% { + opacity: 0; + transform: scale(0.7); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.visible { + visibility: visible; +} + +.static { + position: static; +} + +.fixed { + position: fixed; +} + +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.sticky { + position: -webkit-sticky; + position: sticky; +} + +.inset-0 { + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; +} + +.top-0 { + top: 0px; +} + +.right-0 { + right: 0px; +} + +.bottom-0 { + bottom: 0px; +} + +.top-5 { + top: 1.25rem; +} + +.right-5 { + right: 1.25rem; +} + +.z-10 { + z-index: 10; +} + +.m-auto { + margin: auto; +} + +.m-2 { + margin: 0.5rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.my-auto { + margin-top: auto; + margin-bottom: auto; +} + +.my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + +.my-4 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.mx-1 { + margin-left: 0.25rem; + margin-right: 0.25rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + +.mr-4 { + margin-right: 1rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.ml-auto { + margin-left: auto; +} + +.mt-0 { + margin-top: 0px; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mb-10 { + margin-bottom: 2.5rem; +} + +.mt-10 { + margin-top: 2.5rem; +} + +.mt-8 { + margin-top: 2rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.ml-5 { + margin-left: 1.25rem; +} + +.ml-6 { + margin-left: 1.5rem; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.inline-flex { + display: inline-flex; +} + +.table { + display: table; +} + +.hidden { + display: none; +} + +.h-full { + height: 100%; +} + +.h-7 { + height: 1.75rem; +} + +.h-fit { + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; +} + +.h-10 { + height: 2.5rem; +} + +.h-12 { + height: 3rem; +} + +.h-6 { + height: 1.5rem; +} + +.h-14 { + height: 3.5rem; +} + +.h-4 { + height: 1rem; +} + +.h-40 { + height: 10rem; +} + +.h-\[70vh\] { + height: 70vh; +} + +.h-\[50vh\] { + height: 50vh; +} + +.h-8 { + height: 2rem; +} + +.h-5 { + height: 1.25rem; +} + +.h-screen { + height: 100vh; +} + +.h-16 { + height: 4rem; +} + +.max-h-\[70vh\] { + max-height: 70vh; +} + +.max-h-\[80vh\] { + max-height: 80vh; +} + +.max-h-60 { + max-height: 15rem; +} + +.min-h-\[60vh\] { + min-height: 60vh; +} + +.min-h-screen { + min-height: 100vh; +} + +.w-full { + width: 100%; +} + +.w-7 { + width: 1.75rem; +} + +.w-11\/12 { + width: 91.666667%; +} + +.w-10 { + width: 2.5rem; +} + +.w-12 { + width: 3rem; +} + +.w-32 { + width: 8rem; +} + +.w-6 { + width: 1.5rem; +} + +.w-14 { + width: 3.5rem; +} + +.w-4 { + width: 1rem; +} + +.w-8 { + width: 2rem; +} + +.w-5 { + width: 1.25rem; +} + +.w-16 { + width: 4rem; +} + +.min-w-full { + min-width: 100%; +} + +.max-w-lg { + max-width: 32rem; +} + +.max-w-xs { + max-width: 20rem; +} + +.max-w-sm { + max-width: 24rem; +} + +.flex-1 { + flex: 1 1 0%; +} + +.flex-auto { + flex: 1 1 auto; +} + +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.cursor-pointer { + cursor: pointer; +} + +.resize { + resize: both; +} + +.list-none { + list-style-type: none; +} + +.appearance-none { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.flex-row { + flex-direction: row; +} + +.flex-col { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.content-center { + align-content: center; +} + +.items-end { + align-items: flex-end; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.justify-evenly { + justify-content: space-evenly; +} + +.gap-2 { + gap: 0.5rem; +} + +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} + +.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); +} + +.overflow-hidden { + overflow: hidden; +} + +.overflow-x-auto { + overflow-x: auto; +} + +.overflow-y-auto { + overflow-y: auto; +} + +.overflow-x-hidden { + overflow-x: hidden; +} + +.overflow-y-scroll { + overflow-y: scroll; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.whitespace-nowrap { + white-space: nowrap; +} + +.whitespace-pre-line { + white-space: pre-line; +} + +.rounded-full { + border-radius: 9999px; +} + +.rounded { + border-radius: 0.25rem; +} + +.rounded-xl { + border-radius: 0.75rem; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-md { + border-radius: 0.375rem; +} + +.rounded-t-lg { + border-top-left-radius: 0.5rem; + border-top-right-radius: 0.5rem; +} + +.border-2 { + border-width: 2px; +} + +.border { + border-width: 1px; +} + +.border-b-2 { + border-bottom-width: 2px; +} + +.border-b { + border-bottom-width: 1px; +} + +.border-t { + border-top-width: 1px; +} + +.border-gray-200 { + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); +} + +.border-white { + --tw-border-opacity: 1; + border-color: rgb(255 255 255 / var(--tw-border-opacity)); +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(239 68 68 / var(--tw-border-opacity)); +} + +.bg-blue-500 { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} + +.bg-blue-900 { + --tw-bg-opacity: 1; + background-color: rgb(30 58 138 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-blue-400 { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); +} + +.bg-transparent { + background-color: transparent; +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.bg-green-500 { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); +} + +.bg-gray-400 { + --tw-bg-opacity: 1; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)); +} + +.bg-gray-300 { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); +} + +.bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.bg-slate-100 { + --tw-bg-opacity: 1; + background-color: rgb(241 245 249 / var(--tw-bg-opacity)); +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.bg-red-600 { + --tw-bg-opacity: 1; + background-color: rgb(220 38 38 / var(--tw-bg-opacity)); +} + +.bg-slate-200 { + --tw-bg-opacity: 1; + background-color: rgb(226 232 240 / var(--tw-bg-opacity)); +} + +.bg-gray-800 { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); +} + +.object-cover { + -o-object-fit: cover; + object-fit: cover; +} + +.p-4 { + padding: 1rem; +} + +.p-2 { + padding: 0.5rem; +} + +.p-2\.5 { + padding: 0.625rem; +} + +.p-1\.5 { + padding: 0.375rem; +} + +.p-1 { + padding: 0.25rem; +} + +.p-5 { + padding: 1.25rem; +} + +.p-6 { + padding: 1.5rem; +} + +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} + +.py-2\.5 { + padding-top: 0.625rem; + padding-bottom: 0.625rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.py-5 { + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.px-8 { + padding-left: 2rem; + padding-right: 2rem; +} + +.px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; +} + +.pt-4 { + padding-top: 1rem; +} + +.pr-6 { + padding-right: 1.5rem; +} + +.pb-6 { + padding-bottom: 1.5rem; +} + +.pl-4 { + padding-left: 1rem; +} + +.pb-10 { + padding-bottom: 2.5rem; +} + +.pr-0 { + padding-right: 0px; +} + +.pr-2 { + padding-right: 0.5rem; +} + +.pl-2 { + padding-left: 0.5rem; +} + +.pt-6 { + padding-top: 1.5rem; +} + +.pb-8 { + padding-bottom: 2rem; +} + +.text-left { + text-align: left; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.align-baseline { + vertical-align: baseline; +} + +.align-text-bottom { + vertical-align: text-bottom; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.text-7xl { + font-size: 4.5rem; + line-height: 1; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-base { + font-size: 1rem; + line-height: 1.5rem; +} + +.font-bold { + font-weight: 700; +} + +.font-medium { + font-weight: 500; +} + +.font-normal { + font-weight: 400; +} + +.uppercase { + text-transform: uppercase; +} + +.italic { + font-style: italic; +} + +.leading-6 { + line-height: 1.5rem; +} + +.leading-tight { + line-height: 1.25; +} + +.tracking-wider { + letter-spacing: 0.05em; +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.text-gray-800 { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-slate-500 { + --tw-text-opacity: 1; + color: rgb(100 116 139 / var(--tw-text-opacity)); +} + +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.text-red-500 { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); +} + +.text-blue-500 { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity)); +} + +.text-red-400 { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); +} + +.opacity-40 { + opacity: 0.4; +} + +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-lg { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-inner { + --tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.outline-none { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.outline { + outline-style: solid; +} + +.ring-blue-600 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(37 99 235 / var(--tw-ring-opacity)); +} + +.ring-indigo-600 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity)); +} + +.ring-offset-2 { + --tw-ring-offset-width: 2px; +} + +.blur { + --tw-blur: blur(8px); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.filter { + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + +.transition-transform { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.transition { + transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300 { + transition-duration: 300ms; +} + +.duration-150 { + transition-duration: 150ms; +} + +.ease-in-out { + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +@media screen and (max-width: 767px) { + .sidebar-holder { + width: 100%; + min-width: 200px; + max-width: 200px; + position: fixed; + top: 0; + left: 0; + } + + .page-header span { + margin-left: auto; + } +} + +.hover\:scale-105:hover { + --tw-scale-x: 1.05; + --tw-scale-y: 1.05; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.hover\:bg-green-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} + +.hover\:bg-red-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(185 28 28 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.hover\:text-gray-800:hover { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} + +.hover\:text-gray-900:hover { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.hover\:text-blue-800:hover { + --tw-text-opacity: 1; + color: rgb(30 64 175 / var(--tw-text-opacity)); +} + +.hover\:shadow-lg:hover { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.focus\:bg-blue-700:focus { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.focus\:bg-green-600:focus { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} + +.focus\:bg-red-700:focus { + --tw-bg-opacity: 1; + background-color: rgb(185 28 28 / var(--tw-bg-opacity)); +} + +.focus\:bg-gray-900:focus { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.focus\:shadow-lg:focus { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-0:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-gray-300:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); +} + +.active\:bg-blue-800:active { + --tw-bg-opacity: 1; + background-color: rgb(30 64 175 / var(--tw-bg-opacity)); +} + +.active\:bg-green-700:active { + --tw-bg-opacity: 1; + background-color: rgb(21 128 61 / var(--tw-bg-opacity)); +} + +.active\:bg-red-800:active { + --tw-bg-opacity: 1; + background-color: rgb(153 27 27 / var(--tw-bg-opacity)); +} + +.active\:bg-gray-900:active { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.active\:shadow-lg:active { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.disabled\:cursor-not-allowed:disabled { + cursor: not-allowed; +} + +@media (prefers-color-scheme: dark) { + .dark\:text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); + } + + .dark\:text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); + } + + .dark\:hover\:bg-gray-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); + } + + .dark\:hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } +} + +@media (min-width: 640px) { + .sm\:ml-4 { + margin-left: 1rem; + } + + .sm\:flex { + display: flex; + } + + .sm\:w-1\/2 { + width: 50%; + } + + .sm\:px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + .sm\:text-left { + text-align: left; + } +} + +@media (min-width: 768px) { + .md\:h-52 { + height: 13rem; + } + + .md\:w-1\/2 { + width: 50%; + } +} + +@media (min-width: 1024px) { + .lg\:block { + display: block; + } + + .lg\:flex { + display: flex; + } + + .lg\:hidden { + display: none; + } + + .lg\:h-80 { + height: 20rem; + } + + .lg\:max-h-\[60vh\] { + max-height: 60vh; + } + + .lg\:w-1\/3 { + width: 33.333333%; + } + + .lg\:w-1\/2 { + width: 50%; + } + + .lg\:px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } +} + +@media (min-width: 1280px) { + .xl\:w-1\/4 { + width: 25%; + } + + .xl\:w-1\/2 { + width: 50%; + } +} diff --git a/src/pages/404/NotFoundPage.jsx b/src/pages/404/NotFoundPage.jsx new file mode 100644 index 0000000..7473bde --- /dev/null +++ b/src/pages/404/NotFoundPage.jsx @@ -0,0 +1,27 @@ +import Loader from "Components/Loader"; +import React from "react"; + +const NotFoundPage = () => { + const [loading, setLoading] = React.useState(true); + + React.useEffect(() => { + const interval = setTimeout(() => { + setLoading(false); + }, 5000); + // return () => clearInterval(interval); + }, []); + + return ( + <> + {loading ? ( + + ) : ( +
+ Not Found +
+ )} + + ); +}; + +export default NotFoundPage; diff --git a/src/pages/404/index.js b/src/pages/404/index.js new file mode 100644 index 0000000..3cb343e --- /dev/null +++ b/src/pages/404/index.js @@ -0,0 +1 @@ +export { default as NotFoundPage } from './NotFoundPage' \ No newline at end of file diff --git a/src/pages/admin/Add/AddAdminAccessoriesPage.jsx b/src/pages/admin/Add/AddAdminAccessoriesPage.jsx new file mode 100644 index 0000000..8fd9c45 --- /dev/null +++ b/src/pages/admin/Add/AddAdminAccessoriesPage.jsx @@ -0,0 +1,248 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "Utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; + +const AddAdminAccessoriesPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + name: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + thumbnail: yup.string().required(), + top_view: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(AuthContext); + const [fileObj, setFileObj] = React.useState({}); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + + sdk.setTable("accessories"); + + const result = await sdk.callRestAPI( + { + name: data.name, + length: data.length, + width: data.width, + thumbnail: data.thumbnail, + top_view: data.top_view, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/accessories"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("name", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "accessories", + }, + }); + }, []); + + return ( +
+

Add Accessories

+
+
+ + +

{errors.name?.message}

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

{errors.width?.message}

+
+ +
+ + {fileObj["thumbnail"] ? ( + isImage(fileObj["thumbnail"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("thumbnail", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.thumbnail?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.thumbnail?.message} +

+
+ +
+ + {fileObj["top_view"] ? ( + isImage(fileObj["top_view"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("top_view", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.top_view?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.top_view?.message} +

+
+ + +
+
+ ); +}; + +export default AddAdminAccessoriesPage; diff --git a/src/pages/admin/Add/AddAdminAnalyticLogPage.jsx b/src/pages/admin/Add/AddAdminAnalyticLogPage.jsx new file mode 100644 index 0000000..094cbe0 --- /dev/null +++ b/src/pages/admin/Add/AddAdminAnalyticLogPage.jsx @@ -0,0 +1,269 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "Utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminAnalyticLogPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + user_id: yup.number().required().positive().integer(), + url: yup.string().required(), + path: yup.string().required(), + hostname: yup.string().required(), + ip: yup.string().required(), + role: yup.string().required(), + browser: yup.string().required(), + country: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + + try { + for (let item in fileObj) { + let uploadResult = await sdk.upload(fileObj[item].file); + data[item] = uploadResult.url; + } + + sdk.setTable("analytic_log"); + + const result = await sdk.callRestAPI( + { + user_id: data.user_id, + url: data.url, + path: data.path, + hostname: data.hostname, + ip: data.ip, + role: data.role, + browser: data.browser, + country: data.country, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/analytic_log"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("user_id", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "analytic_log", + }, + }); + }, []); + + return ( +
+

Add AnalyticLog

+
+
+ + +

+ {errors.user_id?.message} +

+
+ +
+ + +

{errors.url?.message}

+
+ +
+ + +

{errors.path?.message}

+
+ +
+ + +

+ {errors.hostname?.message} +

+
+ +
+ + +

{errors.ip?.message}

+
+ +
+ + +

{errors.role?.message}

+
+ +
+ + +

+ {errors.browser?.message} +

+
+ +
+ + +

+ {errors.country?.message} +

+
+ + +
+
+ ); +}; + +export default AddAdminAnalyticLogPage; diff --git a/src/pages/admin/Add/AddAdminBoatLiftsPage.jsx b/src/pages/admin/Add/AddAdminBoatLiftsPage.jsx new file mode 100644 index 0000000..ee38c52 --- /dev/null +++ b/src/pages/admin/Add/AddAdminBoatLiftsPage.jsx @@ -0,0 +1,318 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +import { BoatLiftRange } from "Utils/constants"; + +const AddAdminBoatLiftsPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + model: yup.string().required(), + weight_capacity: yup.number().required(), + lift_range: yup.number().required().positive().integer(), + no_of_cylinders: yup.number().required().positive().integer(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + + sdk.setTable("boat_lifts"); + + const result = await sdk.callRestAPI( + { + model: data.model, + weight_capacity: data.weight_capacity, + lift_range: data.lift_range, + no_of_cylinders: data.no_of_cylinders, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/boat_lifts"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("model", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "boat_lifts", + }, + }); + }, []); + + return ( +
+

Add BoatLifts

+
+
+ + +

{errors.model?.message}

+
+ +
+ + +

+ {errors.weight_capacity?.message} +

+
+ +
+ + +

+ {errors.lift_range?.message} +

+
+ +
+ + +

+ {errors.no_of_cylinders?.message} +

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

{errors.width?.message}

+
+ +
+ + {fileObj["image"] ? ( + isImage(fileObj["image"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("image", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.image?.message ? "border-red-500" : "" + }`} + /> +

{errors.image?.message}

+
+ +
+ + {fileObj["top_view"] ? ( + isImage(fileObj["top_view"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("top_view", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.top_view?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.top_view?.message} +

+
+ + +
+
+ ); +}; + +export default AddAdminBoatLiftsPage; diff --git a/src/pages/admin/Add/AddAdminCmsPage.jsx b/src/pages/admin/Add/AddAdminCmsPage.jsx new file mode 100644 index 0000000..7430349 --- /dev/null +++ b/src/pages/admin/Add/AddAdminCmsPage.jsx @@ -0,0 +1,158 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import DynamicContentType from "Components/DynamicContentType"; + +const AddAdminCmsPage = () => { + const schema = yup + .object({ + page: yup.string().required(), + key: yup.string().required(), + type: yup.string().required(), + value: yup.string(), + }) + .required(); + + const selectType = [ + { key: "text", value: "Text" }, + { key: "image", value: "Image" }, + { key: "number", value: "Number" }, + { key: "kvp", value: "Key-Value Pair" }, + { key: "image-list", value: "Image List" }, + { key: "captioned-image-list", value: "Captioned Image List" }, + { key: "team-list", value: "Team List" }, + ]; + + const { dispatch } = React.useContext(GlobalContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [contentType, setContentType] = React.useState(selectType[0]?.key); + const [contentValue, setContentValue] = React.useState(''); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + console.log(data); + try { + sdk.setTable("cms"); + + const result = await sdk.cmsAdd( + data.page, + data.key, + data.type, + contentValue + ); + if (!result.error) { + navigate("/admin/cms"); + showToast(globalDispatch, "Added"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("page", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "cms", + }, + }); + }, []); + + return ( +
+

Add CMS Content

+
+
+ + +
+
+ + +

{errors.key?.message}

+
+
+ + +
+ + + + +
+ ); +}; + +export default AddAdminCmsPage; + diff --git a/src/pages/admin/Add/AddAdminDealersPage.jsx b/src/pages/admin/Add/AddAdminDealersPage.jsx new file mode 100644 index 0000000..284a527 --- /dev/null +++ b/src/pages/admin/Add/AddAdminDealersPage.jsx @@ -0,0 +1,150 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +const AddAdminDealersPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + name: yup.string().required(), + address: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + + sdk.setTable( "dealers" ); + + const result = await sdk.callRestAPI( + { + + name: data.name, + address: data.address, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/dealers" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "name", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "dealers", + }, + } ); + }, [] ); + + return ( +
+

Add Dealers

+
+ + +
+ + +

+ { errors.name?.message } +

+
+ + +
+ + +

+ { errors.address?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminDealersPage; diff --git a/src/pages/admin/Add/AddAdminDocksPage.jsx b/src/pages/admin/Add/AddAdminDocksPage.jsx new file mode 100644 index 0000000..a63d030 --- /dev/null +++ b/src/pages/admin/Add/AddAdminDocksPage.jsx @@ -0,0 +1,266 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminDocksPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + category: yup.string().required(), + materials: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + + sdk.setTable( "docks" ); + + const result = await sdk.callRestAPI( + { + + category: data.category, + materials: data.materials, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/docks" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "category", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "docks", + }, + } ); + }, [] ); + + return ( +
+

Add Docks

+
+ + +
+ + +

+ { errors.category?.message } +

+
+ + +
+ + +

+ { errors.materials?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : ( + <> + ) } + + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+ + { fileObj[ "top_view" ] ? ( + isImage( fileObj[ "top_view" ] ) ? ( + ) : ( + <> + ) + ) : ( + <> + ) } + + previewImage( "top_view", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.top_view?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.top_view?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminDocksPage; diff --git a/src/pages/admin/Add/AddAdminEmailPage.jsx b/src/pages/admin/Add/AddAdminEmailPage.jsx new file mode 100644 index 0000000..30a8b50 --- /dev/null +++ b/src/pages/admin/Add/AddAdminEmailPage.jsx @@ -0,0 +1,162 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +const AddAdminEmailPage = () => { + const schema = yup + .object( { + slug: yup.string().required(), + subject: yup.string().required(), + html: yup.string().required(), + tag: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + sdk.setTable( "email" ); + + const result = await sdk.callRestAPI( + { + slug: data.slug, + subject: data.subject, + html: data.html, + tag: data.tag, + }, + "POST" + ); + if ( !result.error ) { + navigate( "/admin/email" ); + showToast( globalDispatch, "Added" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "subject", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "email", + }, + } ); + }, [] ); + + return ( +
+

Add Email

+
+
+ + +
+
+ + +

+ { errors.subject?.message } +

+
+
+ + +

{ errors.tag?.message }

+
+
+ + +

{ errors.html?.message }

+
+ +
+
+ ); +}; + +export default AddAdminEmailPage; diff --git a/src/pages/admin/Add/AddAdminInstructionsPage.jsx b/src/pages/admin/Add/AddAdminInstructionsPage.jsx new file mode 100644 index 0000000..c0227e0 --- /dev/null +++ b/src/pages/admin/Add/AddAdminInstructionsPage.jsx @@ -0,0 +1,131 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminInstructionsPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + content: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + + sdk.setTable( "instructions" ); + + const result = await sdk.callRestAPI( + { + + content: data.content, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/instructions" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "content", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "instructions", + }, + } ); + }, [] ); + + return ( +
+

Add Instructions

+
+ + +
+ + +

+ { errors.content?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminInstructionsPage; diff --git a/src/pages/admin/Add/AddAdminPhotoPage.jsx b/src/pages/admin/Add/AddAdminPhotoPage.jsx new file mode 100644 index 0000000..8c8c29a --- /dev/null +++ b/src/pages/admin/Add/AddAdminPhotoPage.jsx @@ -0,0 +1,74 @@ +import React, { useState } from "react"; +import Uppy from "@uppy/core"; +import XHRUpload from "@uppy/xhr-upload"; +import { Dashboard, useUppy } from "@uppy/react"; +import "@uppy/core/dist/style.css"; +import "@uppy/drag-drop/dist/style.css"; + +import { useNavigate } from "react-router"; +// import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const AddAdminPhotoPage = () => { + const { dispatch } = React.useContext( GlobalContext ); + const navigate = useNavigate(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const uppy = useUppy( () => { + let model = new Uppy(); + model.use( XHRUpload, { + id: "XHRUpload", + method: "post", + formData: true, + limit: 0, + fieldName: "file", + metaFields: [ "caption", "size" ], + headers: sdk.getHeader(), + endpoint: sdk.uploadUrl(), + } ); + + model.on( "file-added", ( file ) => { + model.setFileMeta( file.id, { + size: file.size, + caption: "", + } ); + } ); + + model.on( "upload-success", async ( file, response ) => { + const httpStatus = response.status; // HTTP status code + const responseBody = response.body; + console.log( "response", response ); + showToast( globalDispatch, "Uploaded" ); + navigate( "/admin/photos" ); + } ); + + model.on( "upload-error", ( file, error, response ) => { + const httpStatus = response.status; // HTTP status code + if ( httpStatus == 401 ) { + tokenExpireError( dispatch, "TOKEN_EXPIRED" ); + } + } ); + return model; + } ); + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "photos", + }, + } ); + }, [] ); + + return ( +
+

Add Photo

+ +
+ ); +}; + +export default AddAdminPhotoPage; diff --git a/src/pages/admin/Add/AddAdminQuotesMailRecipientsPage.jsx b/src/pages/admin/Add/AddAdminQuotesMailRecipientsPage.jsx new file mode 100644 index 0000000..7d458b7 --- /dev/null +++ b/src/pages/admin/Add/AddAdminQuotesMailRecipientsPage.jsx @@ -0,0 +1,132 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { isImage } from "Utils/utils"; + +const AddAdminQuotesMailRecipientsPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + + email: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + + try { + for (let item in fileObj) { + let formData = new FormData(); + formData.append('file', fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + + sdk.setTable("quotes_mail_recipients"); + + const result = await sdk.callRestAPI( + { + + email: data.email, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/quotes_mail_recipients"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "quotes_mail_recipients", + }, + }); + }, []); + + return ( +
+

Add Quotes Mail Recipients

+
+ + +
+ + +

+ {errors.email?.message} +

+
+ + +
+
+ ); +}; + +export default AddAdminQuotesMailRecipientsPage; diff --git a/src/pages/admin/Add/AddAdminQuotesPage.jsx b/src/pages/admin/Add/AddAdminQuotesPage.jsx new file mode 100644 index 0000000..41455f7 --- /dev/null +++ b/src/pages/admin/Add/AddAdminQuotesPage.jsx @@ -0,0 +1,440 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminQuotesPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + first_name: yup.string().required(), + last_name: yup.string().required(), + email: yup.string().required(), + phone: yup.string().required(), + lake: yup.string().required(), + city: yup.string().required(), + has_dealer: yup.string().required(), + dealer_id: yup.string().required(), + dock_connection: yup.string().required(), + lake_bottom: yup.string().required(), + will_dock_boat: yup.string().required(), + comments: yup.string().required(), + dock_image: yup.string().required(), + selected_items: yup.string().required(), + country: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + + sdk.setTable( "quotes" ); + + const result = await sdk.callRestAPI( + { + + first_name: data.first_name, + last_name: data.last_name, + email: data.email, + phone: data.phone, + lake: data.lake, + city: data.city, + has_dealer: data.has_dealer, + dealer_id: data.dealer_id, + dock_connection: data.dock_connection, + lake_bottom: data.lake_bottom, + will_dock_boat: data.will_dock_boat, + comments: data.comments, + dock_image: data.dock_image, + selected_items: data.selected_items, + country: data.country, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/quotes" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "first_name", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "quotes", + }, + } ); + }, [] ); + + return ( +
+

Add Quotes

+
+ + +
+ + +

+ { errors.first_name?.message } +

+
+ + +
+ + +

+ { errors.last_name?.message } +

+
+ + +
+ + +

+ { errors.email?.message } +

+
+ + +
+ + +

+ { errors.phone?.message } +

+
+ + +
+ + +

+ { errors.lake?.message } +

+
+ + +
+ + +

+ { errors.city?.message } +

+
+ + +
+ + +

+ { errors.has_dealer?.message } +

+
+ + +
+ + +

+ { errors.dealer_id?.message } +

+
+ + +
+ + +

+ { errors.dock_connection?.message } +

+
+ + +
+ + +

+ { errors.lake_bottom?.message } +

+
+ + +
+ + +

+ { errors.will_dock_boat?.message } +

+
+ + +
+ + +

+ { errors.comments?.message } +

+
+ + +
+ + +

+ { errors.dock_image?.message } +

+
+ + +
+ + +

+ { errors.selected_items?.message } +

+
+ + +
+ + +

+ { errors.country?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminQuotesPage; diff --git a/src/pages/admin/Add/AddAdminRampsPage.jsx b/src/pages/admin/Add/AddAdminRampsPage.jsx new file mode 100644 index 0000000..e6575b6 --- /dev/null +++ b/src/pages/admin/Add/AddAdminRampsPage.jsx @@ -0,0 +1,275 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddRampsPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const schema = yup + .object({ + category: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + material: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + sdk.setTable("ramps"); + + const result = await sdk.callRestAPI( + { + category: data.category, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + material: data.material, + }, + "POST" + ); + if (!result.error) { + showToast(globalDispatch, "Added"); + navigate("/admin/ramps"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("category", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "ramps", + }, + }); + }, []); + + return ( +
+

Add Ramps

+
+
+ + +

+ {errors.category?.message} +

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

{errors.width?.message}

+
+ +
+ + {fileObj["image"] ? ( + isImage(fileObj["image"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("image", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.image?.message ? "border-red-500" : "" + }`} + /> +

{errors.image?.message}

+
+ +
+ + {fileObj["top_view"] ? ( + isImage(fileObj["top_view"]) ? ( + + ) : ( + <> + ) + ) : ( + <> + )} + + previewImage("top_view", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.top_view?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.top_view?.message} +

+
+ +
+ + +

+ {errors.material?.message} +

+
+ + +
+
+ ); +}; + +export default AddRampsPage; diff --git a/src/pages/admin/Add/AddAdminReferenceItemsPage.jsx b/src/pages/admin/Add/AddAdminReferenceItemsPage.jsx new file mode 100644 index 0000000..d4d19db --- /dev/null +++ b/src/pages/admin/Add/AddAdminReferenceItemsPage.jsx @@ -0,0 +1,202 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "../authContext"; +import { GlobalContext, showToast } from "../globalContext"; +import { isImage } from "Utils/utils"; + +const AddAdminReferenceItemsPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + name: yup.string().required(), + length: yup.string(), + width: yup.string(), + image: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + + sdk.setTable( "reference_items" ); + + const result = await sdk.callRestAPI( + { + + name: data.name, + length: data.length, + width: data.width, + image: data.image, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/reference_items" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "name", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "reference_items", + }, + } ); + }, [] ); + + return ( +
+

Add ReferenceItems

+
+ + +
+ + +

+ { errors.name?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : ( + <> + ) } + + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminReferenceItemsPage; diff --git a/src/pages/admin/Add/AddAdminUserPage.jsx b/src/pages/admin/Add/AddAdminUserPage.jsx new file mode 100644 index 0000000..df8e407 --- /dev/null +++ b/src/pages/admin/Add/AddAdminUserPage.jsx @@ -0,0 +1,151 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminUserPage = () => { + const schema = yup + .object( { + email: yup.string().email().required(), + password: yup.string().required(), + role: yup.string(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + // const selectRole = [ + // { name: "role", value: "admin" }, + // { name: "role", value: "employee" }, + // ]; + + /** + * + * + * Use /user/put to update user remaining info after registration success + * use /profile/put to update profile info + */ + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + const result = await sdk.createUser( data.email, data.password, 'admin' ); + if ( !result.error ) { + showToast( dispatch, "Added" ); + navigate( "/admin/user" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "email", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "users", + }, + } ); + }, [] ); + return ( +
+

Add User

+
+
+ + +

{ errors.email?.message }

+
+ {/*
+ + +
*/} +
+ + +

{ errors.password?.message }

+
+ +
+
+ ); +}; + +export default AddAdminUserPage; diff --git a/src/pages/admin/Add/AddAdminWedgesPage.jsx b/src/pages/admin/Add/AddAdminWedgesPage.jsx new file mode 100644 index 0000000..ee16822 --- /dev/null +++ b/src/pages/admin/Add/AddAdminWedgesPage.jsx @@ -0,0 +1,265 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import MkdSDK from "../utils/MkdSDK"; +import { useNavigate } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +const AddAdminWedgesPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const schema = yup + .object( { + + category: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + material: yup.string().required(), + } ) + .required(); + + const { dispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + const onSubmit = async ( data ) => { + let sdk = new MkdSDK(); + + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + sdk.setTable( "wedges" ); + + const result = await sdk.callRestAPI( + { + + category: data.category, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + material: data.material, + }, + "POST" + ); + if ( !result.error ) { + showToast( globalDispatch, "Added" ); + navigate( "/admin/wedges" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "category", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "wedges", + }, + } ); + }, [] ); + + return ( +
+

Add Wedges

+
+ + +
+ + +

+ { errors.category?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : ( + <> + ) } + + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+ + { fileObj[ "top_view" ] ? ( + isImage( fileObj[ "top_view" ] ) ? ( + ) : ( + <> + ) + ) : ( + <> + ) } + + previewImage( "top_view", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.top_view?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.top_view?.message } +

+
+ + +
+ + +

+ { errors.material?.message } +

+
+ + +
+
+ ); +}; + +export default AddAdminWedgesPage; diff --git a/src/pages/admin/Add/pg.js b/src/pages/admin/Add/pg.js new file mode 100644 index 0000000..6416cf3 --- /dev/null +++ b/src/pages/admin/Add/pg.js @@ -0,0 +1,96 @@ +const fs = require("fs"); +const path = require("path"); + +// Define the path to the directory where your files are located +const directoryPath = path.join(__dirname); +// console.log( __dirname ) +// Read the contents of the directory +fs.readdir(directoryPath, (err, files) => { + if (err) { + console.error(`Error reading directory: ${err}`); + return; + } + + // Filter the list of files to only include files with the ".jsx" extension + const jsxFiles = files.filter((file) => path.extname(file) === ".jsx"); + console.log(jsxFiles.length); + // Read the contents of each file + jsxFiles.forEach((file, i) => { + // console.log( `import {${ path.basename( file, ".jsx" ) }Template} from './pages/ecomAdmin/${ path.basename( file, '.jsx' ) }'` ) + fs.readFile(path.join(directoryPath, file), "utf-8", (err, contents) => { + // console.log( i ) + if (err) { + console.error(`Error reading file ${file}: ${err}`); + return; + } + + // if ( file.includes( "AdminEcomApiKeyListPage" ) ) { + // const search = `export default ${ path.basename( file, ".jsx" ) };` + // let newData = JSON.stringify( contents ) + // newData.replace( search, `${ search }\`` ) + // console.log( newData ) + // fs.writeFile( path.join( directoryPath, "test" ), newData, "utf-8", err => { + // if ( err ) throw err; + // console.log( `File ${ file } has been modified and saved.` ); + // } ); + + // console.log( newData.match( search ) ) + // } + // "../utils/MkdSDK"; + // "../authContext"; + // "../globalContext"; + //'react-quill'; + // "../utils/utils"; + // "../components/AddButton" + // "../components/ExportButton" + // "../components/PaginationBar"; + + let newData = contents; + // newData = newData.replace("../utils/MkdSDK", "Utils/MkdSDK"); + // newData = newData.replace("../authContext", "Src/authContext"); + // newData = newData.replace("../globalContext", "Src/globalContext"); + // newData = newData.replace("../utils/utils", "Utils/utils"); + newData = newData.replace( + "../../components/AddButton", + "Components/AddButton" + ); + newData = newData.replace( + "../../components/ExportButton", + "Components/ExportButton" + ); + newData = newData.replace( + "../../components/PaginationBar", + "Components/PaginationBar" + ); + newData = newData.replace( + "../components/AddButton", + "Components/AddButton" + ); + newData = newData.replace( + "../components/ExportButton", + "Components/ExportButton" + ); + newData = newData.replace( + "../components/PaginationBar", + "Components/PaginationBar" + ); + newData = newData.replace( + "../../components/DynamicContentType", + "Components/DynamicContentType" + ); + newData = newData.replace("../../globalContext", "Src/globalContext"); + newData = newData.replace("../Src/globalContext", "Src/globalContext"); + newData = newData.replace("../Src/authContext", "Src/authContext"); + newData = newData.replace("../../authContext", "Src/authContext"); + newData = newData.replace("../../utils/MkdSDK", "Utils/MkdSDK"); + newData = newData.replace("../../utils/utils", "Utils/utils"); + // save the new content to the same file + fs.writeFile(path.join(directoryPath, file), newData, "utf-8", (err) => { + if (err) throw err; + console.log(`File ${file} has been modified and saved.`); + }); + + console.log(`Contents of file ${file}:`); + }); + }); +}); diff --git a/src/pages/admin/AdminDashboardPage.jsx b/src/pages/admin/AdminDashboardPage.jsx new file mode 100644 index 0000000..56be8b3 --- /dev/null +++ b/src/pages/admin/AdminDashboardPage.jsx @@ -0,0 +1,82 @@ +import React from "react"; +import { AuthContext } from "../../authContext"; +import { GlobalContext } from "../../globalContext"; +import { + boat_lifts, + dealers, + wedges, + docks, + accessories, + ramps +} from "../../data"; +import MkdSDK from "Utils/MkdSDK"; + +const allData = [ + // { + // table: "dealers", + // data: dealers.model + // }, + { + table: "wedges", + data: wedges.model + }, + { + table: "docks", + data: docks.model + }, + { + table: "accessories", + data: accessories.model + }, + { + table: "ramps", + data: ramps.model + }, + { + table: "boat_lifts", + data: boat_lifts.model + } +]; + +const AdminDashboardPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const seedData = async () => { + const sdk = new MkdSDK(); + const promise = allData?.map(async (item) => { + sdk.setTable(item.table); + + const promise = item.data?.map(async (data) => + sdk.callRestAPI(data, "POST") + ); + return Promise.all(promise); + }); + await Promise.all(promise); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "admin" + } + }); + }, []); + return ( + <> +
+ Dashboard{" "} + {/* */} +
+ + ); +}; + +export default AdminDashboardPage; diff --git a/src/pages/admin/Auth/AdminForgotPage.jsx b/src/pages/admin/Auth/AdminForgotPage.jsx new file mode 100644 index 0000000..6b9020b --- /dev/null +++ b/src/pages/admin/Auth/AdminForgotPage.jsx @@ -0,0 +1,107 @@ +import React from "react"; +import { Link } from "react-router-dom"; + +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; + +const AdminForgotPage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + }) + .required(); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const { dispatch } = React.useContext(GlobalContext); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.forgot(data.email); + + if (!result.error) { + showToast(dispatch, "Reset Code Sent"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + } + }; + + return ( + <> +
+
+
+ + +

+ {errors.email?.message} +

+
+ +
+ + + Login? + +
+
+

+ © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

+
+ + ); +}; + +export default AdminForgotPage; diff --git a/src/pages/admin/Auth/AdminLoginPage.jsx b/src/pages/admin/Auth/AdminLoginPage.jsx new file mode 100644 index 0000000..1e7396a --- /dev/null +++ b/src/pages/admin/Auth/AdminLoginPage.jsx @@ -0,0 +1,126 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AuthContext } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +const AdminLoginPage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + password: yup.string().required(), + }) + .required(); + + const { dispatch } = React.useContext(AuthContext); + const navigate = useNavigate(); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.login(data.email, data.password, "admin"); + if (!result.error) { + dispatch({ + type: "LOGIN", + payload: result, + }); + navigate("/admin/dashboard"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + } + }; + + return ( +
+
+
+ + +

{errors.email?.message}

+
+ +
+ + +

+ {errors.password?.message} +

+
+
+ + + Forgot Password? + +
+
+

+ © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

+
+ ); +}; + +export default AdminLoginPage; diff --git a/src/pages/admin/Auth/AdminProfilePage.jsx b/src/pages/admin/Auth/AdminProfilePage.jsx new file mode 100644 index 0000000..9539215 --- /dev/null +++ b/src/pages/admin/Auth/AdminProfilePage.jsx @@ -0,0 +1,154 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const AdminProfilePage = () => { + const schema = yup + .object({ + email: yup.string().email().required(), + }) + .required(); + + const { dispatch } = React.useContext(GlobalContext); + const [oldEmail, setOldEmail] = useState(""); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "profile", + }, + }); + + (async function () { + try { + const result = await sdk.getProfile(); + setValue("email", result.email); + setOldEmail(result.email); + } catch (error) { + console.log("Error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const onSubmit = async (data) => { + try { + if (oldEmail !== data.email) { + const emailresult = await sdk.updateEmail(data.email); + if (!emailresult.error) { + showToast(dispatch, "Email Updated", 1000); + } else { + if (emailresult.validation) { + const keys = Object.keys(emailresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: emailresult.validation[field], + }); + } + } + } + } + + if (data.password.length > 0) { + const passwordresult = await sdk.updatePassword(data.password); + if (!passwordresult.error) { + showToast(dispatch, "Password Updated", 2000); + } else { + if (passwordresult.validation) { + const keys = Object.keys(passwordresult.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: passwordresult.validation[field], + }); + } + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + return ( + <> +
+
+

Edit Profile

+
+
+ + +

+ {errors.email?.message} +

+
+
+ + +

+ {errors.password?.message} +

+
+
+ +
+
+
+
+ + ); +}; + +export default AdminProfilePage; diff --git a/src/pages/admin/Auth/AdminResetPage.jsx b/src/pages/admin/Auth/AdminResetPage.jsx new file mode 100644 index 0000000..f738dd5 --- /dev/null +++ b/src/pages/admin/Auth/AdminResetPage.jsx @@ -0,0 +1,156 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AuthContext } from "Src/authContext"; +import { showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; + +const AdminResetPage = () => { + const { dispatch } = React.useContext(AuthContext); + const search = window.location.search; + const params = new URLSearchParams(search); + const token = params.get("token"); + + const schema = yup + .object({ + code: yup.string().required(), + password: yup.string().required(), + confirmPassword: yup + .string() + .oneOf([yup.ref("password"), null], "Passwords must match"), + }) + .required(); + + const navigate = useNavigate(); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const onSubmit = async (data) => { + let sdk = new MkdSDK(); + try { + const result = await sdk.reset(token, data.code, data.password); + if (!result.error) { + showToast(dispatch, "Password Reset"); + setTimeout(() => { + navigate("/admin/login"); + }, 2000); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("code", { + type: "manual", + message: error.message, + }); + } + }; + + return ( + <> +
+
+
+ + +

+ {errors.code?.message} +

+
+
+ + +

+ {errors.password?.message} +

+
+
+ + +

+ {errors.confirmPassword?.message} +

+
+
+ + + Login? + +
+
+

+ © {new Date().getFullYear()} manaknightdigital inc. All rights + reserved. +

+
+ + ); +}; + +export default AdminResetPage; diff --git a/src/pages/admin/Edit/EditAdminAccessoriesPage.jsx b/src/pages/admin/Edit/EditAdminAccessoriesPage.jsx new file mode 100644 index 0000000..bfc8323 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminAccessoriesPage.jsx @@ -0,0 +1,278 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminAccessoriesPage = () => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + name: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + thumbnail: yup.string().required(), + top_view: yup.string().required(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [length, setLength] = useState(0); + const [width, setWidth] = useState(0); + const [thumbnail, setThumbnail] = useState(""); + const [top_view, setTopView] = useState(""); + const [id, setId] = useState(0); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + (async function () { + try { + sdk.setTable("accessories"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setValue("name", result.model.name); + setValue("length", result.model.length); + setValue("width", result.model.width); + setValue("thumbnail", result.model.thumbnail); + setValue("top_view", result.model.top_view); + + setName(result.model.name); + setLength(result.model.length); + setWidth(result.model.width); + setThumbnail(result.model.thumbnail); + setTopView(result.model.top_view); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + name: data.name, + length: data.length, + width: data.width, + thumbnail: data.thumbnail, + top_view: data.top_view, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/accessories"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("name", { + type: "manual", + message: error.message, + }); + } + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "accessories", + }, + }); + }, []); + + return ( +
+

Edit Accessories

+
+
+ + +

{errors.name?.message}

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

{errors.width?.message}

+
+ +
+ + {fileObj["thumbnail"] ? ( + isImage(fileObj["thumbnail"]) ? ( + + ) : ( + <> + ) + ) : thumbnail ? ( + + ) : null} + + previewImage("thumbnail", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.thumbnail?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.thumbnail?.message} +

+
+ +
+ + {fileObj["top_view"] ? ( + isImage(fileObj["top_view"]) ? ( + + ) : ( + <> + ) + ) : top_view ? ( + + ) : null} + + previewImage("top_view", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.top_view?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.top_view?.message} +

+
+ + +
+
+ ); +}; + +export default EditAdminAccessoriesPage; diff --git a/src/pages/admin/Edit/EditAdminAnalyticLogPage.jsx b/src/pages/admin/Edit/EditAdminAnalyticLogPage.jsx new file mode 100644 index 0000000..759af82 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminAnalyticLogPage.jsx @@ -0,0 +1,315 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; + +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminAnalyticLogPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + user_id: yup.number().required().positive().integer(), + url: yup.string().required(), + path: yup.string().required(), + hostname: yup.string().required(), + ip: yup.string().required(), + role: yup.string().required(), + browser: yup.string().required(), + country: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ user_id, setUserId ] = useState( 0 ); const [ url, setUrl ] = useState( '' ); const [ path, setPath ] = useState( '' ); const [ hostname, setHostname ] = useState( '' ); const [ ip, setIp ] = useState( '' ); const [ role, setRole ] = useState( '' ); const [ browser, setBrowser ] = useState( '' ); const [ country, setCountry ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "analytic_log" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'user_id', result.model.user_id ); + setValue( 'url', result.model.url ); + setValue( 'path', result.model.path ); + setValue( 'hostname', result.model.hostname ); + setValue( 'ip', result.model.ip ); + setValue( 'role', result.model.role ); + setValue( 'browser', result.model.browser ); + setValue( 'country', result.model.country ); + + + setUserId( result.model.user_id ); + setUrl( result.model.url ); + setPath( result.model.path ); + setHostname( result.model.hostname ); + setIp( result.model.ip ); + setRole( result.model.role ); + setBrowser( result.model.browser ); + setCountry( result.model.country ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + user_id: data.user_id, + url: data.url, + path: data.path, + hostname: data.hostname, + ip: data.ip, + role: data.role, + browser: data.browser, + country: data.country, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/analytic_log" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "user_id", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "analytic_log", + }, + } ); + }, [] ); + + return ( +
+

Edit AnalyticLog

+
+ + +
+ + +

+ { errors.user_id?.message } +

+
+ + +
+ + +

+ { errors.url?.message } +

+
+ + +
+ + +

+ { errors.path?.message } +

+
+ + +
+ + +

+ { errors.hostname?.message } +

+
+ + +
+ + +

+ { errors.ip?.message } +

+
+ + +
+ + +

+ { errors.role?.message } +

+
+ + +
+ + +

+ { errors.browser?.message } +

+
+ + +
+ + +

+ { errors.country?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminAnalyticLogPage; diff --git a/src/pages/admin/Edit/EditAdminBoatLiftsPage.jsx b/src/pages/admin/Edit/EditAdminBoatLiftsPage.jsx new file mode 100644 index 0000000..79abdcf --- /dev/null +++ b/src/pages/admin/Edit/EditAdminBoatLiftsPage.jsx @@ -0,0 +1,348 @@ +import React, { useEffect, useState } from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +import { BoatLiftRange } from "Utils/constants"; + +let sdk = new MkdSDK(); + +const EditAdminBoatLiftsPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + model: yup.string().required(), + weight_capacity: yup.number().required(), + lift_range: yup.number().required().positive().integer(), + no_of_cylinders: yup.number().required().positive().integer(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ model, setModel ] = useState( '' ); const [ weight_capacity, setWeightCapacity ] = useState( 0 ); const [ lift_range, setLiftRange ] = useState( 0 ); const [ no_of_cylinders, setNoOfCylinders ] = useState( 0 ); const [ length, setLength ] = useState( 0 ); const [ width, setWidth ] = useState( 0 ); const [ image, setImage ] = useState( '' ); const [ top_view, setTopView ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "boat_lifts" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'model', result.model.model ); + setValue( 'weight_capacity', result.model.weight_capacity ); + setValue( 'lift_range', result.model.lift_range ); + setValue( 'no_of_cylinders', result.model.no_of_cylinders ); + setValue( 'length', result.model.length ); + setValue( 'width', result.model.width ); + setValue( 'image', result.model.image ); + setValue( 'top_view', result.model.top_view ); + + + setModel( result.model.model ); + setWeightCapacity( result.model.weight_capacity ); + setLiftRange( result.model.lift_range ); + setNoOfCylinders( result.model.no_of_cylinders ); + setLength( result.model.length ); + setWidth( result.model.width ); + setImage( result.model.image ); + setTopView( result.model.top_view ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + model: data.model, + weight_capacity: data.weight_capacity, + lift_range: data.lift_range, + no_of_cylinders: data.no_of_cylinders, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/boat_lifts" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "model", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "boat_lifts", + }, + } ); + }, [] ); + + return ( +
+

Edit BoatLifts

+
+ + +
+ + +

+ { errors.model?.message } +

+
+ + +
+ + +

+ { errors.weight_capacity?.message } +

+
+ + +
+ + +

+ { errors.lift_range?.message } +

+
+ + +
+ + +

+ { errors.no_of_cylinders?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : image ? ( + + ) : null } + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+ + { fileObj[ "top_view" ] ? ( + isImage( fileObj[ "top_view" ] ) ? ( + ) : ( + <> + ) + ) : top_view ? ( + + ) : null } + + previewImage( "top_view", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.top_view?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.top_view?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminBoatLiftsPage; diff --git a/src/pages/admin/Edit/EditAdminCmsPage.jsx b/src/pages/admin/Edit/EditAdminCmsPage.jsx new file mode 100644 index 0000000..1f06bdf --- /dev/null +++ b/src/pages/admin/Edit/EditAdminCmsPage.jsx @@ -0,0 +1,182 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { useNavigate, useParams } from "react-router-dom"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import DynamicContentType from "Components/DynamicContentType"; + +let sdk = new MkdSDK(); + +const EditAdminCmsPage = () => { + const schema = yup + .object({ + page: yup.string().required(), + key: yup.string().required(), + type: yup.string().required(), + value: yup.string(), + }) + .required(); + + const selectType = [ + { key: "text", value: "Text" }, + { key: "image", value: "Image" }, + { key: "number", value: "Number" }, + { key: "kvp", value: "Key-Value Pair" }, + { key: "image-list", value: "Image List" }, + { key: "captioned-image-list", value: "Captioned Image List" }, + { key: "team-list", value: "Team List" }, + ]; + + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const navigate = useNavigate(); + const [id, setId] = useState(0); + const [contentType, setContentType] = React.useState(selectType[0]?.key); + const [contentValue, setContentValue] = React.useState(''); + + + + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + globalDispatch({ + type: "SETPATH", + payload: { + path: "cms", + }, + }); + + (async function () { + try { + sdk.setTable("cms"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setValue("page", result.model.page); + setValue("key", result.model.content_key); + setValue("type", result.model.content_type); + setValue("value", result.model.content_value); + setContentType(result.model.content_type); + setContentValue(result.model.content_value); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const onSubmit = async (data) => { + try { + const result = await sdk.cmsEdit( + id, + data.page, + data.key, + data.type, + contentValue + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/cms"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("page", { + type: "manual", + message: error.message, + }); + tokenExpireError(dispatch, error.message); + } + }; + + return ( +
+

Edit CMS Content

+
+
+ + +
+
+ + +

{errors.key?.message}

+
+
+ + +
+ + + + +
+ ); +}; + +export default EditAdminCmsPage; diff --git a/src/pages/admin/Edit/EditAdminDealersPage.jsx b/src/pages/admin/Edit/EditAdminDealersPage.jsx new file mode 100644 index 0000000..c1c09fb --- /dev/null +++ b/src/pages/admin/Edit/EditAdminDealersPage.jsx @@ -0,0 +1,173 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminDealersPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + name: yup.string().required(), + address: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ name, setName ] = useState( '' ); const [ address, setAddress ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "dealers" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'name', result.model.name ); + setValue( 'address', result.model.address ); + + + setName( result.model.name ); + setAddress( result.model.address ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + name: data.name, + address: data.address, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/dealers" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "name", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "dealers", + }, + } ); + }, [] ); + + return ( +
+

Edit Dealers

+
+ + +
+ + +

+ { errors.name?.message } +

+
+ + +
+ + +

+ { errors.address?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminDealersPage; diff --git a/src/pages/admin/Edit/EditAdminDocksPage.jsx b/src/pages/admin/Edit/EditAdminDocksPage.jsx new file mode 100644 index 0000000..483527c --- /dev/null +++ b/src/pages/admin/Edit/EditAdminDocksPage.jsx @@ -0,0 +1,297 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminDocksPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + category: yup.string().required(), + materials: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ category, setCategory ] = useState( 0 ); const [ materials, setMaterials ] = useState( 0 ); const [ length, setLength ] = useState( 0 ); const [ width, setWidth ] = useState( 0 ); const [ image, setImage ] = useState( '' ); const [ top_view, setTopView ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "docks" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'category', result.model.category ); + setValue( 'materials', result.model.materials ); + setValue( 'length', result.model.length ); + setValue( 'width', result.model.width ); + setValue( 'image', result.model.image ); + setValue( 'top_view', result.model.top_view ); + + + setCategory( result.model.category ); + setMaterials( result.model.materials ); + setLength( result.model.length ); + setWidth( result.model.width ); + setImage( result.model.image ); + setTopView( result.model.top_view ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + + const result = await sdk.callRestAPI( + { + id: id, + category: data.category, + materials: data.materials, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/docks" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "category", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "docks", + }, + } ); + }, [] ); + + return ( +
+

Edit Docks

+
+ + +
+ + +

+ { errors.category?.message } +

+
+ + +
+ + +

+ { errors.materials?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : image ? ( + + ) : null } + + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+ + { fileObj[ "top_view" ] ? ( + isImage( fileObj[ "top_view" ] ) ? ( + ) : ( + <> + ) + ) : top_view ? ( + + ) : null } + + previewImage( "top_view", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.top_view?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.top_view?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminDocksPage; diff --git a/src/pages/admin/Edit/EditAdminEmailPage.jsx b/src/pages/admin/Edit/EditAdminEmailPage.jsx new file mode 100644 index 0000000..4707c1b --- /dev/null +++ b/src/pages/admin/Edit/EditAdminEmailPage.jsx @@ -0,0 +1,176 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const EditAdminEmailPage = () => { + const schema = yup + .object( { + subject: yup.string().required(), + html: yup.string().required(), + tag: yup.string().required(), + } ) + .required(); + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const navigate = useNavigate(); + const [ id, setId ] = useState( 0 ); + const [ slug, setSlug ] = useState( "" ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + globalDispatch( { + type: "SETPATH", + payload: { + path: "email", + }, + } ); + + ( async function () { + try { + sdk.setTable( "email" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + setValue( "subject", result.model.subject ); + setValue( "html", result.model.html ); + setValue( "tag", result.model.tag ); + setSlug( result.model.slug ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const onSubmit = async ( data ) => { + try { + const result = await sdk.callRestAPI( + { id, slug, subject: data.subject, html: data.html, tag: data.tag }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/email" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "html", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + return ( +
+

Edit Email

+
+
+ + +
+
+ + +

+ { errors.subject?.message } +

+
+
+ + +

{ errors.tag?.message }

+
+
+ + +

{ errors.html?.message }

+
+ +
+
+ ); +}; + +export default EditAdminEmailPage; diff --git a/src/pages/admin/Edit/EditAdminInstructionsPage.jsx b/src/pages/admin/Edit/EditAdminInstructionsPage.jsx new file mode 100644 index 0000000..7c74028 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminInstructionsPage.jsx @@ -0,0 +1,151 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminInstructionsPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + content: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ content, setContent ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "instructions" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'content', result.model.content ); + + + setContent( result.model.content ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + for ( let item in fileObj ) { + let uploadResult = await sdk.upload( fileObj[ item ].file ); + data[ item ] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + content: data.content, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/instructions" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "content", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "instructions", + }, + } ); + }, [] ); + + return ( +
+

Edit Instructions

+
+ + +
+ + +

+ { errors.content?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminInstructionsPage; diff --git a/src/pages/admin/Edit/EditAdminQuotesMailRecipientsPage.jsx b/src/pages/admin/Edit/EditAdminQuotesMailRecipientsPage.jsx new file mode 100644 index 0000000..d3d8fa8 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminQuotesMailRecipientsPage.jsx @@ -0,0 +1,152 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { useNavigate, useParams } from "react-router-dom"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminQuotesMailRecipientsPage = () => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + + email: yup.string().required(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); +const [email, setEmail] = useState(''); + const [id, setId] = useState(0); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + (async function () { + try { + sdk.setTable("quotes_mail_recipients"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + + setValue('email', result.model.email); + + + setEmail(result.model.email); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + + const onSubmit = async (data) => { + try { + for (let item in fileObj) { + let formData = new FormData(); + formData.append('file', fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + const result = await sdk.callRestAPI( + { + id: id, + email: data.email, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/quotes_mail_recipients"); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + } + } catch (error) { + console.log("Error", error); + setError("email", { + type: "manual", + message: error.message, + }); + } + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "quotes_mail_recipients", + }, + }); + }, []); + + return ( +
+

Edit Quotes Mail Recipients

+
+ + +
+ + +

+ {errors.email?.message} +

+
+ + +
+
+ ); +}; + +export default EditAdminQuotesMailRecipientsPage; diff --git a/src/pages/admin/Edit/EditAdminQuotesPage.jsx b/src/pages/admin/Edit/EditAdminQuotesPage.jsx new file mode 100644 index 0000000..5e9b346 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminQuotesPage.jsx @@ -0,0 +1,489 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const EditAdminQuotesPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + first_name: yup.string().required(), + last_name: yup.string().required(), + email: yup.string().required(), + phone: yup.string().required(), + lake: yup.string().required(), + city: yup.string().required(), + has_dealer: yup.string().required(), + dealer_id: yup.string().required(), + dock_connection: yup.string().required(), + lake_bottom: yup.string().required(), + will_dock_boat: yup.string().required(), + comments: yup.string().required(), + dock_image: yup.string().required(), + selected_items: yup.string().required(), + country: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ first_name, setFirstName ] = useState( '' ); const [ last_name, setLastName ] = useState( '' ); const [ email, setEmail ] = useState( '' ); const [ phone, setPhone ] = useState( '' ); const [ lake, setLake ] = useState( '' ); const [ city, setCity ] = useState( '' ); const [ has_dealer, setHasDealer ] = useState( 0 ); const [ dealer_id, setDealerId ] = useState( 0 ); const [ dock_connection, setDockConnection ] = useState( 0 ); const [ lake_bottom, setLakeBottom ] = useState( 0 ); const [ will_dock_boat, setWillDockBoat ] = useState( 0 ); const [ comments, setComments ] = useState( '' ); const [ dock_image, setDockImage ] = useState( '' ); const [ selected_items, setSelectedItems ] = useState( '' ); const [ country, setCountry ] = useState( '' ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "quotes" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'first_name', result.model.first_name ); + setValue( 'last_name', result.model.last_name ); + setValue( 'email', result.model.email ); + setValue( 'phone', result.model.phone ); + setValue( 'lake', result.model.lake ); + setValue( 'city', result.model.city ); + setValue( 'has_dealer', result.model.has_dealer ); + setValue( 'dealer_id', result.model.dealer_id ); + setValue( 'dock_connection', result.model.dock_connection ); + setValue( 'lake_bottom', result.model.lake_bottom ); + setValue( 'will_dock_boat', result.model.will_dock_boat ); + setValue( 'comments', result.model.comments ); + setValue( 'dock_image', result.model.dock_image ); + setValue( 'selected_items', result.model.selected_items ); + setValue( 'country', result.model.country ); + + + setFirstName( result.model.first_name ); + setLastName( result.model.last_name ); + setEmail( result.model.email ); + setPhone( result.model.phone ); + setLake( result.model.lake ); + setCity( result.model.city ); + setHasDealer( result.model.has_dealer ); + setDealerId( result.model.dealer_id ); + setDockConnection( result.model.dock_connection ); + setLakeBottom( result.model.lake_bottom ); + setWillDockBoat( result.model.will_dock_boat ); + setComments( result.model.comments ); + setDockImage( result.model.dock_image ); + setSelectedItems( result.model.selected_items ); + setCountry( result.model.country ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + + const result = await sdk.callRestAPI( + { + id: id, + first_name: data.first_name, + last_name: data.last_name, + email: data.email, + phone: data.phone, + lake: data.lake, + city: data.city, + has_dealer: data.has_dealer, + dealer_id: data.dealer_id, + dock_connection: data.dock_connection, + lake_bottom: data.lake_bottom, + will_dock_boat: data.will_dock_boat, + comments: data.comments, + dock_image: data.dock_image, + selected_items: data.selected_items, + country: data.country, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/quotes" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "first_name", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "quotes", + }, + } ); + }, [] ); + + return ( +
+

Edit Quotes

+
+ + +
+ + +

+ { errors.first_name?.message } +

+
+ + +
+ + +

+ { errors.last_name?.message } +

+
+ + +
+ + +

+ { errors.email?.message } +

+
+ + +
+ + +

+ { errors.phone?.message } +

+
+ + +
+ + +

+ { errors.lake?.message } +

+
+ + +
+ + +

+ { errors.city?.message } +

+
+ + +
+ + +

+ { errors.has_dealer?.message } +

+
+ + +
+ + +

+ { errors.dealer_id?.message } +

+
+ + +
+ + +

+ { errors.dock_connection?.message } +

+
+ + +
+ + +

+ { errors.lake_bottom?.message } +

+
+ + +
+ + +

+ { errors.will_dock_boat?.message } +

+
+ + +
+ + +

+ { errors.comments?.message } +

+
+ + +
+ + +

+ { errors.dock_image?.message } +

+
+ + +
+ + +

+ { errors.selected_items?.message } +

+
+ + +
+ + +

+ { errors.country?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminQuotesPage; diff --git a/src/pages/admin/Edit/EditAdminRampsPage.jsx b/src/pages/admin/Edit/EditAdminRampsPage.jsx new file mode 100644 index 0000000..e89d0e2 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminRampsPage.jsx @@ -0,0 +1,317 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; +import { InteractiveButton } from "Components/InteractiveButton"; + +let sdk = new MkdSDK(); + +const EditAdminRampsPage = () => { + const { dispatch } = React.useContext(AuthContext); + const schema = yup + .object({ + category: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + material: yup.string().required(), + }) + .required(); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [fileObj, setFileObj] = React.useState({}); + const navigate = useNavigate(); + const [category, setCategory] = useState(0); + const [length, setLength] = useState(0); + const [width, setWidth] = useState(0); + const [image, setImage] = useState(""); + const [top_view, setTopView] = useState(""); + const [material, setMaterial] = useState(0); + const [id, setId] = useState(0); + const [submitLoading, setSubmitLoading] = useState(false); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + const params = useParams(); + + useEffect(function () { + (async function () { + try { + sdk.setTable("ramps"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setValue("category", result.model.category); + setValue("length", result.model.length); + setValue("width", result.model.width); + setValue("image", result.model.image); + setValue("top_view", result.model.top_view); + setValue("material", result.model.material); + + setCategory(result.model.category); + setLength(result.model.length); + setWidth(result.model.width); + setImage(result.model.image); + setTopView(result.model.top_view); + setMaterial(result.model.material); + setId(result.model.id); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + + const previewImage = (field, target) => { + let tempFileObj = fileObj; + tempFileObj[field] = { + file: target.files[0], + tempURL: URL.createObjectURL(target.files[0]), + }; + setFileObj({ ...tempFileObj }); + }; + + const onSubmit = async (data) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + setSubmitLoading(true); + // S3 Uploads + for (let item in fileObj) { + let formData = new FormData(); + formData.append("file", fileObj[item].file); + let uploadResult = await sdk.uploadImage(formData); + data[item] = uploadResult.url; + } + + const result = await sdk.callRestAPI( + { + id: id, + category: data.category, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + material: data.material, + }, + "PUT" + ); + + if (!result.error) { + showToast(globalDispatch, "Updated"); + navigate("/admin/ramps"); + setSubmitLoading(false); + } else { + if (result.validation) { + const keys = Object.keys(result.validation); + for (let i = 0; i < keys.length; i++) { + const field = keys[i]; + setError(field, { + type: "manual", + message: result.validation[field], + }); + } + } + setSubmitLoading(false); + } + } catch (error) { + setSubmitLoading(false); + console.log("Error", error); + setError("category", { + type: "manual", + message: error.message, + }); + } + }; + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "ramps", + }, + }); + }, []); + + return ( +
+

Edit Ramps

+
+
+ + +

+ {errors.category?.message} +

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

{errors.width?.message}

+
+ +
+ + {fileObj["image"] ? ( + isImage(fileObj["image"]) ? ( + + ) : ( + <> + ) + ) : image ? ( + + ) : null} + + previewImage("image", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.image?.message ? "border-red-500" : "" + }`} + /> +

{errors.image?.message}

+
+ +
+ + {fileObj["top_view"] ? ( + isImage(fileObj["top_view"]) ? ( + + ) : ( + <> + ) + ) : top_view ? ( + + ) : null} + + previewImage("top_view", e.target), + })} + className={`"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ + errors.top_view?.message ? "border-red-500" : "" + }`} + /> +

+ {errors.top_view?.message} +

+
+ +
+ + +

+ {errors.material?.message} +

+
+ + + Submit + +
+
+ ); +}; + +export default EditAdminRampsPage; diff --git a/src/pages/admin/Edit/EditAdminUserPage.jsx b/src/pages/admin/Edit/EditAdminUserPage.jsx new file mode 100644 index 0000000..d09e6c2 --- /dev/null +++ b/src/pages/admin/Edit/EditAdminUserPage.jsx @@ -0,0 +1,228 @@ +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const EditAdminUserPage = () => { + const schema = yup + .object( { + email: yup.string().email().required(), + password: yup.string(), + role: yup.string(), + } ) + .required(); + + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const navigate = useNavigate(); + const params = useParams(); + const [ oldEmail, setOldEmail ] = useState( "" ); + const [ id, setId ] = useState( 0 ); + + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const selectRole = [ "admin", "employee" ]; + const selectStatus = [ + { key: "0", value: "Inactive" }, + { key: "2", value: "Suspend" }, + { key: "1", value: "Active" }, + ]; + + /** + * + * + * Use /user/put to update user info + * use /profile/put to update profile info + */ + const onSubmit = async ( data ) => { + try { + if ( oldEmail !== data.email ) { + const emailresult = await sdk.updateEmailByAdmin( data.email, id ); + if ( !emailresult.error ) { + showToast( globalDispatch, "Email Updated", 1000 ); + } else { + if ( emailresult.validation ) { + const keys = Object.keys( emailresult.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: emailresult.validation[ field ], + } ); + } + } + } + } + + if ( data.password.length > 0 ) { + const passwordresult = await sdk.updatePasswordByAdmin( data.password, id ); + if ( !passwordresult.error ) { + showToast( globalDispatch, "Password Updated", 2000 ); + } else { + if ( passwordresult.validation ) { + const keys = Object.keys( passwordresult.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: passwordresult.validation[ field ], + } ); + } + } + } + } + + sdk.setTable( "user" ); + + const result = await sdk.callRestAPI( { id, email: data.email, role: data.role, status: data.status }, "PUT" ); + + if ( !result.error ) { + showToast( globalDispatch, "Added", 4000 ); + navigate( "/admin/users" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "email", { + type: "manual", + message: error.message, + } ); + tokenExpireError( dispatch, error.message ); + } + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "users", + }, + } ); + + ( async function () { + try { + sdk.setTable( "user" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + + if ( !result.error ) { + setValue( "email", result.model.email ); + setValue( "role", result.model.role ); + setValue( "status", result.model.status ); + setOldEmail( result.model.email ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "Error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

Edit User

+
+
+ + +

{ errors.email?.message }

+
+
+ + +
+
+ + +
+
+ + +

{ errors.password?.message }

+
+ +
+
+ ); +}; + +export default EditAdminUserPage; diff --git a/src/pages/admin/Edit/EditAdminWedgesPage.jsx b/src/pages/admin/Edit/EditAdminWedgesPage.jsx new file mode 100644 index 0000000..8fe81cc --- /dev/null +++ b/src/pages/admin/Edit/EditAdminWedgesPage.jsx @@ -0,0 +1,298 @@ +import React, { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate, useParams } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { GlobalContext, showToast } from "Src/globalContext"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const EditAdminWedgesPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const schema = yup + .object( { + + category: yup.string().required(), + length: yup.string().required(), + width: yup.string().required(), + image: yup.string().required(), + top_view: yup.string().required(), + material: yup.string().required(), + } ) + .required(); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const [ fileObj, setFileObj ] = React.useState( {} ); + const navigate = useNavigate(); + const [ category, setCategory ] = useState( 0 ); const [ length, setLength ] = useState( 0 ); const [ width, setWidth ] = useState( 0 ); const [ image, setImage ] = useState( '' ); const [ top_view, setTopView ] = useState( '' ); const [ material, setMaterial ] = useState( 0 ); + const [ id, setId ] = useState( 0 ); + const { + register, + handleSubmit, + setError, + setValue, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const params = useParams(); + + useEffect( function () { + ( async function () { + try { + sdk.setTable( "wedges" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setValue( 'category', result.model.category ); + setValue( 'length', result.model.length ); + setValue( 'width', result.model.width ); + setValue( 'image', result.model.image ); + setValue( 'top_view', result.model.top_view ); + setValue( 'material', result.model.material ); + + + setCategory( result.model.category ); + setLength( result.model.length ); + setWidth( result.model.width ); + setImage( result.model.image ); + setTopView( result.model.top_view ); + setMaterial( result.model.material ); + setId( result.model.id ); + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + + const previewImage = ( field, target ) => { + let tempFileObj = fileObj; + tempFileObj[ field ] = { + file: target.files[ 0 ], + tempURL: URL.createObjectURL( target.files[ 0 ] ), + }; + setFileObj( { ...tempFileObj } ); + }; + + + const onSubmit = async ( data ) => { + try { + // Local Uploads + // for (let item in fileObj) { + // let uploadResult = await sdk.upload(fileObj[item].file); + // data[item] = uploadResult.url; + // } + + // S3 Uploads + for ( let item in fileObj ) { + let formData = new FormData(); + formData.append( 'file', fileObj[ item ].file ); + let uploadResult = await sdk.uploadImage( formData ); + data[ item ] = uploadResult.url; + } + + + const result = await sdk.callRestAPI( + { + id: id, + category: data.category, + length: data.length, + width: data.width, + image: data.image, + top_view: data.top_view, + material: data.material, + }, + "PUT" + ); + + if ( !result.error ) { + showToast( globalDispatch, "Updated" ); + navigate( "/admin/wedges" ); + } else { + if ( result.validation ) { + const keys = Object.keys( result.validation ); + for ( let i = 0; i < keys.length; i++ ) { + const field = keys[ i ]; + setError( field, { + type: "manual", + message: result.validation[ field ], + } ); + } + } + } + } catch ( error ) { + console.log( "Error", error ); + setError( "category", { + type: "manual", + message: error.message, + } ); + } + }; + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "wedges", + }, + } ); + }, [] ); + + return ( +
+

Edit Wedges

+
+ + +
+ + +

+ { errors.category?.message } +

+
+ + +
+ + +

+ { errors.length?.message } +

+
+ + +
+ + +

+ { errors.width?.message } +

+
+ + +
+ + { fileObj[ "image" ] ? ( + isImage( fileObj[ "image" ] ) ? ( + ) : ( + <> + ) + ) : image ? ( + + ) : null } + + previewImage( "image", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.image?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.image?.message } +

+
+ + +
+ + { fileObj[ "top_view" ] ? ( + isImage( fileObj[ "top_view" ] ) ? ( + ) : ( + <> + ) + ) : top_view ? ( + + ) : null } + + previewImage( "top_view", e.target ) } ) } + className={ `"shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${ errors.top_view?.message ? "border-red-500" : "" + }` } + /> +

+ { errors.top_view?.message } +

+
+ + +
+ + +

+ { errors.material?.message } +

+
+ + +
+
+ ); +}; + +export default EditAdminWedgesPage; diff --git a/src/pages/admin/List/AdminAccessoriesListPage.jsx b/src/pages/admin/List/AdminAccessoriesListPage.jsx new file mode 100644 index 0000000..221b147 --- /dev/null +++ b/src/pages/admin/List/AdminAccessoriesListPage.jsx @@ -0,0 +1,349 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +// import PaginationBar from "Components/ExportButton"; +import { AddButton, PaginationBar } from "Components"; +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; +let sdk = new MkdSDK(); + +const columns = [ + { + header: "ID", + accessor: "id", + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Name", + accessor: "name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Length", + accessor: "length", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Width", + accessor: "width", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Thumbnail", + accessor: "thumbnail", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Top View", + accessor: "top_view", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminAccessoriesListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const navigate = useNavigate(); + + const schema = yup.object({ + name: yup.string(), + }); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + sdk.setTable("accessories"); + let sortField = columns.filter((col) => col.isSorted); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[0].accessor : "", + direction: sortField.length + ? sortField[0].isSortedDesc + ? "DESC" + : "ASC" + : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + sdk.setTable("accessories"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + } catch (err) { + throw new Error(err); + } + }; + + const onSubmit = (data) => { + let name = getNonNullValue(data.name); + let filter = { + name, + }; + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "accessories", + }, + }); + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( + <> +
+

Accessories Search

+
+
+ + +

+ {errors.name?.message} +

+
+
+ +
+ +
+
+

Accessories

+ +
+
+ + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
+ + + + + {cell.mappings[row[cell.accessor]]} + + {["thumbnail", "top_view"].includes(cell.accessor) ? ( + + ) : ( + row[cell.accessor] + )} +
+
+
+ + + ); +}; + +export default AdminAccessoriesListPage; diff --git a/src/pages/admin/List/AdminAnalyticLogListPage.jsx b/src/pages/admin/List/AdminAnalyticLogListPage.jsx new file mode 100644 index 0000000..aca2bce --- /dev/null +++ b/src/pages/admin/List/AdminAnalyticLogListPage.jsx @@ -0,0 +1,534 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'User Id', + accessor: 'user_id', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Url', + accessor: 'url', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Path', + accessor: 'path', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Hostname', + accessor: 'hostname', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Ip', + accessor: 'ip', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Role', + accessor: 'role', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Browser', + accessor: 'browser', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Country', + accessor: 'country', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminAnalyticLogListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + + user_id: yup.number().positive().integer(), + url: yup.string(), + path: yup.string(), + hostname: yup.string(), + ip: yup.string(), + role: yup.string(), + browser: yup.string(), + country: yup.string(), + } ); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "analytic_log" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "analytic_log" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + const onSubmit = ( currentTableData ) => { + let id = getNonNullValue( data.id ); + let user_id = getNonNullValue( data.user_id ); + let url = getNonNullValue( data.url ); + let path = getNonNullValue( data.path ); + let hostname = getNonNullValue( data.hostname ); + let ip = getNonNullValue( data.ip ); + let role = getNonNullValue( data.role ); + let browser = getNonNullValue( data.browser ); + let country = getNonNullValue( data.country ); + let filter = { + id, + + user_id: user_id, + url: url, + path: path, + hostname: hostname, + ip: ip, + role: role, + browser: browser, + country: country, + }; + getData( 1, pageSize, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "analytic_log", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

AnalyticLog Search

+
+ +
+ + +

+ { errors.id?.message } +

+
+ +
+ + +

+ { errors.user_id?.message } +

+
+ +
+ + +

+ { errors.url?.message } +

+
+ +
+ + +

+ { errors.path?.message } +

+
+ +
+ + +

+ { errors.hostname?.message } +

+
+ +
+ + +

+ { errors.ip?.message } +

+
+ +
+ + +

+ { errors.role?.message } +

+
+ +
+ + +

+ { errors.browser?.message } +

+
+ +
+ + +

+ { errors.country?.message } +

+
+ +
+ +
+ +
+
+

AnalyticLog

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminAnalyticLogListPage; diff --git a/src/pages/admin/List/AdminBoatLiftsListPage.jsx b/src/pages/admin/List/AdminBoatLiftsListPage.jsx new file mode 100644 index 0000000..0806e1f --- /dev/null +++ b/src/pages/admin/List/AdminBoatLiftsListPage.jsx @@ -0,0 +1,433 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Model', + accessor: 'model', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Weight Capacity', + accessor: 'weight_capacity', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Lift Range', + accessor: 'lift_range', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'No Of Cylinders', + accessor: 'no_of_cylinders', + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 2: '2', 4: '4' } + }, + { + header: 'Length', + accessor: 'length', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Width', + accessor: 'width', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Image', + accessor: 'image', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Top View', + accessor: 'top_view', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminBoatLiftsListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + model: yup.string(), + weight_capacity: yup.string(), + lift_range: yup.string(), + no_of_cylinders: yup.string(), + } ); + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "boat_lifts" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "boat_lifts" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + const onSubmit = ( data ) => { + let model = getNonNullValue( data.model ); + let weight_capacity = getNonNullValue( data.weight_capacity ); + let lift_range = getNonNullValue( data.lift_range ); + let no_of_cylinders = getNonNullValue( data.no_of_cylinders ); + let filter = { + model, + weight_capacity, + lift_range, + no_of_cylinders, + }; + getData( 1, pageSize, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "boat_lifts", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

BoatLifts Search

+
+
+ + +

+ { errors.model?.message } +

+
+ +
+ + +

+ { errors.weight_capacity?.message } +

+
+ +
+ + +

+ { errors.lift_range?.message } +

+
+ +
+ + +

+ { errors.no_of_cylinders?.message } +

+
+ + +
+ +
+ +
+
+

BoatLifts

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { [ "image", "top_view" ].includes( cell.accessor ) ? : row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminBoatLiftsListPage; diff --git a/src/pages/admin/List/AdminCmsListPage.jsx b/src/pages/admin/List/AdminCmsListPage.jsx new file mode 100644 index 0000000..336bca1 --- /dev/null +++ b/src/pages/admin/List/AdminCmsListPage.jsx @@ -0,0 +1,257 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Page", + accessor: "page", + }, + { + header: "Identifier", + accessor: "content_key", + }, + { + header: "Content Type", + accessor: "content_type", + }, + + { + header: "Action", + accessor: "", + }, +]; + +const AdminCmsListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ data, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 3 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + page: yup.string(), + key: yup.string(), + type: yup.string(), + } ); + + const selectType = [ + { key: "", value: "All" }, + { key: "text", value: "Text" }, + { key: "image", value: "Image" }, + { key: "number", value: "Number" }, + ]; + + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( currentPage + 1 <= pageCount ? currentPage + 1 : 0, pageSize ); + } )(); + } + + async function getData ( pageNum, limitNum, data ) { + try { + sdk.setTable( "cms" ); + const result = await sdk.callRestAPI( + { + payload: { ...data }, + page: pageNum, + limit: limitNum, + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const onSubmit = ( data ) => { + let page = getNonNullValue( data.page ); + let key = getNonNullValue( data.key ); + let type = getNonNullValue( data.type ); + let filter = { page, content_key: key, content_type: type }; + getData( 0, 10, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "cms", + }, + } ); + + ( async function () { + await getData( 0, 10 ); + } )(); + }, [] ); + + return ( + <> +
+

CMS Search

+
+
+ + +

{ errors.page?.message }

+
+
+ + +

{ errors.key?.message }

+
+ +
+ + +

+
+
+ + +
+ +
+
+

CMS

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { data.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mapping ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
+ { column.header } + { column.isSorted ? ( column.isSortedDesc ? " â–¼" : " â–²" ) : "" } +
+ + + { cell.mapping[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminCmsListPage; diff --git a/src/pages/admin/List/AdminDealersListPage.jsx b/src/pages/admin/List/AdminDealersListPage.jsx new file mode 100644 index 0000000..47e76c4 --- /dev/null +++ b/src/pages/admin/List/AdminDealersListPage.jsx @@ -0,0 +1,341 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Name', + accessor: 'name', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Address', + accessor: 'address', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminDealersListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + + name: yup.string(), + address: yup.string(), + } ); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "dealers" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "dealers" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + const onSubmit = ( data ) => { + let name = getNonNullValue( data.name ); + let address = getNonNullValue( data.address ); + let filter = { + name: name, + address: address, + }; + getData( 1, pageSize, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "dealers", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

Dealers Search

+
+ +
+ + +

+ { errors.name?.message } +

+
+ +
+ + +

+ { errors.address?.message } +

+
+ +
+ +
+ +
+
+

Dealers

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminDealersListPage; diff --git a/src/pages/admin/List/AdminDocksListPage.jsx b/src/pages/admin/List/AdminDocksListPage.jsx new file mode 100644 index 0000000..2433018 --- /dev/null +++ b/src/pages/admin/List/AdminDocksListPage.jsx @@ -0,0 +1,423 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Category', + accessor: 'category', + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: 'Floating Dock', 1: 'Sectional Dock', 2: 'Roll-In Dock' } + }, + { + header: 'Materials', + accessor: 'materials', + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: 'Wood Grain', 1: 'Perforated', 2: 'Grey Aluminium' } + }, + { + header: 'Length', + accessor: 'length', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Width', + accessor: 'width', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Image', + accessor: 'image', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Top View', + accessor: 'top_view', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminDocksListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + + category: yup.string(), + materials: yup.string(), + length: yup.string(), + width: yup.string(), + } ); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "docks" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "docks" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + const onSubmit = ( data ) => { + let category = getNonNullValue( data.category ); + let materials = getNonNullValue( data.materials ); + let length = getNonNullValue( data.length ); + let width = getNonNullValue( data.width ); + + let filter = { + + category: category, + materials: materials, + length: length, + width: width, + + }; + getData( 1, pageSize, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "docks", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

Docks Search

+
+ +
+ + +

+ { errors.category?.message } +

+
+ +
+ + +

+ { errors.materials?.message } +

+
+ +
+ + +

+ { errors.length?.message } +

+
+ +
+ + +

+ { errors.width?.message } +

+
+ + +
+ +
+ +
+
+

Docks

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { [ "image", "top_view" ].includes( cell.accessor ) ? : row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminDocksListPage; diff --git a/src/pages/admin/List/AdminEmailListPage.jsx b/src/pages/admin/List/AdminEmailListPage.jsx new file mode 100644 index 0000000..8a69405 --- /dev/null +++ b/src/pages/admin/List/AdminEmailListPage.jsx @@ -0,0 +1,162 @@ +import React from "react"; +import Skeleton from "react-loading-skeleton"; +import { useNavigate } from "react-router-dom"; + +import { AddButton } from "Components"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "ID", + accessor: "id", + }, + { + header: "Email Type", + accessor: "slug", + }, + { + header: "Subject", + accessor: "subject", + }, + { + header: "Tags", + accessor: "tag", + }, + + { + header: "Action", + accessor: "", + }, +]; + +const AdminEmailListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const [ data, setCurrentTableData ] = React.useState( [] ); + const [ loadingData, setLoadingData ] = React.useState( false ); + const navigate = useNavigate(); + + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + async function getData () { + try { + sdk.setTable( "email" ); + const result = await sdk.callRestAPI( {}, "GETALL" ); + + const { list } = result; + + setCurrentTableData( list ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "email", + }, + } ); + + ( async function () { + setLoadingData( true ); + await getData(); + setLoadingData( false ); + } )(); + }, [] ); + + return ( + <> +
+
+

Emails

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { data.length == 0 ? ( + + + + ) : null } + { data.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mapping ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
+ { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ { loadingData && } +
+ + + { cell.mapping[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + ); +}; + +export default AdminEmailListPage; diff --git a/src/pages/admin/List/AdminInstructionsListPage.jsx b/src/pages/admin/List/AdminInstructionsListPage.jsx new file mode 100644 index 0000000..f2aba59 --- /dev/null +++ b/src/pages/admin/List/AdminInstructionsListPage.jsx @@ -0,0 +1,333 @@ +import React from "react"; + +// import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +// import { yupResolver } from "@hookform/resolvers/yup"; +// import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Content', + accessor: 'content', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminInstructionsListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + // const schema = yup.object( { + + // id: yup.string(), + // } ); + // const { + // register, + // handleSubmit, + // setError, + // formState: { errors }, + // } = useForm( { + // resolver: yupResolver( schema ), + // } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "instructions" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "instructions" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + // const onSubmit = ( data ) => + // { + + // let id = getNonNullValue( Number( data.id ) ); + // let filter = { + // id: id, + // }; + + // getData( 1, pageSize, filter ); + // }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "instructions", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> + {/*
+

Instructions Search

+
+ +
+ + +

+ { errors.id?.message } +

+
+ +
+ + +

+ { errors.content?.message } +

+
+ +
+ +
*/} + +
+
+

Instructions

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminInstructionsListPage; diff --git a/src/pages/admin/List/AdminPhotoListPage.jsx b/src/pages/admin/List/AdminPhotoListPage.jsx new file mode 100644 index 0000000..c0ae445 --- /dev/null +++ b/src/pages/admin/List/AdminPhotoListPage.jsx @@ -0,0 +1,295 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import Skeleton from "react-loading-skeleton"; + +import PaginationBar from "Components/PaginationBar"; +import AddButton from "Components/AddButton"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Photos", + accessor: "url", + }, + { + header: "Create at", + accessor: "create_at", + }, + + { + header: "Action", + accessor: "", + }, +]; + +const AdminPhotoListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + const [query, setQuery] = React.useState(""); + const [data, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(3); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const [loadingData, setLoadingData] = React.useState(false); + const navigate = useNavigate(); + const globalContext = React.useContext(GlobalContext); + + const schema = yup.object({ + date: yup.string(), + id: yup.string(), + user_id: yup.string(), + }); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, data) { + try { + sdk.setTable("photo"); + const result = await sdk.callRestAPI( + { + payload: { ...data }, + page: pageNum, + limit: limitNum, + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "photos", + }, + }); + + (async function () { + setLoadingData(true); + await getData(0, 50); + setLoadingData(false); + })(); + }, []); + + async function deleteImage(id) { + sdk.setTable("photo"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + showToast(globalDispatch, "Deleted"); + await getData(0, 50); + } + + return ( + <> +
{ + let create_at = getNonNullValue(data.date); + let id = getNonNullValue(data.id); + let user_id = getNonNullValue(data.user_id); + let filter = { create_at, id, user_id }; + getData(0, 50, filter); + })} + > +

Photo Search

+
+
+ + +

+ {errors.date?.message} +

+
+
+ + +

{errors.id?.message}

+
+ +
+ + + +

+ {errors.user_id?.message} +

+
+
+ + +
+ +
+
+

Photos

+ +
+
+ + + + {columns.map((column, index) => ( + + ))} + + + + {data.length == 0 ? ( + + + + ) : null} + {data.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mapping) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
+ {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
{loadingData && }
+ + + {cell.mapping[row[cell.accessor]]} + + {cell.accessor == "url" ? ( + + ) : ( + row[cell.accessor] + )} +
+
+
+ + + ); +}; + +export default AdminPhotoListPage; diff --git a/src/pages/admin/List/AdminQuotesListPage.jsx b/src/pages/admin/List/AdminQuotesListPage.jsx new file mode 100644 index 0000000..d42898a --- /dev/null +++ b/src/pages/admin/List/AdminQuotesListPage.jsx @@ -0,0 +1,500 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import PaginationBar from "Components/PaginationBar"; + +import { AuthContext, tokenExpireError } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Action", + accessor: "", + }, + + { + header: "ID", + accessor: "id", + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "First Name", + accessor: "first_name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Last Name", + accessor: "last_name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Email", + accessor: "email", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Phone", + accessor: "phone", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Lake", + accessor: "lake", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "City", + accessor: "city", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Has Dealer", + accessor: "has_dealer", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "No", 1: "Yes" }, + }, + { + header: "Dealer Id", + accessor: "dealer_id", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Dock Connection", + accessor: "dock_connection", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "Resting", 1: "Bolted", 2: "Other" }, + }, + { + header: "Lake Bottom", + accessor: "lake_bottom", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "Rocky", 1: "Silty", 2: "Sandy" }, + }, + { + header: "Will Dock Boat", + accessor: "will_dock_boat", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "No", 1: "Yes" }, + }, + { + header: "Comments", + accessor: "comments", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Dock Image", + accessor: "dock_image", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + // { + // header: 'Selected Items', + // accessor: 'selected_items', + // isSorted: false, + // isSortedDesc: false, + // mappingExist: false, + // mappings: {} + // }, + { + header: "Country", + accessor: "country", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, +]; + +const AdminQuotesListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const navigate = useNavigate(); + + const schema = yup.object({ + first_name: yup.string(), + last_name: yup.string(), + email: yup.string(), + phone: yup.string(), + }); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + sdk.setTable("quotes"); + let sortField = columns.filter((col) => col.isSorted); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[0].accessor : "", + direction: sortField.length + ? sortField[0].isSortedDesc + ? "DESC" + : "ASC" + : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + sdk.setTable("quotes"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + } catch (err) { + throw new Error(err); + } + }; + + const onSubmit = (data) => { + let first_name = getNonNullValue(data.first_name); + let last_name = getNonNullValue(data.last_name); + let email = getNonNullValue(data.email); + let phone = getNonNullValue(data.phone); + + let filter = { + first_name: first_name, + last_name: last_name, + email: email, + phone: phone, + }; + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "quotes", + }, + }); + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( + <> +
+

Quotes Search

+
+
+ + +

+ {errors.first_name?.message} +

+
+ +
+ + +

+ {errors.last_name?.message} +

+
+ +
+ + +

+ {errors.email?.message} +

+
+ +
+ + +

+ {errors.phone?.message} +

+
+
+ +
+ +
+
+

Quotes

+ {/* */} +
+
+ + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
+ {/* */} + + + + {cell.mappings[row[cell.accessor]]} + + {cell.accessor === "dock_image" ? ( + + ) : ( + row[cell.accessor] + )} +
+
+
+ + + ); +}; + +export default AdminQuotesListPage; diff --git a/src/pages/admin/List/AdminQuotesMailRecipientsListPage.jsx b/src/pages/admin/List/AdminQuotesMailRecipientsListPage.jsx new file mode 100644 index 0000000..543016a --- /dev/null +++ b/src/pages/admin/List/AdminQuotesMailRecipientsListPage.jsx @@ -0,0 +1,378 @@ +import React from "react"; +import { AuthContext } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext } from "Src/globalContext"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { getNonNullValue } from "Utils/utils"; +import PaginationBar from "Components/PaginationBar"; +import AddButton from "Components/AddButton"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Action", + accessor: "", + }, + + { + header: "ID", + accessor: "id", + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Email", + accessor: "email", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, +]; + +const AdminQuotesMailRecipientsListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const navigate = useNavigate(); + + const schema = yup.object({ + email: yup.string(), + }); + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + sdk.setTable("quotes_mail_recipients"); + let sortField = columns.filter((col) => col.isSorted); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[0].accessor : "", + direction: sortField.length + ? sortField[0].isSortedDesc + ? "DESC" + : "ASC" + : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + sdk.setTable("quotes_mail_recipients"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + } catch (err) { + throw new Error(err); + } + }; + + const exportTable = async (id) => { + try { + sdk.setTable("quotes_mail_recipients"); + const result = await sdk.exportCSV(); + } catch (err) { + throw new Error(err); + } + }; + + const resetForm = async () => { + reset(); + await getData(0, pageSize); + }; + + const onSubmit = (data) => { + let id = getNonNullValue(data.id); + let email = getNonNullValue(data.email); + let filter = { + id, + + email: email, + }; + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "quotes_mail_recipients", + }, + }); + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( + <> +
+

Quotes Mail Recipients Search

+
+
+ + +

{errors.id?.message}

+
+ +
+ + +

+ {errors.email?.message} +

+
+
+ + + +
+ +
+
+

Quotes Mail Recipients

+
+ + {/* */} +
+
+
+ + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor.indexOf("image") > -1) { + return ( + + ); + } + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
+ + + + + + + {cell.mappings[row[cell.accessor]]} + + {row[cell.accessor]} +
+
+
+ + + ); +}; + +export default AdminQuotesMailRecipientsListPage; diff --git a/src/pages/admin/List/AdminRampsListPage.jsx b/src/pages/admin/List/AdminRampsListPage.jsx new file mode 100644 index 0000000..6ce0d01 --- /dev/null +++ b/src/pages/admin/List/AdminRampsListPage.jsx @@ -0,0 +1,474 @@ +import React from "react"; +import { AuthContext, tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext } from "Src/globalContext"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import { getNonNullValue } from "Utils/utils"; +import PaginationBar from "Components/PaginationBar"; +import AddButton from "Components/AddButton"; +// import ExportButton from "Components/ExportButton"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Action", + accessor: "", + }, + + { + header: "Id", + accessor: "id", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + // { + // header: "Create At", + // accessor: "create_at", + // isSorted: false, + // isSortedDesc: false, + // mappingExist: false, + // mappings: {}, + // }, + + // { + // header: "Update At", + // accessor: "update_at", + // isSorted: false, + // isSortedDesc: false, + // mappingExist: false, + // mappings: {}, + // }, + + { + header: "Category", + accessor: "category", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "Pivot Ramp", 1: "Truss Ramp" }, + }, + + { + header: "Length", + accessor: "length", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + { + header: "Width", + accessor: "width", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + { + header: "Image", + accessor: "image", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + { + header: "Top View", + accessor: "top_view", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + + { + header: "Material", + accessor: "material", + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: "Wood Grain", 1: "Grey Aluminium", 2: "Perforated" }, + }, +]; + +const RampsListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const navigate = useNavigate(); + + const schema = yup.object({ + category: yup.string(), + + material: yup.string(), + }); + const { + register, + handleSubmit, + setError, + reset, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + sdk.setTable("ramps"); + let sortField = columns.filter((col) => col.isSorted); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[0].accessor : "", + direction: sortField.length + ? sortField[0].isSortedDesc + ? "DESC" + : "ASC" + : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + sdk.setTable("ramps"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + } catch (err) { + throw new Error(err); + } + }; + + const exportTable = async (id) => { + try { + sdk.setTable("notes"); + const result = await sdk.exportCSV(); + } catch (err) { + throw new Error(err); + } + }; + + const resetForm = async () => { + reset(); + await getData(0, pageSize); + }; + + const onSubmit = (_data) => { + let material = getNonNullValue(_data.material); + let category = getNonNullValue(_data.category); + let filter = { + category: category, + + material: material, + }; + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "ramps", + }, + }); + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( + <> +
+

Ramps Search

+
+
+ + +

+ {errors.category?.message} +

+
+ +
+ + +

+ {errors.material?.message} +

+
+
+ +
+ +
+
+

Ramps

+
+ + {/* */} +
+
+
+ + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if ( + cell.accessor.indexOf("image") > -1 || + cell.accessor === "top_view" + ) { + return ( + + ); + } + if ( + cell.accessor.indexOf("pdf") > -1 || + cell.accessor.indexOf("doc") > -1 || + cell.accessor.indexOf("file") > -1 || + cell.accessor.indexOf("video") > -1 + ) { + return ( + + ); + } + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + if (["update_at", "create_at"].includes(cell.accessor)) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
+ + + + {" "} + View + + + + + + + {cell.mappings[row[cell.accessor]]} + + {row[cell.accessor].split("T")[0]} + + {row[cell.accessor]} +
+
+
+ + + ); +}; + +export default RampsListPage; diff --git a/src/pages/admin/List/AdminReferenceItemsListPage.jsx b/src/pages/admin/List/AdminReferenceItemsListPage.jsx new file mode 100644 index 0000000..119b1ca --- /dev/null +++ b/src/pages/admin/List/AdminReferenceItemsListPage.jsx @@ -0,0 +1,443 @@ +import React from "react"; +import { AuthContext } from "../authContext"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { GlobalContext } from "../globalContext"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import PaginationBar from "Components/PaginationBar"; +import AddButton from "Components/AddButton"; +// import ExportButton from "Components/ExportButton"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "Action", + accessor: "", + }, + + { + header: "ID", + accessor: "id", + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Name", + accessor: "name", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Length", + accessor: "length", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Width", + accessor: "width", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, + { + header: "Image", + accessor: "image", + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {}, + }, +]; + +const AdminReferenceItemsListPage = () => { + const { dispatch } = React.useContext(AuthContext); + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const [query, setQuery] = React.useState(""); + const [currentTableData, setCurrentTableData] = React.useState([]); + const [pageSize, setPageSize] = React.useState(10); + const [pageCount, setPageCount] = React.useState(0); + const [dataTotal, setDataTotal] = React.useState(0); + const [currentPage, setPage] = React.useState(0); + const [canPreviousPage, setCanPreviousPage] = React.useState(false); + const [canNextPage, setCanNextPage] = React.useState(false); + const navigate = useNavigate(); + + const schema = yup.object({ + name: yup.string(), + length: yup.string(), + width: yup.string(), + image: yup.string(), + }); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm({ + resolver: yupResolver(schema), + }); + + function onSort(columnIndex) { + console.log(columns[columnIndex]); + if (columns[columnIndex].isSorted) { + columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc; + } else { + columns.map((i) => (i.isSorted = false)); + columns.map((i) => (i.isSortedDesc = false)); + columns[columnIndex].isSorted = true; + } + + (async function () { + await getData(0, pageSize); + })(); + } + + function updatePageSize(limit) { + (async function () { + setPageSize(limit); + await getData(0, limit); + })(); + } + + function previousPage() { + (async function () { + await getData(currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize); + })(); + } + + function nextPage() { + (async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + })(); + } + + async function getData(pageNum, limitNum, currentTableData) { + try { + sdk.setTable("reference_items"); + let sortField = columns.filter((col) => col.isSorted); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[0].accessor : "", + direction: sortField.length + ? sortField[0].isSortedDesc + ? "DESC" + : "ASC" + : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData(list); + setPageSize(limit); + setPageCount(num_pages); + setPage(page); + setDataTotal(total); + setCanPreviousPage(page > 1); + setCanNextPage(page + 1 <= num_pages); + } catch (error) { + console.log("ERROR", error); + tokenExpireError(dispatch, error.message); + } + } + + const deleteItem = async (id) => { + try { + sdk.setTable("reference_items"); + const result = await sdk.callRestAPI({ id }, "DELETE"); + setCurrentTableData((list) => + list.filter((x) => Number(x.id) !== Number(id)) + ); + } catch (err) { + throw new Error(err); + } + }; + + const exportTable = async (id) => { + try { + sdk.setTable("reference_items"); + const result = await sdk.exportCSV(); + } catch (err) { + throw new Error(err); + } + }; + + const onSubmit = (data) => { + let id = getNonNullValue(data.id); + let name = getNonNullValue(data.name); + let length = getNonNullValue(data.length); + let width = getNonNullValue(data.width); + let image = getNonNullValue(data.image); + let filter = { + id, + + name: name, + length: length, + width: width, + image: image, + }; + getData(1, pageSize, filter); + }; + + React.useEffect(() => { + globalDispatch({ + type: "SETPATH", + payload: { + path: "reference_items", + }, + }); + + (async function () { + await getData(1, pageSize); + })(); + }, []); + + return ( + <> +
+

ReferenceItems Search

+
+
+ + +

{errors.id?.message}

+
+ +
+ + +

+ {errors.name?.message} +

+
+ +
+ + +

+ {errors.length?.message} +

+
+ +
+ + +

+ {errors.width?.message} +

+
+ +
+ + +

+ {errors.image?.message} +

+
+
+ +
+ +
+
+

ReferenceItems

+
+ + {/* */} +
+
+
+ + + + {columns.map((column, i) => ( + + ))} + + + + {currentTableData.map((row, i) => { + return ( + + {columns.map((cell, index) => { + if (cell.accessor == "") { + return ( + + ); + } + if (cell.mappingExist) { + return ( + + ); + } + return ( + + ); + })} + + ); + })} + +
onSort(i)} + > + {column.header} + + {column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : ""} + +
+ + + + + {cell.mappings[row[cell.accessor]]} + + {row[cell.accessor]} +
+
+
+ + + ); +}; + +export default AdminReferenceItemsListPage; diff --git a/src/pages/admin/List/AdminUserListPage.jsx b/src/pages/admin/List/AdminUserListPage.jsx new file mode 100644 index 0000000..ad09b6b --- /dev/null +++ b/src/pages/admin/List/AdminUserListPage.jsx @@ -0,0 +1,326 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const columns = [ + { + header: "ID", + accessor: "id", + }, + { + header: "Email", + accessor: "email", + isSorted: true, + isSortedDesc: false, + }, + { + header: "Role", + accessor: "role", + }, + { + header: "Status", + accessor: "status", + mapping: [ "Inactive", "Active", "Suspend" ], + }, + { + header: "Action", + accessor: "", + }, +]; +const AdminUserListPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + const { dispatch } = React.useContext( AuthContext ); + const [ query, setQuery ] = React.useState( "" ); + const [ tableColumns, setTableColumns ] = React.useState( columns ); + const [ data, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + id: yup.string(), + email: yup.string(), + status: yup.string(), + } ); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + const selectRole = [ "", "admin", "employee" ]; + const selectStatus = [ + { key: "", value: "All" }, + { key: "0", value: "Inactive" }, + { key: "1", value: "Active" }, + { key: "2", value: "Suspend" }, + ]; + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + function onSort ( accessor ) { + const columns = tableColumns + const index = columns.findIndex( ( column ) => column.accessor === accessor ) + const column = columns[ index ] + column.isSortedDesc = !column.isSortedDesc + columns.splice( index, 1, column ) + setTableColumns( () => [ ...columns ] ) + const sortedList = selector( data, column.isSortedDesc ) + setCurrentTableData( sortedList ); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + function selector ( users, isSortedDesc ) { + return users.sort( ( a, b ) => { + if ( isSortedDesc ) { + return a.email < b.email ? 1 : -1 + } + if ( !isSortedDesc ) { + return a.email < b.email ? -1 : 1 + } + } ) + } + + async function getData ( pageNum, limitNum, data ) { + try { + sdk.setTable( "user" ); + const result = await sdk.callRestAPI( + { + payload: { + ...data, + }, + page: pageNum, + limit: limitNum, + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + const sortedList = selector( list, false ) + setCurrentTableData( sortedList ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const onSubmit = ( data ) => { + const email = getNonNullValue( data.email ); + const status = getNonNullValue( data.status ); + const id = getNonNullValue( data.id ); + getData( 0, pageSize, { email, role: 'admin', status, id } ); + }; + + // React.useEffect(() => { + + // }, []); + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "users", + }, + } ); + + ( async function () { + await getData( 0, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

Search

+
+
+ + +

{ errors.id?.message }

+
+
+ + +

+ { errors.email?.message } +

+
+ +
+ + +

+
+
+ +
+ +
+
+

Users

+ +
+
+ + + + { tableColumns.map( ( column, index ) => ( + + ) ) } + + + + { data.map( ( row, i ) => { + return ( + + { tableColumns.map( ( cell, index ) => { + if ( cell.accessor === "" ) { + return ( + + ); + } + if ( cell.mapping ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( column.accessor ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + { cell.mapping[ row[ cell.accessor ] ] } + + { row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminUserListPage; diff --git a/src/pages/admin/List/AdminWedgesListPage.jsx b/src/pages/admin/List/AdminWedgesListPage.jsx new file mode 100644 index 0000000..6313719 --- /dev/null +++ b/src/pages/admin/List/AdminWedgesListPage.jsx @@ -0,0 +1,379 @@ +import React from "react"; + +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { AddButton, PaginationBar } from "Components"; + +import { AuthContext } from "Src/authContext"; +import { GlobalContext } from "Src/globalContext"; +import MkdSDK from "Utils/MkdSDK"; +import { getNonNullValue } from "Utils/utils"; +let sdk = new MkdSDK(); + +const columns = [ + + { + header: 'ID', + accessor: 'id', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Category', + accessor: 'category', + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: 'Floating Wedge', 1: 'Roll-In Wedge' } + }, + { + header: 'Length', + accessor: 'length', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Width', + accessor: 'width', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Image', + accessor: 'image', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Top View', + accessor: 'top_view', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Material', + accessor: 'material', + isSorted: false, + isSortedDesc: false, + mappingExist: true, + mappings: { 0: 'Wood Grain', 1: 'Grey Aluminium', 2: 'Perforated' } + }, + { + header: "Action", + accessor: "", + }, +]; + +const AdminWedgesListPage = () => { + const { dispatch } = React.useContext( AuthContext ); + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const [ query, setQuery ] = React.useState( "" ); + const [ currentTableData, setCurrentTableData ] = React.useState( [] ); + const [ pageSize, setPageSize ] = React.useState( 10 ); + const [ pageCount, setPageCount ] = React.useState( 0 ); + const [ dataTotal, setDataTotal ] = React.useState( 0 ); + const [ currentPage, setPage ] = React.useState( 0 ); + const [ canPreviousPage, setCanPreviousPage ] = React.useState( false ); + const [ canNextPage, setCanNextPage ] = React.useState( false ); + const navigate = useNavigate(); + + const schema = yup.object( { + + category: yup.string(), + material: yup.string(), + } ); + const { + register, + handleSubmit, + setError, + formState: { errors }, + } = useForm( { + resolver: yupResolver( schema ), + } ); + + function onSort ( columnIndex ) { + console.log( columns[ columnIndex ] ); + if ( columns[ columnIndex ].isSorted ) { + columns[ columnIndex ].isSortedDesc = !columns[ columnIndex ].isSortedDesc; + } else { + columns.map( ( i ) => ( i.isSorted = false ) ); + columns.map( ( i ) => ( i.isSortedDesc = false ) ); + columns[ columnIndex ].isSorted = true; + } + + ( async function () { + await getData( 0, pageSize ); + } )(); + } + + + function updatePageSize ( limit ) { + ( async function () { + setPageSize( limit ); + await getData( 0, limit ); + } )(); + } + + function previousPage () { + ( async function () { + await getData( currentPage - 1 > 0 ? currentPage - 1 : 0, pageSize ); + } )(); + } + + function nextPage () { + ( async function () { + await getData( + currentPage + 1 <= pageCount ? currentPage + 1 : 0, + pageSize + ); + } )(); + } + + async function getData ( pageNum, limitNum, currentTableData ) { + try { + sdk.setTable( "wedges" ); + let sortField = columns.filter( ( col ) => col.isSorted ); + const result = await sdk.callRestAPI( + { + payload: { ...currentTableData }, + page: pageNum, + limit: limitNum, + sortId: sortField.length ? sortField[ 0 ].accessor : "", + direction: sortField.length ? ( sortField[ 0 ].isSortedDesc ? "DESC" : "ASC" ) : "", + }, + "PAGINATE" + ); + + const { list, total, limit, num_pages, page } = result; + + setCurrentTableData( list ); + setPageSize( limit ); + setPageCount( num_pages ); + setPage( page ); + setDataTotal( total ); + setCanPreviousPage( page > 1 ); + setCanNextPage( page + 1 <= num_pages ); + } catch ( error ) { + console.log( "ERROR", error ); + tokenExpireError( dispatch, error.message ); + } + } + + const deleteItem = async ( id ) => { + try { + sdk.setTable( "wedges" ); + const result = await sdk.callRestAPI( { id }, "DELETE" ); + setCurrentTableData( list => list.filter( x => Number( x.id ) !== Number( id ) ) ); + } catch ( err ) { + throw new Error( err ); + } + + } + + const onSubmit = ( data ) => { + + let category = getNonNullValue( data.category ); + let material = getNonNullValue( data.material ); + let filter = { + + category: category, + material: material, + + }; + getData( 1, pageSize, filter ); + }; + + React.useEffect( () => { + globalDispatch( { + type: "SETPATH", + payload: { + path: "wedges", + }, + } ); + + ( async function () { + await getData( 1, pageSize ); + } )(); + }, [] ); + + return ( + <> +
+

Wedges Search

+
+ +
+ + +

+ { errors.category?.message } +

+
+ +
+ + +

+ { errors.material?.message } +

+
+ +
+ +
+ +
+
+

Wedges

+ +
+
+ + + + { columns.map( ( column, i ) => ( + + ) ) } + + + + { currentTableData.map( ( row, i ) => { + return ( + + { columns.map( ( cell, index ) => { + if ( cell.accessor == "" ) { + return ( + + ); + } + if ( cell.mappingExist ) { + return ( + + ); + } + return ( + + ); + } ) } + + ); + } ) } + +
onSort( i ) } + > + { column.header } + + { column.isSorted + ? column.isSortedDesc + ? " â–¼" + : " â–²" + : "" } + +
+ + + + + { cell.mappings[ row[ cell.accessor ] ] } + + { [ "image", "top_view" ].includes( cell.accessor ) ? : row[ cell.accessor ] } +
+
+
+ + + ); +}; + +export default AdminWedgesListPage; diff --git a/src/pages/admin/View/ViewAdminAccessoriesPage.jsx b/src/pages/admin/View/ViewAdminAccessoriesPage.jsx new file mode 100644 index 0000000..89fbaaa --- /dev/null +++ b/src/pages/admin/View/ViewAdminAccessoriesPage.jsx @@ -0,0 +1,78 @@ +import React from "react"; +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const ViewAdminAccessoriesPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const { dispatch } = React.useContext(GlobalContext); + const [viewModel, setViewModel] = React.useState({}); + + const params = useParams(); + + React.useEffect(function () { + (async function () { + try { + sdk.setTable("accessories"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setViewModel(result.model); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + return ( +
+

View Accessories

+ +
+
+
Name
+
{viewModel?.name}
+
+
+ +
+
+
Length
+
{viewModel?.length}
+
+
+ +
+
+
Width
+
{viewModel?.width}
+
+
+ +
+
+
Thumbnail
+
+ View +
+
+
+ +
+
+
Top View
+
+ View +
+
+
+
+ ); +}; + +export default ViewAdminAccessoriesPage; diff --git a/src/pages/admin/View/ViewAdminAnalyticLogPage.jsx b/src/pages/admin/View/ViewAdminAnalyticLogPage.jsx new file mode 100644 index 0000000..26ee598 --- /dev/null +++ b/src/pages/admin/View/ViewAdminAnalyticLogPage.jsx @@ -0,0 +1,104 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); + +const ViewAdminAnalyticLogPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "analytic_log" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View AnalyticLog

+ + +
+
+
User Id
+
{ viewModel?.user_id }
+
+
+ +
+
+
Url
+
{ viewModel?.url }
+
+
+ +
+
+
Path
+
{ viewModel?.path }
+
+
+ +
+
+
Hostname
+
{ viewModel?.hostname }
+
+
+ +
+
+
Ip
+
{ viewModel?.ip }
+
+
+ +
+
+
Role
+
{ viewModel?.role }
+
+
+ +
+
+
Browser
+
{ viewModel?.browser }
+
+
+ +
+
+
Country
+
{ viewModel?.country }
+
+
+ + + + +
+ ); +}; + +export default ViewAdminAnalyticLogPage; diff --git a/src/pages/admin/View/ViewAdminBoatLiftsPage.jsx b/src/pages/admin/View/ViewAdminBoatLiftsPage.jsx new file mode 100644 index 0000000..8348107 --- /dev/null +++ b/src/pages/admin/View/ViewAdminBoatLiftsPage.jsx @@ -0,0 +1,109 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); +const no_of_cylindersMapping = { '2': 2, '4': 4 } + +const ViewAdminBoatLiftsPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "boat_lifts" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View BoatLifts

+ + +
+
+
Model
+
{ viewModel?.model }
+
+
+ +
+
+
Weight Capacity
+
{ viewModel?.weight_capacity }
+
+
+ +
+
+
Lift Range
+
{ viewModel?.lift_range }
+
+
+ +
+
+
No Of Cylinders
+
{ no_of_cylindersMapping[ viewModel?.no_of_cylinders ] }
+
+
+ +
+
+
Length
+
{ viewModel?.length }
+
+
+ +
+
+
Width
+
{ viewModel?.width }
+
+
+ +
+
+
Image
+
+ View +
+
+
+ +
+
+
Top View
+
+ View +
+
+
+ + + + +
+ ); +}; + +export default ViewAdminBoatLiftsPage; diff --git a/src/pages/admin/View/ViewAdminDealersPage.jsx b/src/pages/admin/View/ViewAdminDealersPage.jsx new file mode 100644 index 0000000..876f1a2 --- /dev/null +++ b/src/pages/admin/View/ViewAdminDealersPage.jsx @@ -0,0 +1,63 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const ViewAdminDealersPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "dealers" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View Dealers

+ + +
+
+
Name
+
{ viewModel?.name }
+
+
+ +
+
+
Address
+
{ viewModel?.address }
+
+
+ + + + +
+ ); +}; + +export default ViewAdminDealersPage; diff --git a/src/pages/admin/View/ViewAdminDocksPage.jsx b/src/pages/admin/View/ViewAdminDocksPage.jsx new file mode 100644 index 0000000..830a4be --- /dev/null +++ b/src/pages/admin/View/ViewAdminDocksPage.jsx @@ -0,0 +1,94 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import { categoryMapping, materialsMapping } from 'Utils/constants'; + + +let sdk = new MkdSDK(); + +const ViewAdminDocksPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "docks" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View Docks

+ + +
+
+
Category
+
{ categoryMapping[ viewModel?.category ] }
+
+
+ +
+
+
Materials
+
{ materialsMapping[ viewModel?.materials ] }
+
+
+ +
+
+
Length
+
{ viewModel?.length }
+
+
+ +
+
+
Width
+
{ viewModel?.width }
+
+
+ +
+
+
Image
+
+ View +
+
+
+ +
+
+
Top View
+
+ View +
+
+
+ + + + +
+ ); +}; + +export default ViewAdminDocksPage; diff --git a/src/pages/admin/View/ViewAdminInstructionsPage.jsx b/src/pages/admin/View/ViewAdminInstructionsPage.jsx new file mode 100644 index 0000000..f1a5909 --- /dev/null +++ b/src/pages/admin/View/ViewAdminInstructionsPage.jsx @@ -0,0 +1,56 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const ViewAdminInstructionsPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "instructions" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View Instructions

+ + +
+
+
Content
+
{ viewModel?.content }
+
+
+ + + + +
+ ); +}; + +export default ViewAdminInstructionsPage; diff --git a/src/pages/admin/View/ViewAdminQuotesMailRecipientsPage.jsx b/src/pages/admin/View/ViewAdminQuotesMailRecipientsPage.jsx new file mode 100644 index 0000000..a9a0b2e --- /dev/null +++ b/src/pages/admin/View/ViewAdminQuotesMailRecipientsPage.jsx @@ -0,0 +1,58 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; +import MkdSDK from "Utils/MkdSDK"; +import { useNavigate, useParams } from "react-router-dom"; +import { tokenExpireError } from "Src/authContext"; +import { GlobalContext, showToast } from "Src/globalContext"; +import { isImage } from "Utils/utils"; + +let sdk = new MkdSDK(); + +const ViewAdminQuotesMailRecipientsPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const { dispatch } = React.useContext(GlobalContext); + const [viewModel, setViewModel] = React.useState({}); + + + + const params = useParams(); + + React.useEffect(function () { + (async function () { + try { + sdk.setTable("quotes_mail_recipients"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + + setViewModel(result.model); + + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + return ( +
+

View QuotesMailRecipients

+ + +
+
+
Email
+
{viewModel?.email}
+
+
+ + + + +
+ ); +}; + +export default ViewAdminQuotesMailRecipientsPage; diff --git a/src/pages/admin/View/ViewAdminQuotesPage.jsx b/src/pages/admin/View/ViewAdminQuotesPage.jsx new file mode 100644 index 0000000..9c032fb --- /dev/null +++ b/src/pages/admin/View/ViewAdminQuotesPage.jsx @@ -0,0 +1,239 @@ +import React from 'react' +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; +import * as XLSX from "xlsx"; +import { DownloadIcon, Loader } from 'Assets/svgs'; +import { Table } from 'Components/Table'; +import { selectedItemsTableColumns } from 'Utils/constants'; +import { useCallback } from 'react'; +import { ViewDockImageModal } from 'Components/ViewDockImageModal'; + + +let sdk = new MkdSDK(); +const has_dealerMapping = { 0: 'No', 1: 'Yes' } +const dock_connectionMapping = { 0: 'Resting', 1: 'Bolted', 2: 'Other' } +const lake_bottomMapping = { 0: 'Rocky', 1: 'Silty', 2: 'Sandy' } +const will_dock_boatMapping = { 0: 'No', 1: 'Yes' } +const ViewAdminQuotesPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + const [ viewModelSelectedItems, setViewModelSelectedItems ] = React.useState( "" ); + const [ viewModelLoading, setViewModelLoading ] = React.useState( false ); + const [ viewDockImageModal, setViewDockImageModal ] = React.useState( false ); + const [ dockImage, setDockImage ] = React.useState( '' ); + + const params = useParams(); + + const viewDockImageModalOpen = useCallback( ( image ) => { + setDockImage( image ) + setViewDockImageModal( true ) + }, [ dockImage, viewDockImageModal ] ) + + const viewDockImageModalClose = useCallback( () => { + setViewDockImageModal( false ) + }, [ viewDockImageModal ] ) + + const fetchData = useCallback( () => { + + ( async function () { + try { + setViewModelLoading( true ) + sdk.setTable( "quotes" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + setViewModelSelectedItems( result.model.selected_items ) + setViewModelLoading( false ) + + } + } catch ( error ) { + setViewModelLoading( false ) + console.log( "error", error ) + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [ viewModelLoading, viewModel, viewModelSelectedItems ] ) + const onDownloadClick = () => { + const data = viewModel + data.selected_items = null + data.dock_image = null + const selectedItems = viewModelSelectedItems && ( String( viewModelSelectedItems ).startsWith( "[{\"" ) ) ? JSON.parse( viewModelSelectedItems ) : [] + console.log( selectedItems ) + // return + const workbook = XLSX.utils.book_new(); + const worksheet = XLSX.utils.json_to_sheet( [ data ] ); + XLSX.utils.book_append_sheet( workbook, worksheet, "Quotation" ); + if ( selectedItems.length ) { + const worksheet2 = XLSX.utils.json_to_sheet( selectedItems ); + XLSX.utils.book_append_sheet( workbook, worksheet2, "Selected Items" ); + } + //let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }); + //XLSX.write(workbook, { bookType: "xlsx", type: "binary" }); + XLSX.writeFile( workbook, "Paradise_dock_quotation.xlsx" ); + } + + React.useEffect( function () { + if ( !viewModel.first_name ) { + fetchData() + } + }, [] ); + return ( + <> + { viewModelLoading ? +
+ +
+ + : +
+
+ +

View Quotes

+
+ +
+
+ +
+
+
First Name
+
{ viewModel?.first_name }
+
+
+ +
+
+
Last Name
+
{ viewModel?.last_name }
+
+
+ +
+
+
Email
+
{ viewModel?.email }
+
+
+ +
+
+
Phone
+
{ viewModel?.phone }
+
+
+ +
+
+
Lake
+
{ viewModel?.lake }
+
+
+ +
+
+
City
+
{ viewModel?.city }
+
+
+ +
+
+
Has Dealer
+
{ has_dealerMapping[ viewModel?.has_dealer ] }
+
+
+ +
+
+
Dealer Id
+
{ viewModel?.dealer_id }
+
+
+ +
+
+
Dock Connection
+
{ dock_connectionMapping[ viewModel?.dock_connection ] }
+
+
+ +
+
+
Lake Bottom
+
{ lake_bottomMapping[ viewModel?.lake_bottom ] }
+
+
+ +
+
+
Will Dock Boat
+
{ will_dock_boatMapping[ viewModel?.will_dock_boat ] }
+
+
+ +
+
+
Comments
+
{ viewModel?.comments }
+
+
+ +
+
+
Country
+
{ viewModel?.country }
+
+
+ + + + +
+
+
Selected Items
+
+ + + {/*
{ viewModel?.selected_items }
*/ } + + + + } + + + ); +}; + +export default ViewAdminQuotesPage; diff --git a/src/pages/admin/View/ViewAdminRampsPage.jsx b/src/pages/admin/View/ViewAdminRampsPage.jsx new file mode 100644 index 0000000..81f1b76 --- /dev/null +++ b/src/pages/admin/View/ViewAdminRampsPage.jsx @@ -0,0 +1,97 @@ +import React from "react"; +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); +const categoryMapping = { + 0: "Pivot Ramp", + 1: "Truss Ramp", +}; +const materialMapping = { + 0: "Wood Grain", + 1: "Perforated", + 2: "Grey Aluminium", +}; +const ViewRampsPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const { dispatch } = React.useContext(GlobalContext); + const [viewModel, setViewModel] = React.useState({}); + + const params = useParams(); + + React.useEffect(function () { + (async function () { + try { + sdk.setTable("ramps"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setViewModel(result.model); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + return ( +
+

View Wedges

+ +
+
+
Category
+
{categoryMapping[viewModel?.category]}
+
+
+ +
+
+
Length
+
{viewModel?.length}
+
+
+ +
+
+
Width
+
{viewModel?.width}
+
+
+ +
+
+
Image
+ +
+
+ +
+
+
Top View
+ +
+
+ +
+
+
Material
+
{materialMapping[viewModel?.material]}
+
+
+
+ ); +}; + +export default ViewRampsPage; diff --git a/src/pages/admin/View/ViewAdminReferenceItemsPage.jsx b/src/pages/admin/View/ViewAdminReferenceItemsPage.jsx new file mode 100644 index 0000000..98e3787 --- /dev/null +++ b/src/pages/admin/View/ViewAdminReferenceItemsPage.jsx @@ -0,0 +1,82 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as yup from "yup"; + +import { useNavigate, useParams } from "react-router-dom"; +import { tokenExpireError } from "../authContext"; +import { GlobalContext, showToast } from "../globalContext"; +import MkdSDK from "Utils/MkdSDK"; + + +let sdk = new MkdSDK(); + +const ViewAdminReferenceItemsPage = () => { + const { dispatch: globalDispatch } = React.useContext( GlobalContext ); + + const { dispatch } = React.useContext( GlobalContext ); + const [ viewModel, setViewModel ] = React.useState( {} ); + + + + const params = useParams(); + + React.useEffect( function () { + ( async function () { + try { + sdk.setTable( "reference_items" ); + const result = await sdk.callRestAPI( { id: Number( params?.id ) }, "GET" ); + if ( !result.error ) { + + setViewModel( result.model ); + + } + } catch ( error ) { + console.log( "error", error ); + tokenExpireError( dispatch, error.message ); + } + } )(); + }, [] ); + return ( +
+

View ReferenceItems

+ + +
+
+
Name
+
{ viewModel?.name }
+
+
+ +
+
+
Length
+
{ viewModel?.length }
+
+
+ +
+
+
Width
+
{ viewModel?.width }
+
+
+ +
+
+
Image
+
+ View +
+
+
+ + + + +
+ ); +}; + +export default ViewAdminReferenceItemsPage; diff --git a/src/pages/admin/View/ViewAdminWedgesPage.jsx b/src/pages/admin/View/ViewAdminWedgesPage.jsx new file mode 100644 index 0000000..2917631 --- /dev/null +++ b/src/pages/admin/View/ViewAdminWedgesPage.jsx @@ -0,0 +1,98 @@ +import React from "react"; +import { useParams } from "react-router-dom"; + +import { GlobalContext } from "Src/globalContext"; +import { tokenExpireError } from "Src/authContext"; +import MkdSDK from "Utils/MkdSDK"; + +let sdk = new MkdSDK(); +const categoryMapping = { + 0: "Floating Dock", + 1: "Sectional Dock", + 2: "Roll-In Dock", +}; +const materialMapping = { + 0: "Wood Grain", + 1: "Perforated", + 2: "Grey Aluminium", +}; +const ViewAdminWedgesPage = () => { + const { dispatch: globalDispatch } = React.useContext(GlobalContext); + + const { dispatch } = React.useContext(GlobalContext); + const [viewModel, setViewModel] = React.useState({}); + + const params = useParams(); + + React.useEffect(function () { + (async function () { + try { + sdk.setTable("wedges"); + const result = await sdk.callRestAPI({ id: Number(params?.id) }, "GET"); + if (!result.error) { + setViewModel(result.model); + } + } catch (error) { + console.log("error", error); + tokenExpireError(dispatch, error.message); + } + })(); + }, []); + return ( +
+

View Wedges

+ +
+
+
Category
+
{categoryMapping[viewModel?.category]}
+
+
+ +
+
+
Length
+
{viewModel?.length}
+
+
+ +
+
+
Width
+
{viewModel?.width}
+
+
+ +
+
+
Image
+ +
+
+ +
+
+
Top View
+ +
+
+ +
+
+
Material
+
{materialMapping[viewModel?.material]}
+
+
+
+ ); +}; + +export default ViewAdminWedgesPage; diff --git a/src/pages/admin/index.js b/src/pages/admin/index.js new file mode 100644 index 0000000..e8dc1b9 --- /dev/null +++ b/src/pages/admin/index.js @@ -0,0 +1,60 @@ +export { default as AddAdminAccessoriesPage } from "./Add/AddAdminAccessoriesPage"; +export { default as AddAdminAnalyticLogPage } from "./Add/AddAdminAnalyticLogPage"; +export { default as AddAdminBoatLiftsPage } from "./Add/AddAdminBoatLiftsPage"; +export { default as AddAdminCmsPage } from "./Add/AddAdminCmsPage"; +export { default as AddAdminDealersPage } from "./Add/AddAdminDealersPage"; +export { default as AddAdminDocksPage } from "./Add/AddAdminDocksPage"; +export { default as AddAdminEmailPage } from "./Add/AddAdminEmailPage"; +export { default as AddAdminInstructionsPage } from "./Add/AddAdminInstructionsPage"; +export { default as AddAdminPhotoPage } from "./Add/AddAdminPhotoPage"; +export { default as AddAdminQuotesPage } from "./Add/AddAdminQuotesPage"; +export { default as AddAdminUserPage } from "./Add/AddAdminUserPage"; +export { default as AddAdminWedgesPage } from "./Add/AddAdminWedgesPage"; +export { default as AddAdminRampsPage } from "./Add/AddAdminRampsPage"; +export { default as AddAdminQuotesMailRecipientsPage } from "./Add/AddAdminQuotesMailRecipientsPage"; + +export { default as AdminAccessoriesListPage } from "./List/AdminAccessoriesListPage"; +export { default as AdminAnalyticLogListPage } from "./List/AdminAnalyticLogListPage"; +export { default as AdminBoatLiftsListPage } from "./List/AdminBoatLiftsListPage"; +export { default as AdminCmsListPage } from "./List/AdminCmsListPage"; +export { default as AdminDashboardPage } from "./AdminDashboardPage"; +export { default as AdminDealersListPage } from "./List/AdminDealersListPage"; +export { default as AdminDocksListPage } from "./List/AdminDocksListPage"; +export { default as AdminEmailListPage } from "./List/AdminEmailListPage"; +export { default as AdminForgotPage } from "./Auth/AdminForgotPage"; +export { default as AdminInstructionsListPage } from "./List/AdminInstructionsListPage"; +export { default as AdminPhotoListPage } from "./List/AdminPhotoListPage"; +export { default as AdminQuotesListPage } from "./List/AdminQuotesListPage"; +export { default as AdminUserListPage } from "./List/AdminUserListPage"; +export { default as AdminWedgesListPage } from "./List/AdminWedgesListPage"; +export { default as AdminRampsListPage } from "./List/AdminRampsListPage"; +export { default as AdminQuotesMailRecipientsListPage } from "./List/AdminQuotesMailRecipientsListPage"; + +export { default as EditAdminAccessoriesPage } from "./Edit/EditAdminAccessoriesPage"; +export { default as EditAdminAnalyticLogPage } from "./Edit/EditAdminAnalyticLogPage"; +export { default as EditAdminBoatLiftsPage } from "./Edit/EditAdminBoatLiftsPage"; +export { default as EditAdminCmsPage } from "./Edit/EditAdminCmsPage"; +export { default as EditAdminDealersPage } from "./Edit/EditAdminDealersPage"; +export { default as EditAdminDocksPage } from "./Edit/EditAdminDocksPage"; +export { default as EditAdminEmailPage } from "./Edit/EditAdminEmailPage"; +export { default as EditAdminInstructionsPage } from "./Edit/EditAdminInstructionsPage"; +export { default as EditAdminQuotesPage } from "./Edit/EditAdminQuotesPage"; +export { default as EditAdminUserPage } from "./Edit/EditAdminUserPage"; +export { default as EditAdminWedgesPage } from "./Edit/EditAdminWedgesPage"; +export { default as EditAdminRampsPage } from "./Edit/EditAdminRampsPage"; +export { default as EditAdminQuotesMailRecipientsPage } from "./Edit/EditAdminQuotesMailRecipientsPage"; + +export { default as ViewAdminAccessoriesPage } from "./View/ViewAdminAccessoriesPage"; +export { default as ViewAdminAnalyticLogPage } from "./View/ViewAdminAnalyticLogPage"; +export { default as ViewAdminBoatLiftsPage } from "./View/ViewAdminBoatLiftsPage"; +export { default as ViewAdminDealersPage } from "./View/ViewAdminDealersPage"; +export { default as ViewAdminDocksPage } from "./View/ViewAdminDocksPage"; +export { default as ViewAdminInstructionsPage } from "./View/ViewAdminInstructionsPage"; +export { default as ViewAdminQuotesPage } from "./View/ViewAdminQuotesPage"; +export { default as ViewAdminWedgesPage } from "./View/ViewAdminWedgesPage"; +export { default as ViewAdminRampsPage } from "./View/ViewAdminRampsPage"; +export { default as ViewAdminQuotesMailRecipientsPage } from "./View/ViewAdminQuotesMailRecipientsPage"; + +export { default as AdminLoginPage } from "./Auth/AdminLoginPage"; +export { default as AdminProfilePage } from "./Auth/AdminProfilePage"; +export { default as AdminResetPage } from "./Auth/AdminResetPage"; diff --git a/src/pages/dock/DockBuilderPage.jsx b/src/pages/dock/DockBuilderPage.jsx new file mode 100644 index 0000000..87dd492 --- /dev/null +++ b/src/pages/dock/DockBuilderPage.jsx @@ -0,0 +1,23 @@ +import React, { useContext } from 'react'; +import { Loader } from 'Assets/svgs'; +import { DockBuilder } from 'Components/DockBuilder'; +import { GlobalContext } from '../../globalContext'; + +export const DockBuilderPage = () => { + + const { state: { dockLoading } } = useContext( GlobalContext ) + + return ( +
+ { dockLoading ? +
+ +
+ : null + } + + + +
+ ) +} diff --git a/src/pages/dock/index.js b/src/pages/dock/index.js new file mode 100644 index 0000000..a7204fe --- /dev/null +++ b/src/pages/dock/index.js @@ -0,0 +1 @@ +export { DockBuilderPage } from './DockBuilderPage' \ No newline at end of file diff --git a/src/utils/DockBuilderUtils/clone.jsx b/src/utils/DockBuilderUtils/clone.jsx new file mode 100644 index 0000000..feaa9aa --- /dev/null +++ b/src/utils/DockBuilderUtils/clone.jsx @@ -0,0 +1,130 @@ +// import { useContext } from "react"; +// import { GlobalContext } from "../../globalContext"; +// import { scaleFactor, SnapType } from "../constants"; +import { SnapType } from "Utils/constants"; +import { reScaleXY, resolveHeight, resolveWidth } from "./edgeDetection"; +// const {state: {dockTop, dockLeft}, dispatch: GlobalDispatch} = useContext(GlobalContext) +export const clone = (selectedObj, editorMemo, detectedObj, dir) => { + const snapCloneFound = editorMemo.getObjects("image").find((o) => { + // console.log( o ) + + if (o.snapClone) { + return o; + } + }); + // console.log( snapCloneFound ) + if (snapCloneFound) { + return handlePosition( + dir, + detectedObj, + selectedObj, + snapCloneFound, + SnapType.SnapClone, + editorMemo + ); + } + + // console.log( "snapCloneFound skip" ) + selectedObj.clone(function (cloned) { + cloned.set({ + snapClone: true, + opacity: 0.02 + }); + + editorMemo.add(cloned).sendBackwards(cloned); + + editorMemo.getObjects("image").forEach((o) => { + if (o.snapClone) { + return handlePosition( + dir, + detectedObj, + selectedObj, + o, + SnapType.SnapClone, + editorMemo + ); + } + }); + }); +}; +export const clearClone = (editorMemo) => { + // return + // setTimeout( () => { + editorMemo.getObjects("image").forEach((o) => { + if (o.snapClone) { + editorMemo.remove(o); + } + }); + // }, 100 ) +}; + +export const handlePosition = ( + dir, + detectedObj, + selectedObj, + o, + objType, + editorMemo +) => { + // console.log( editorMemo ) + switch (dir) { + case "left": + o.left = detectedObj.left - reScaleXY(o, "width"); + if (objType === SnapType.Snap) { + // console.log( o ) + } + if (objType === SnapType.SnapClone) { + o.set({ + top: selectedObj.top + }); + } + editorMemo.renderAll(); + break; + case "right": + o.left = detectedObj.left + reScaleXY(detectedObj, "width"); + if (objType === SnapType.Snap) { + // console.log( o ) + } + if (objType === SnapType.SnapClone) { + o.set({ + top: selectedObj.top + }); + // o.top = selectedObj.top + } + editorMemo.renderAll(); + break; + + case "bottom": + o.top = detectedObj.top + reScaleXY(detectedObj, "height"); + if (objType === SnapType.Snap) { + // console.log( o ) + } + if (objType === SnapType.SnapClone) { + o.set({ + left: selectedObj.left + }); + } + editorMemo.renderAll(); + break; + + case "top": + o.top = detectedObj.top - reScaleXY(o, "height"); + if (objType === SnapType.Snap) { + // console.log( o ) + } + if (objType === SnapType.SnapClone) { + o.set({ + left: selectedObj.left + }); + } + editorMemo.renderAll(); + break; + } +}; + +// export const resolveTop = (o, detectedObj, objType) => { +// switch (objType) { +// case SnapType.SnapClone: + +// } +// } diff --git a/src/utils/DockBuilderUtils/edgeDetection.jsx b/src/utils/DockBuilderUtils/edgeDetection.jsx new file mode 100644 index 0000000..7bf22a0 --- /dev/null +++ b/src/utils/DockBuilderUtils/edgeDetection.jsx @@ -0,0 +1,170 @@ +import { edgeSnapThreshold } from "../constants"; +export const edgeDetection = (selectedObj, detectedObj, dir) => { + /** Function to determine the position of the selected dock */ + const isImageNotSnapClone = + !detectedObj.snapClone && ["image", "rect"].includes(detectedObj.type); + let isWithinSnapThreshold; + let isWithinTopRange; + let isWithinLeftRange; + + switch (dir) { + case "left": + isWithinSnapThreshold = + Math.abs( + resolveWidth(selectedObj) - detectedObj.getBoundingRect().left + ) < edgeSnapThreshold; + isWithinTopRange = compareTop(selectedObj, detectedObj); + return isWithinSnapThreshold && isWithinTopRange && isImageNotSnapClone; + + case "right": + isWithinSnapThreshold = + Math.abs( + resolveWidth(detectedObj) - selectedObj.getBoundingRect().left + ) < edgeSnapThreshold; + isWithinTopRange = compareTop(selectedObj, detectedObj); + return isWithinSnapThreshold && isWithinTopRange && isImageNotSnapClone; + + case "bottom": + isWithinSnapThreshold = + Math.abs( + Math.abs(selectedObj.getBoundingRect().top) - + resolveHeight(detectedObj) + ) < edgeSnapThreshold; + isWithinLeftRange = compareLeft(selectedObj, detectedObj, "bottom"); + return isWithinSnapThreshold && isWithinLeftRange && isImageNotSnapClone; + + case "top": + isWithinSnapThreshold = + Math.abs( + Math.abs(detectedObj.getBoundingRect().top) - + resolveHeight(selectedObj) + ) < edgeSnapThreshold; + isWithinLeftRange = compareLeft(selectedObj, detectedObj, "top"); + return isWithinSnapThreshold && isWithinLeftRange && isImageNotSnapClone; + + case "neutral": + return ( + !edgeDetection(selectedObj, detectedObj, "left") && + !edgeDetection(selectedObj, detectedObj, "right") && + !edgeDetection(selectedObj, detectedObj, "top") && + !edgeDetection(selectedObj, detectedObj, "bottom") + ); + } +}; + +export const handleIntersection = (selectedObj, detectedObj) => { + handleEdgeDetection(selectedObj, detectedObj); +}; + +export const handleEdgeDetection = (selectedObj, detectedObj) => { + if (edgeDetection(selectedObj, detectedObj, "left")) { + selectedObj.set({ + left: detectedObj.left - selectedObj.width, + }); + } + + if (edgeDetection(selectedObj, detectedObj, "right")) { + selectedObj.set({ + left: detectedObj.left + detectedObj.width, + }); + } + + if (edgeDetection(selectedObj, detectedObj, "top")) { + selectedObj.set({ + top: detectedObj.top - selectedObj.height, + }); + } + + if (edgeDetection(selectedObj, detectedObj, "bottom")) { + selectedObj.set({ + top: detectedObj.top + detectedObj.height, + }); + } +}; + +export const resolveWidth = (obj) => { + /** This Function add left position and width of dock to find the horizontal end of the dock */ + return Math.abs(obj.getBoundingRect().left + obj.getBoundingRect().width); +}; +export const resolveHeight = (obj) => { + /** This Function add top position and height of dock to find the vertical end of the dock */ + return Math.abs(obj.getBoundingRect().top + obj.getBoundingRect().height); +}; +export const reScaleXY = (obj, XY) => { + /** THis basically was to rescale the width or height of the dock but We are barely using this as the implementation has changed, we are not even rescaling in this function right now */ + switch (XY) { + case "width": + return obj.getBoundingRect().width; + case "height": + return obj.getBoundingRect().height; + } +}; + +export const compareTop = (selectedObj, detectedObj) => { + const detectedObjBound = detectedObj.getBoundingRect(); + const selectedObjBound = selectedObj.getBoundingRect(); + + return ( + Math.abs(selectedObjBound.top - detectedObjBound.top) < edgeSnapThreshold || + (selectedObjBound.top > detectedObjBound.top && + selectedObjBound.top < resolveHeight(detectedObj)) || + (selectedObjBound.top < detectedObjBound.top && + resolveHeight(selectedObj) > detectedObjBound.top) + ); +}; +export const compareLeft = (selectedObj, detectedObj, dir) => { + const detectedObjBound = detectedObj.getBoundingRect(); + const selectedObjBound = selectedObj.getBoundingRect(); + + switch (dir) { + case "top": + return ( + Math.abs(selectedObjBound.left - detectedObjBound.left) < + edgeSnapThreshold || + (selectedObjBound.left > detectedObjBound.left && + selectedObjBound.left <= resolveWidth(detectedObj) && + detectedObjBound.top > resolveHeight(selectedObj)) || + (selectedObjBound.left < detectedObjBound.left && + resolveWidth(selectedObj) > detectedObjBound.left) + ); + case "bottom": + return ( + Math.abs(selectedObjBound.left - detectedObjBound.left) < + edgeSnapThreshold || + (selectedObjBound.left > detectedObjBound.left && + selectedObjBound.left <= resolveWidth(detectedObj) && + selectedObj.top > resolveHeight(detectedObj) && + selectedObjBound.top - resolveHeight(detectedObj) < + edgeSnapThreshold) || + (selectedObjBound.left < detectedObjBound.left && + resolveWidth(selectedObj) > detectedObjBound.left) + ); + } +}; + +export const boatLiftLeft = (boatLiftObj, detectedObj) => { + const boatLiftWidth = reScaleXY(boatLiftObj, "width"); + const detectedObjWidth = reScaleXY(detectedObj, "width"); + if (boatLiftWidth > detectedObjWidth) { + const leftToSet = (boatLiftWidth - detectedObjWidth) / 2; + return detectedObj.left - leftToSet; + } else if (detectedObjWidth > boatLiftWidth) { + const leftToSet = (detectedObjWidth - boatLiftWidth) / 2; + return detectedObj.left + leftToSet; + } else { + return detectedObj.left; + } +}; +export const boatLiftTop = (boatLiftObj, detectedObj) => { + const boatLiftHeight = reScaleXY(boatLiftObj, "height"); + const detectedObjHeight = reScaleXY(detectedObj, "height"); + if (boatLiftHeight > detectedObjHeight) { + const topToSet = (boatLiftHeight - detectedObjHeight) / 2; + return detectedObj.top - topToSet; + } else if (detectedObjHeight > boatLiftHeight) { + const topToSet = (detectedObjHeight - boatLiftHeight) / 2; + return detectedObj.top + topToSet; + } else { + return detectedObj.top; + } +}; diff --git a/src/utils/DockBuilderUtils/index.js b/src/utils/DockBuilderUtils/index.js new file mode 100644 index 0000000..d412d75 --- /dev/null +++ b/src/utils/DockBuilderUtils/index.js @@ -0,0 +1,6 @@ +export { clearClone, clone } from "./clone" +export { + edgeDetection, + handleIntersection, + handleEdgeDetection +} from "./edgeDetection" \ No newline at end of file diff --git a/src/utils/MkdSDK.jsx b/src/utils/MkdSDK.jsx new file mode 100644 index 0000000..ff6e5eb --- /dev/null +++ b/src/utils/MkdSDK.jsx @@ -0,0 +1,1763 @@ +export default function MkdSDK() { + // this._baseurl = "https://paradisedocklift.manaknightdigital.com"; + // this._baseurl = "https://app.paradisedocklift.com"; + // this._baseurl = "http://localhost:3048"; + this._project_id = "paralift"; + this._secret = "grljhaqkwmb6cbadsabuj6ysla302xnxi"; + //this._project_id = "manaknight"; + //this._secret = "grljhaqkwmb6cbadsabuj6ysla302xnxi"; + this.fe_baseurl = "http://localhost:3000"; + // this._baseurl = "http://localhost:3048"; + // this._baseurl = "https://paradisedocklift.mkdlabs.com"; + this._baseurl = "https://paralift.mkdlabs.com"; + // this._project_id = "paralift"; + // this._secret = "grljhaqkwmb6cbadsabuj6ysla302xnxi"; + // this._project_id = "manaknight"; + // this._secret = "grljhaqkwmb6cbadsabuj6ysla302xnxi"; + // this.fe_baseurl = "http://localhost:3000"; + // this._project_id = "localproject"; + // this._secret = "ok5pdxzobdk9so4sgke7ie9zgmyxqmpu"; + + this._table = ""; + this._custom = ""; + this._method = ""; + + const raw = this._project_id + ":" + this._secret; + let base64Encode = btoa(raw); + + this.getItems = async (table) => { + const result = await fetch( + this._baseurl + `/v3/api/custom/paradisedock/${table}`, + { + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + } + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.requestQuote = async (Quotebody) => { + const result = await fetch( + this._baseurl + `/v3/api/custom/paradisedock/quotes`, + { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + }, + body: JSON.stringify(Quotebody) + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.login = async function (email, password, role) { + const result = await fetch(this._baseurl + "/v2/api/lambda/login", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + }, + body: JSON.stringify({ + email, + password, + role + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.getHeader = function () { + return { + Authorization: "Bearer " + localStorage.getItem("token"), + "x-project": base64Encode + }; + }; + + this.baseUrl = function () { + return this._baseurl; + }; + this.uploadUrl = function () { + return this._baseurl + "/v2/api/lambda/upload"; + }; + + this.upload = async function (file) { + let formData = new FormData(); + formData.append("file", file); + + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const uploadResult = await fetch(this._baseurl + `/v2/api/lambda/upload`, { + method: "post", + headers: header, + body: formData + }).then((res) => res.json()); + return uploadResult; + }; + this.getProfile = async function () { + const result = await fetch(this._baseurl + "/v2/api/lambda/profile", { + method: "get", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.check = async function (role) { + const result = await fetch(this._baseurl + "/v2/api/lambda/check", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + role + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + return json; + }; + + this.getProfilePreference = async function () { + const result = await fetch(this._baseurl + "/v2/api/lambda/preference", { + method: "get", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // update email + this.updateEmail = async function (email) { + const result = await fetch(this._baseurl + "/v2/api/lambda/update/email", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + email + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // update password + this.updatePassword = async function (password) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/update/password", + { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + password + }) + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // update email + this.updateEmailByAdmin = async function (email, id) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/admin/update/email", + { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + email, + id + }) + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // update password + this.updatePasswordByAdmin = async function (password, id) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/admin/update/password", + { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + password, + id + }) + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.sendEmailVerification = function () {}; + this.updateEmailVerification = function () {}; + + this.setTable = function (table) { + this._table = table; + }; + + this.getProjectId = function () { + return this._project_id; + }; + + this.logout = function () { + window.localStorage.clear(); + }; + + this.register = async function (email, password, role) { + const result = await fetch(this._baseurl + "/v2/api/lambda/register", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + }, + body: JSON.stringify({ + email, + password, + role + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.createUser = async function (email, password, role) { + const result = await fetch(this._baseurl + "/v2/api/lambda/register", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + email, + password, + role + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.forgot = async function (email) { + const result = await fetch(this._baseurl + "/v2/api/lambda/forgot", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + }, + body: JSON.stringify({ + email + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.reset = async function (token, code, password) { + const result = await fetch(this._baseurl + "/v2/api/lambda/reset", { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode + }, + body: JSON.stringify({ + token, + code, + password + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.callRestAPI = async function (payload, method) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + switch (method) { + case "GET": + const getResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/GET`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonGet = await getResult.json(); + + if (getResult.status === 401) { + throw new Error(jsonGet.message); + } + + if (getResult.status === 403) { + throw new Error(jsonGet.message); + } + return jsonGet; + case "POST": + const insertResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonInsert = await insertResult.json(); + + if (insertResult.status === 401) { + throw new Error(jsonInsert.message); + } + + if (insertResult.status === 403) { + throw new Error(jsonInsert.message); + } + return jsonInsert; + case "PUT": + const updateResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonUpdate = await updateResult.json(); + + if (updateResult.status === 401) { + throw new Error(jsonUpdate.message); + } + + if (updateResult.status === 403) { + throw new Error(jsonUpdate.message); + } + return jsonUpdate; + + // Part: Update Table Without Using ID + case "PUTWHERE": + const updateWhereRes = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) // Note: payload: {set: {[string]: any}, where: {[string]: any}} + } + ); + const jsonUpdateWhereRes = await updateWhereRes.json(); + + if (updateWhereRes.status === 401) { + throw new Error(jsonUpdateWhereRes.message); + } + + return jsonUpdateWhereRes; + + case "DELETE": + const deleteResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonDelete = await deleteResult.json(); + + if (deleteResult.status === 401) { + throw new Error(jsonDelete.message); + } + + if (deleteResult.status === 403) { + throw new Error(jsonDelete.message); + } + return jsonDelete; + case "DELETEALL": + const deleteAllResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonDeleteAll = await deleteAllResult.json(); + + if (deleteAllResult.status === 401) { + throw new Error(jsonDeleteAll.message); + } + + if (deleteAllResult.status === 403) { + throw new Error(jsonDeleteAll.message); + } + return jsonDeleteAll; + case "GETALL": + const getAllResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonGetAll = await getAllResult.json(); + + if (getAllResult.status === 401) { + throw new Error(jsonGetAll.message); + } + + if (getAllResult.status === 403) { + throw new Error(jsonGetAll.message); + } + return jsonGetAll; + case "PAGINATE": + if (!payload.page) { + payload.page = 1; + } + if (!payload.limit) { + payload.limit = 10; + } + const paginateResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonPaginate = await paginateResult.json(); + + if (paginateResult.status === 401) { + throw new Error(jsonPaginate.message); + } + + if (paginateResult.status === 403) { + throw new Error(jsonPaginate.message); + } + return jsonPaginate; + case "AUTOCOMPLETE": + const autocompleteResult = await fetch( + this._baseurl + `/v1/api/rest/${this._table}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonAutocomplete = await autocompleteResult.json(); + + if (autocompleteResult.status === 401) { + throw new Error(jsonAutocomplete.message); + } + + if (autocompleteResult.status === 403) { + throw new Error(jsonAutocomplete.message); + } + return jsonAutocomplete; + default: + break; + } + }; + + this.callRawAPI = async function (uri, payload, method) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const result = await fetch(this._baseurl + uri, { + method: method, + headers: header, + body: JSON.stringify(payload) + }); + const jsonResult = await result.json(); + + if (result.status === 401) { + throw new Error(jsonResult.message); + } + + if (result.status === 403) { + throw new Error(jsonResult.message); + } + return jsonResult; + }; + + // Part: Get All Data by Joining Two Columns + this.callJoinRestAPI = async function ( + table1, + table2, + join_id_1, + join_id_2, + select, + where, + method, + page, + limit + ) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + switch (method) { + case "GETALL": + const result = await fetch( + this._baseurl + `/v1/api/join/${table1}/${table2}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify({ + join_id_1, // "tableName1" + join_id_2, // "tableName2" + select, // "tableName1.field1, tableName2.field2" + where: where || "" // where: ["status=2424", "id=1"] + }) + } + ); + const jsonResult = await result.json(); + + if (result.status === 401) { + throw new Error(jsonResult.message); + } + + if (result.status === 403) { + throw new Error(jsonResult.message); + } + return jsonResult; + + case "PAGINATE": + if (!page) { + page = 1; + } + if (!limit) { + limit = 10; + } + const paginateResult = await fetch( + this._baseurl + `/v1/api/join/${table1}/${table2}/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify({ + join_id_1, // "tableName1" + join_id_2, // "tableName2" + select, // "tableName1.field1, tableName2.field2" + where: where || "", // where: ["status=2424", "id=1"] + page, + limit + }) + } + ); + const jsonPaginate = await paginateResult.json(); + + if (paginateResult.status === 401) { + throw new Error(jsonPaginate.message); + } + + if (paginateResult.status === 403) { + throw new Error(jsonPaginate.message); + } + return jsonPaginate; + + default: + break; + } + }; + + // Part: Get Data by Joining Multiple Columns with Pagination + this.callMultiJoinRestAPI = async function ( + tables, + joinIds, + selectStr, + where, + page, + limit, + method + ) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + if (!page) { + page = 1; + } + if (!limit) { + limit = 10; + } + const paginateResult = await fetch( + this._baseurl + `/v1/api/multi-join/${method}`, + { + method: "post", + headers: header, + body: JSON.stringify({ + tables, // ["tableName1", "tableName2"] + joinIds, // ["tableName1.id", "tableName2.id"] + selectStr, // "tableName1.field1, tableName2.field2" + where, // ["status=2424", "id=1"] + page, + limit + }) + } + ); + const jsonPaginate = await paginateResult.json(); + + if (paginateResult.status === 401) { + throw new Error(jsonPaginate.message); + } + + if (paginateResult.status === 403) { + throw new Error(jsonPaginate.message); + } + return jsonPaginate; + }; + + this.subscribe = function (payload) {}; + this.subscribeChannel = function (channel, payload) {}; + this.subscribeListen = function (channel) {}; + this.unSubscribeChannel = function (channel, payload) {}; + this.broadcast = function (payload) {}; + this.exportCSV = function (payload) {}; + + this.cmsAdd = async function (page, key, type, value) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const insertResult = await fetch(this._baseurl + `/v2/api/lambda/cms`, { + method: "post", + headers: header, + body: JSON.stringify({ + page, + key, + type, + value + }) + }); + const jsonInsert = await insertResult.json(); + + if (insertResult.status === 401) { + throw new Error(jsonInsert.message); + } + + if (insertResult.status === 403) { + throw new Error(jsonInsert.message); + } + return jsonInsert; + }; + + this.cmsEdit = async function (id, page, key, type, value) { + const header = { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const updateResult = await fetch( + this._baseurl + `/v2/api/lambda/cms/` + id, + { + method: "put", + headers: header, + body: JSON.stringify({ + page, + key, + type, + value + }) + } + ); + const jsonInsert = await updateResult.json(); + + if (updateResult.status === 401) { + throw new Error(jsonInsert.message); + } + + if (updateResult.status === 403) { + throw new Error(jsonInsert.message); + } + return jsonInsert; + }; + + this.getToken = function () { + return window.localStorage.getItem("token"); + }; + + // get chat room + this.getMyRoom = async function () { + const result = await fetch( + this._baseurl + "/v3/api/lambda/realtime/room/my", + { + method: "GET", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + } + ); + + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // get chat id + this.getChatId = async function (room_id) { + const result = await fetch( + this._baseurl + `/v2/api/lambda/room?room_id=${room_id}`, + { + method: "get", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + } + ); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // post chat + this.getChats = async function (room_id, chat_id, date) { + const result = await fetch(this._baseurl + `/v3/api/lambda/realtime/chat`, { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + room_id, + chat_id, + date + }) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.restoreChat = async function (room_id) { + await fetch( + this._baseurl + `/v2/api/lambda/v2/api/lambda/room/poll?room=${room_id}`, + { + method: "get", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + } + ); + }; + + // post a new message + this.postMessage = async function (messageDetails) { + const result = await fetch(this._baseurl + `/v3/api/lambda/realtime/send`, { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(messageDetails) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.uploadImage = async function (file) { + const result = await fetch(this._baseurl + `/v2/api/lambda/s3/upload`, { + method: "post", + headers: { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: file + }); + + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.createRoom = async function (roomDetails) { + const result = await fetch(this._baseurl + `/v3/api/lambda/realtime/room`, { + method: "post", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(roomDetails) + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + this.getAllUsers = async function () { + const result = await fetch(this._baseurl + `/v1/api/rest/user/GETALL`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + }); + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + // start pooling + this.startPooling = async function (user_id) { + const result = await fetch( + this._baseurl + `/v3/api/lambda/realtime/room/poll?user_id=${user_id}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + } + } + ); + + const json = await result.json(); + + if (result.status === 401) { + throw new Error(json.message); + } + + if (result.status === 403) { + throw new Error(json.message); + } + return json; + }; + + /** + * start stripe functions + */ + + this.addStripeProduct = async function (data) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/stripe/product", + { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.getStripeProducts = async function (paginationParams, filterParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/products?${paginationQuery}&${filterQuery}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getStripeProduct = async function (id) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/product/${id}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.updateStripeProduct = async function (id, payload) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/product/${id}`, + { + method: "put", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.addStripePrice = async function (data) { + const result = await fetch(this._baseurl + "/v2/api/lambda/stripe/price", { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + }); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.getStripePrices = async function (paginationParams, filterParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/prices?${paginationQuery}&${filterQuery}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getStripePrice = async function (id) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/price/${id}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.updateStripePrice = async function (id, payload) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/price/${id}`, + { + method: "put", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getStripeSubscriptions = async function ( + paginationParams, + filterParams + ) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/subscriptions?${paginationQuery}&${filterQuery}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.adminCancelStripeSubscription = async function (subId, data) { + const result = await fetch( + this._baseurl + `/v2/api/lambda/stripe/subscription/${subId}`, + { + method: "delete", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + + return json; + }; + + this.adminCreateUsageCharge = async function (subId, quantity) { + const result = await fetch( + this._baseurl + `/v2/api/lambda/stripe/subscription/usage-charge`, + { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify({ + subId, + quantity + }) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + + return json; + }; + + this.getStripeInvoices = async function (paginationParams, filterParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/invoices?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + this.getStripeInvoicesV2 = async function (paginationParams, filterParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/invoices-v2?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getStripeOrders = async function (paginationParams, filterParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/orders?${paginationQuery}&${filterQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + /** + * ------------------------------------------------------- + */ + + this.initCheckoutSession = async function (data) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/stripe/checkout", + { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.registerAndSubscribe = async function (data) { + /** + * + * @param {object} data {email, password, cardToken, planId} + * @returns + */ + const result = await fetch( + this._baseurl + "/v2/api/lambda/stripe/customer/register-subscribe", + { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.createStripeCustomer = async function (payload) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.createCustomerStripeCard = async function (payload) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer/card`, + { + method: "post", + headers: header, + body: JSON.stringify(payload) + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.createStripeSubscription = async function (data) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/stripe/customer/subscription", + { + method: "post", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.getCustomerStripeSubscription = async function (userId) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer/subscription`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getCustomerStripeSubscriptions = async function ( + paginationParams, + filterParams + ) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const filterQuery = new URLSearchParams(filterParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/customer/subscriptions?${paginationQuery}&${filterQuery}`, + { + method: "get", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.changeStripeSubscription = async function (data) { + const result = await fetch( + this._baseurl + "/v2/api/lambda/stripe/customer/subscription", + { + method: "put", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.cancelStripeSubscription = async function (subId, data) { + const result = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer/subscription/${subId}`, + { + method: "delete", + headers: { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }, + body: JSON.stringify(data) + } + ); + + const json = await result.json(); + if ([401, 403, 500].includes(result.status)) { + throw new Error(json.message); + } + return json; + }; + + this.getCustomerStripeDetails = async function () { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getCustomerStripeCards = async function (paginationParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer/cards?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getCustomerStripeInvoices = async function (paginationParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/customer/invoices?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getCustomerStripeCharges = async function (paginationParams) { + const header = { + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const paginationQuery = new URLSearchParams(paginationParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/customer/charges?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.getCustomerStripeOrders = async function (paginationParams) { + const header = { + Authorization: "Bearer " + localStorage.getItem("token"), + "x-project": base64Encode + }; + const paginationQuery = new URLSearchParams(paginationParams); + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/customer/orders?${paginationQuery}`, + { + method: "get", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.projectHealth = async function () { + const header = { + "x-project": base64Encode + }; + + const getResult = await fetch( + this._baseurl + `/v3/api/custom/paradisedock/health`, + { + method: "GET", + headers: header + } + ); + + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.setStripeCustomerDefaultCard = async function (cardId) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + + `/v2/api/lambda/stripe/customer/card/${cardId}/set-default`, + { + method: "put", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + this.deleteCustomerStripeCard = async function (cardId) { + const header = { + "content-Type": "application/json", + "x-project": base64Encode, + Authorization: "Bearer " + localStorage.getItem("token") + }; + const getResult = await fetch( + this._baseurl + `/v2/api/lambda/stripe/customer/card/${cardId}`, + { + method: "delete", + headers: header + } + ); + const jsonGet = await getResult.json(); + + if ([401, 403, 500].includes(getResult.status)) { + throw new Error(jsonGet.message); + } + + return jsonGet; + }; + + /** end stripe functions */ + return this; +} diff --git a/src/utils/constants/constants.jsx b/src/utils/constants/constants.jsx new file mode 100644 index 0000000..6129a0f --- /dev/null +++ b/src/utils/constants/constants.jsx @@ -0,0 +1,110 @@ +export const TabNames = { + Builder: "Builder", + SelectedItems: "Selected Items", +}; + +export const CanvasModes = { + Pan: "Pan", + Still: "Still", +}; + +export const DockPanelCategories = { + RollIn: "ROLL-IN", + Floating: "FLOATING", + Sectional: "SECTIONAL", + Wedges: "WEDGES", + Ramps: "RAMPS", + BoatLift2: "BOAT LIFTS (2 CYLINDER)", + BoatLift4: "BOAT LIFTS (4 CYLINDER)", + Accessories: "ACCESSORIES", +}; +export const Tables = { + Docks: "docks", + Boat_lifts: "boat_lifts", + Accessories: "accessories", + Wedges: "wedges", + Ramps: "ramps", + ReferenceItems: "reference_items", + Dealers: "dealers", + Quotes: "quotes", +}; +export const BoatLiftRange = ["4", "5", "6"]; + +export const categoryMapping = { + 0: "Floating Dock", + 1: "Sectional Dock", + 2: "Roll-In Dock", +}; +export const wedgesCategoryMapping = { + 0: "Floating Wedges", + 1: "Roll-In Wedges", +}; +export const rampsCategoryMapping = { + 0: "Pivot Ramp", + 1: "Truss Ramp", +}; +export const materialsMapping = { + 0: "Wood Grain", + 1: "Perforated", + 2: "Grey Aluminium", +}; +export const wedgesAndRampsMaterialsMapping = { + 0: "Wood Grain", + 1: "Grey Aluminium", + 2: "Perforated", +}; + +export const MaterialType = { + Woodgrain: 0, + Perforated: 1, + Gray: 2, +}; +export const DockPanelCategoryMap = { + Floating: 0, + Sectional: 1, + RollIn: 2, +}; +export const CylinderType = { + "BOAT LIFTS (2 CYLINDER)": 2, + "BOAT LIFTS (4 CYLINDER)": 4, +}; +export const EstimateSteps = { + ContactInformation: 1, + LakeSurrounding: 2, + Comments: 3, + InquirySubmitted: 4, +}; +// export const IsDealer = { +// YES: "Yes", +// NO: "No", +// } +export const Truthy = { + True: true, + False: false, +}; +export const SnapType = { + Snap: "Snap", + SnapClone: "SnapClone", +}; +export const scaleFactor = 0.2; +export const oneFeet = 303 * scaleFactor; +// export const edgeSnapThreshold = 100 +export const edgeSnapThreshold = 15; +export const nintyDeg = 90; +export const fortyFiveDeg = 45; +export const twoSeventyDeg = 270; +export const threeFifteenDeg = 315; +export const oneEightyDeg = 180; +export const twoTwentyFiveDeg = 225; +export const onThirtyFiveDeg = 135; +// export const edgeSnapThreshold = 100 / 1.889 +export const deleteIcon = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAA+VBMVEVHcEz/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////NhAsAAAAUnRSTlMAEnBvAv4H0xYGExTPXPBgn4QeVvb13s5eXWfNe57xZVT0M3ZYlwgwNDLg0d1aX2FbIKZ6px+F0sx9gqmoeFdzmJqUnZWZ4dBm8hliZJxjfNcVFGav3QAAATZJREFUKM91kmdjgjAQhqMyRBFQUMSFo9Y6a622ru692/f//5gmARFpvQ9cLk9yee84QjZ2UsoaRrY0IxETRip8sx0hTI7OAW1S0fXKVAP6zS05sDAYKt5ayRRgXQZExL2yPSi1IZp+NgtXuy+3kO9yBSpuo6ra6DMtIxSUKFIGyFCnYsiiWCLNXDoRY85BmVYKjV+KQ04SkpQR51JqYo6UMOE5UjJllMgpHq7hkjOcevnZtsyvMqsgS6o4JgELCHlDNYR+aLe+X/3gEx/7En7RhM+Y/idjhXcy2y+e2LzwSMlFzPn3b6MOexiz9tq4i6JrPPFf3cyjtUsu0Oh4K1PEgxTKdgOxvgnMPHqOD6XiIxr17cEunafaeqHri9ULUO7sDFum7M+aOB8LUVU5d2kYSzcXbPwCfA4wgva2ZmUAAAAASUVORK5CYII="; +// export const deleteIcon = "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E"; + +export const rotateIcon = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAeCAMAAAAfOR5kAAABJlBMVEVHcEz///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+w8PQxAAAAYXRSTlMAAQnFCtXWJwj3/NLyWEH1K/YZ3LXxDkX+YpQwpgZMBfCNdFpuiw+ezGeqFhqZ6yaXICUL+NnjQ5KbI5yCxgMSOVx/1Mhv76tmLP0tt+oMXsrP3q/TFJ+aR49PDcmA+gfk0N+uwAAAAOZJREFUKM9t0NdSAkEQheEhLMsSJZkDJsScc0DAHFAxgNn//V/CQmzKcrovpk59cy6mx5j2FPxGmXIsYGPtCbYs7XogdWzpTRLn8j+W7uHq0epWac317eleIvyH97m4q3s/d97USod3cpwZkz6MTxYjROaD4nFS5+20vLRG1BXfxZGOG2Vh8TcHHbalspolMyvrJBkX9weYkTxNfkjyXIxNyaODvs7TxjjSPjN8gqt5g3eNX8hq7JLR+JMPjV/JaZzmS+MEbxpXeFbUt05T4WE2DpTdQ0wo5X5CI7Z293oD2jv6elrnN1VOI4sPCr1mAAAAAElFTkSuQmCC"; +// export const rotateIcon = +// "data:image/svg+xml,%3Csvg height='32px' width='32px' fill='%23000000' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' x='0px' y='0px' viewBox='0 0 33.317 28' enable-background='new 0 0 33.317 28' xml:space='preserve'%3E%3Cpath d='M16.659,24c-5.078,0-9.213-3.987-9.475-9h2.975l-4.5-5l-4.5,5h3.025c0.264,6.671,5.74,12,12.475,12c3.197,0,6.104-1.21,8.315-3.185l-2.122-2.122C21.188,23.127,19.027,24,16.659,24z'%3E%3C/path%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M29.133,14c-0.265-6.669-5.74-12-12.475-12c-3.197,0-6.104,1.21-8.315,3.185l2.122,2.122C12.129,5.873,14.29,5,16.659,5c5.077,0,9.213,3.987,9.475,9h-2.975l4.5,5l4.5-5H29.133z'%3E%3C/path%3E%3C/svg%3E"; +export const dock_image = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAAXNSR0IArs4c6QAAEzdJREFUeF7tndF22zgMRNv//+jucZxdKwolXF6DsjedvgYCgcEMACqp/fvXr19/fr3o358/80f//v37S7QjH3ubF6V3eCzJ2+S5yu8okf1ZI8yreMgzr67ljW3zLG1iXAXg6BhDnKZw29yQvE2eq/xGIG2ln3NECrr3aIgzF9V6a5K3yXOV3whkPSeGJ5CCRiB3BMgqSfA0wotANggQkI2eyL5ZicGc2/mM2bvJDm3JX/kmfi35Ca4VXoRrhjckNrK+32y+3UFI0CYAk2hFABPHM89UBR91epIDITKx2edmnrE5GKERrhne2BqPzopAJtCMQCbAGqyFZL0jWwQR1lykd+sIxKB2sn6S7pYJ8gDwRwqEFNiMVzLKSacgJLW6sLnPnkfypDvz1q5rxSL5kDqsEoitE9kIyhVr5eFVgIQ4pDCkwIaA1i+5KxDfVW0ikHMUK/6hS3pVhKMQyOGVTQRyXuCqNhFIBDK8WBFhdXRo4oPY2HgjkOPLtcFdXdKrImSCkFLMdTLqsapNJsgc7v87gZDLP7k7WKJ03BUqEo9eVnzsvuKPMquV1eJpMd4/Z7Agd0zil+QegWxQMqCaVYicQwRsbOzZZIIRAUcgJ0iSbkZsTBcnxSPkMWd3kCIT5IFiJshkVyddPALhl1eCZ1asDQKmq9v9rioO6R5kHSA2XWeZyUTiMxibtWw0vWx85jnCP2JDziZ+3uoXhWQ9qURFgCEd8ejyXPmPQCqEzn9OSEtsSBTETwTyiWQmyPneTwjXYUNIS2xILMRPBBKBfOPSlVOwehFCGpeNNwIhbSQCiUBOOFBOkAmOnZqSTkDuIFXHGV0yuy6rpOMQvMw9ahV+5PJPcjLxvdIvvYdGIJ9IGRF1jfZVRHn3+FblTfxGIBsEDPnJJHp3Ar57fITIqyZTBBKBDP/SmZDyqhWQxPJ2AiFBd9lUO/2qzk+mA7EhxXulzU/Fr4t/xM9bfbKi+RORV5LgleS/FfdvbTCE2F02EUjzJb0iLSF2l80rm8fKCdxFfuInAolAvvHkqkluJzAhdpdNBBKBRCAnavr9x7yy6JKn8EO6294ted1pYLAdcNVZBE6Cn8Gr6xmDDcnb2kQgJxOkAjUCeSAUgVRsuejnpANmghwXg+DXRfZ9FOYFxkW0OjwmEyQTpLyDjNhDyP7XCuSqDvPy7gE+WcRMq6vyWvma1+RAppfxO3rGcHTox1zSzeHmmS6wrB9TUJKnjWf2uQjkHDHyQkCtWIQEHSN4lhDd9hHIHVFCJIK9wZP4zQSxKD35nCkoaR5PhoUfzwRpmCDmW25fOR0IAa+Kj8RCLri2A1aX4C6/V+aA1T9pqJtFBOLXiAjknKUWn0nuI/MIZANTJsgxZ7pIS+4lXWchBRRGEUgEgi7TXaSNQE4UeVWHtjv0VfFZsq0i1yq/uYNMzrCrCmHHIknHvKHa++0SCPmbLtIsTGO4kvyGN4QDpN7WRv25u0nUBEjAIbEYcpF4IxCC0sOG1Io0Lov7XLR36wjkEzVSvEyQBwKGpATjCGRCxpkgc69Rs2JNkAuafvtTE6Jg4tv4IV2JkIDYkBz2NsQv6ZJkEl15lsmzAz/jwz5DuDVcxfd/rGiI3bXjkyQMcYhfArw5m/gll3RiY8+KQI6RywQhrDq4p6wk7ZVijEAikAkZHJteSdorz4pAIpAI5BMBsm4ScRpAzf3MnENWfupXrVgEZBLAOxWiK6eqG99+bs4yb/TICkhsughHBEKwMbwhZ7dd0kkSEcgdAUJsg9VIaIQ4xiYC2SBA3mJFIITSEQiZpnsbwi0icnN2JsgJr0lhuCwelpkg51i8vUCq/zBlC0x2vmpa2f3YELnrGSM0g9Uo3i4/pvuSWhFszHTowmLI9QikSxp3P4QEXQRc5afLryG7eSYC2SBAumQv5ee8RSDHKxXBJgKZeCFAxvYcfddbExJ0dehVfrr8GrKbZzJBMkHQ6kam65UCNmQ3z1wqEBIgsSG9uioomSCm4BZQ8saFYFPlPbrLkGcI5gQvclb1gsXG0oWfqdUo5vJ70leStCrEyrPNGmFAJzkMCyM+F9iS0mARgXyiRgpMupLp2ivPNqSIQB4IRCARSNmQrYCryZkV61iIt58Q/EwzG05y8+nu5HDSoavJY4Ag68oIZEt2kmeFV9cvY01XJ3mXnUL+/odsFTa+ilvk7I9GFYHcoSKFIKATURMim7OI30qsnR2aCKtqMKQutClW8QwbVQQSgVQkrYh11GDIc9XZEcgJiqQbkyIQkK1NVWDS3bJiPVDqes1LJjCpXVasT5QikGOS2iZEnqtISupCmhCJBf2x4pUK7pgQBEBiQwDs6krkLGLTEY/FpuO+01F/gtORDcmh5ReFVsEdAJECExsCdAchyTnUpiMeiw0h1z4P8wzFwtiReCKQCWQ7CDlxXGnaEU8Ecr5aRiAlDR8GHYScOK407YgnApkUSFkVaUDe1JiVi5DE+O1aG7viI36qC68sHXqMxEfut++Wg/p0d4TYzigCOUaNCJgQ8N3IVcVDciLYGD7SBhiBTKBrCmqeocWrQn81uSKQqkKbn2eCZIL8iBXLJDGhky+mVYcjF0hi824d2UwVkid5bbnHgsQywo/wpLLpaporc1BvsawgqpFLileBfvNRCe9mY0Alfgk25GyTZwRC0H/YEIwjkAlMI5A5clUEzAQpyFcRzqwVmSDHJO5aNUcYm1pFIBHIEIGsWHdYfqxAqtHZ1cUJgBMb0tQLAnJPIfFZG3Ifq+50pKuTqVJN+iOsKp5YbK5qMB957T96tErKjldSiKrghLRUMLboW/9dBe6IZWVdbHwVl7rwG9W8OpviFYGcKKrqVF0FtgSsGkomyAMhgsXIJgKJQL4h0PW6uOriXQ1m6QQxXwNddVa65hi7CnTqs6tr0/OusFuVU5ffrtoRLE3MQ8FGIMdwv7IREBJUK5a595FubP1GIKaqk890gWw6zGSol5uvyqnLb1ftCLAm5kyQDbIGQFKYV9qsyqnLbwRyATu6QO4q+gUp4yNW5dTlt6t2BBAT86UThAS4T9S8PenahwnoVby3nxMSdGBD4jXn3PySuxfJk8Ro7lGkDh1+P7BYdUk3xYlAel8YmBpEIF9rEIGYNvf5jP3lkyEu6eptXXP33STkzZaJj/gl5SFnG8wzQQj6JzYRyAMcQlICtyEyOdv4/RDIVV8DbcnU1RWr4hiQbU5kfzc2Xbt5FxYV5mSCrMSYxBeBnKxLlThXFi8CuaO/EuMIhCAQgXxDKRNkszpmxTruVJkgxx2GTLiJ/vSfKfHbZUPiy4qVCZIJcvYi5qoJgtQKvvqYjP+q849iIX7NmxCyQxtsyDPkEmz9kBcCpNObWpGzSV6knpdNEBIw+UUhIbIBnfglgJLidfkhmBosjF/SCK7EmORA6hCBPLFikSIQ4lg/5LkIhN+jhptFVqw7LFd2N9K5yCSKQHjt7LpZfkchIY4pFHmGEInER/yQe4nZqUme1qYjHosNEXBHfBYbMjnRSl99DTQhYFcSJClSGOMnAnmuimSVfDcuRSCfNbddsgLwlQW/pdbRoS02pFF1xPecbB9Pj/Ks6vuxemeCHJegAjACeWCXCdIl5Qk/pLsRkhI/WbEmCjMw/WsEQghHoCSk7OjQZHTaNxhVnpYUHdh8jP/i/20QbIgNwa+KpcLy35+btczmQO6q5X+YoomRw6q99UpwCEmr3COQ8xWrwq9LeBHICdIWnAjkDmoXfpkgk+2AEDArln9BkBVr7g0Voe+wWVQf2mAdV+uUHa9EeOTsDj9d3Ze8IHhlHbriW5UDqSVZh4d5RiCkbHebauKRrn601hBRV5FaonTcH6vY6M9NDuYZXIcIhJYuAtki1XXn6BBnBLJBkYBBunGHn6xYvLlQS1IXMsm7OKC+H4SoniRRdaFXE5AUqyp8lWP1/L8/t1hU/jtyPFotjW/CG0L+Km+8YpmvYItACPzjewt/8qtlBHKMnG1CRMCZICeMJQBWhLfFM02oimX0844cM0EK5El3IzZdpCBFJ8QlfipSknMqH0frQIfvjhwjkAiEcHho00HiCOQcfosxaQ7lijUKzQZEJsTWRv9yB3z4MmH8HkCSt3nGrj5VPGZqj8RYnUMFTLDpsiFcI3lFIBN3EAIoKbARp2lUEcgDNYtFBBKBfEPAiJwQkPjtsskEOSE26fSmixO/pMDm7EyQ42lg6nL0YmGPc/lfbkkxbYDfggGfrGjiId3N3AO67kgkPnShXIQfwZzYkBwqTpBz6D2KNLMIZGLFIsUjJCC/LSY2VTwkFjOZKEnJmlP5Is2XNDfSzEY2EUgE8g0BS8qK7EawNhYyHYhNBBKBRCCfCGSCbKhAOlPV8cjYJitM7iDHXYrU6aUrFiGBTaIayeTnFYnp2wpyFtmpCRZktBObKh5SOytgg1d1Z6KXa3I2wY/YlCsWAZmQgiRlbCKQB2qk4AYv8oyp3UpuGSzUirUyCQNq1TVJR+w4d9Tt6LTqKl6FBakdwSsCOWEMATkT5AEgwSICueO1kltdGJdfoGMvQFV36+riKzvgqt9FEBEZfFZ1+i6MCZ6rbAyeHyKuvkAnAjne8S1xIpA7cvbtnRFRBLJBgABIADN+yDMRSATyjX/vPv7tNNg/F4Ectx6DTdeUIQ1xyIGsWM8VNAI5ngYd2Ly9QEjnX/k2wlz2TacyHcYWj5xl1jDz5obEQmxIvIZLFuMuDpSXdJPU6AJGACSFMPEQkMnZRKykMOQsg1cE8kCW1IFgHIEQth7YEOERQZP7DwkzAolAhq8GO3ZdQsBMEH5fG1mSZmE6v21UaIKs+vBqkmgHsQnohvy3ZwiARDRVnpZMJi9Tl64JR7Ai8Zm6WIxbvoLNKrgiTpdfQ6QI5By1DpLa+nacPbonDxtBJshzawPpilUjsN3NCJ90aOK3g6QRyAZpsgqR4hEbUmBiY0hg8oxA+i/XpL6oVpkgmSCETGYKVn7/lxOkSope2MwrRzIdTFcnOZFuQkjSkfdoP+76ZSyJz+BF6nIlxiQHYlP+j0LkZPBZuKQQlQ3pMCQ+YnNl8aq8I5DjlYtiQ2pObCKQT5QiEEKXhw0R+d7jlRjPZXOyZu/vIMaxHf8VyJkg/Z20wpzW3/j5EQIhuyQBkYBR3Tm6YhnFa+K7Km9yjrUhmHaRv6rvu+UwvF93vMXqIqApjAU5AjlGztSBTHuCOannKpFHIBsESLFIIcyevaqzvpJcEQhB/0kCms41GdZ/5hFIJgjhzrIv0FlFduKXkJ+As7cxE8WcQ5+psCA4kBcsw9UDfNXCK/GyuX+refU96QQccgfpAqsixS0WAg4l4dauKwdztsGY4BCBnFcjE2SCrRHIAyxyj3olXrY5ZIJMCCIr1jFYEcgJkUhnIKuQ4SrxS7qHOZvkbfzaZyosCA5ZsYoVq+M36bbAHR2avF608VUE7PJL/BBxGkEQ/IgNuSORepMciJ+9DclhaBOBHNMzArljQ8gVgZA296QN6ZKmM9iwIpAIpOWveS0BzaiMQPjEG1may/VfPUHMR492CaLq0GQftZdMkkNFJjPxRisLycGeRRpKhYU9u6ovWcssNoQ7Vd63n5cfHEecWJsKQJIkAdDGF4HckYtALIOefC4COSZghY2FnjSdjtWXTspqwpEGSGwsXpkgJ8hlgmSCRCARSNlcs2JtIDIjuEQYfmEj8UPG/6ocXhmfWSMIsckbqlV4mpzImzlaJ7LGqj9WpAFs7brAiEAeCFTEjUDOmRqBGCU3P9PVGIyfCCQCQd+13cz5KXeG2HSNyARZ/xKhXLFIFxoVlIyvysbux9XbpymGT1ziu/xaPxWe9NUr8UNi7PJDzqpsCJeGjan6H4URyDH0FpuqmPbnhJBdNiRGchbx02ETgWxQzAQ5Xj0IaYkNIW2XH3JWZROBRCDf/iyd3H+sTUVIus4RPx02EUgEEoGcKCkCmRSIuT9Ub43o2yfTEcnZJifygsXEe3umiofkZDElvqv4PnL4Wy/pBJx9cQjo+2fMOZa0V55FRFPFY/Akwhutd1ZoEQip9KeNKWhFEno8OfvKs0jcVTwkJ0ts4ruKLxOEVHljQ0DPBHkgUBHQ4PlXT5BJvn6Yk7cwK7tQJQh7OSSvSCuCWWyqnGidXhlfdTYV2lutWBT4rZ0lQdXd6B5bkSkCOa6qrV2FOa0d4UAEcqJK0oWqYkUgEcgQgY4VgUwU24VI94hA7hUgWI1qVeFna1c1pUyQDUIWZFL0qsDkbpMJ8sMnCOnixMYSueoWhIDEhuSwtzECMuc808XNeSQv8/dupCmZeFc+U95Bug6PQJ5D8kpyRSCPWkUgT/CWEOkJ918ejUC6kJzzE4HM4fXFOgJ5wEGwuFLkT5T1a2N6p48ere4bo7cTrwS9ixTkjmTOIn4tkTriIWs3sbEvS0jub/W5WBHIZvcFX5JZ4RWBzE24odAyQUgfGduYLjryRIhsziJ+bfYd8ZDpQGwyQTYIkF9A2qLPPmdIEoEcT0m6QhvcyTOZILMKKOwJ6OSORDq9OYv4tZB0xEOmA7FZOUH+Ad91GpdhtTegAAAAAElFTkSuQmCC"; diff --git a/src/utils/constants/index.js b/src/utils/constants/index.js new file mode 100644 index 0000000..2da2609 --- /dev/null +++ b/src/utils/constants/index.js @@ -0,0 +1,31 @@ +export { + TabNames, + MaterialType, + DockPanelCategories, + BoatLiftRange, + CanvasModes, + categoryMapping, + materialsMapping, + DockPanelCategoryMap, + CylinderType, + EstimateSteps, + Tables, + Truthy, + dock_image, + scaleFactor, + edgeSnapThreshold, + oneFeet, + SnapType, + fortyFiveDeg, + nintyDeg, + onThirtyFiveDeg, + oneEightyDeg, + threeFifteenDeg, + twoSeventyDeg, + twoTwentyFiveDeg, + deleteIcon, + rotateIcon, +} from './constants' +export { + selectedItemsTableColumns, +} from './tableColumns' \ No newline at end of file diff --git a/src/utils/constants/tableColumns.jsx b/src/utils/constants/tableColumns.jsx new file mode 100644 index 0000000..2534a93 --- /dev/null +++ b/src/utils/constants/tableColumns.jsx @@ -0,0 +1,113 @@ + +export const selectedItemsTableColumns = [ + // { + // header: "Action", + // accessor: "", + // }, + + + { + header: 'Item Name', + accessor: 'itemName', + isSorted: true, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Category', + accessor: 'category', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Name', + accessor: 'name', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Materials', + accessor: 'materials', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Length', + accessor: 'length', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Width', + accessor: 'width', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'Model', + accessor: 'model', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'LIFT RANGE', + accessor: 'lift_range', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: { 0: 'No', 1: 'Yes' } + }, + { + header: 'NO OF CYLINDERS', + accessor: 'no_of_cylinders', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, + { + header: 'WEIGHT CAPACITY', + accessor: 'weight_capacity', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: { 0: 'Resting', 1: 'Bolted', 2: 'Other' } + }, + { + header: 'IMAGE', + accessor: 'image', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: { 0: 'Rocky', 1: 'Silty', 2: 'Sandy' } + }, + { + header: 'TOP VIEW', + accessor: 'top_view', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: { 0: 'No', 1: 'Yes' } + }, + { + header: 'THUMBNAIL', + accessor: 'thumbnail', + isSorted: false, + isSortedDesc: false, + mappingExist: false, + mappings: {} + }, +]; diff --git a/src/utils/helper/helper.js b/src/utils/helper/helper.js new file mode 100644 index 0000000..65fa025 --- /dev/null +++ b/src/utils/helper/helper.js @@ -0,0 +1,8 @@ +export const capitalize = (string) => { + const removedSpecialCharacters = string.replace(/[^a-zA-Z0-9]/g, " ") + + const splitWords = removedSpecialCharacters.split(' ') + const capitalized = splitWords.map((dt) => `${dt[0].toUpperCase()}${dt.substring(1).toLowerCase()}`) + + return capitalized.join(" ") +} \ No newline at end of file diff --git a/src/utils/helper/index.js b/src/utils/helper/index.js new file mode 100644 index 0000000..5b938ec --- /dev/null +++ b/src/utils/helper/index.js @@ -0,0 +1 @@ +export { capitalize } from "./helper" \ No newline at end of file diff --git a/src/utils/utils.jsx b/src/utils/utils.jsx new file mode 100644 index 0000000..7ad846c --- /dev/null +++ b/src/utils/utils.jsx @@ -0,0 +1,143 @@ +import { categoryMapping, materialsMapping, MaterialType } from "./constants"; +import { + rampsCategoryMapping, + wedgesAndRampsMaterialsMapping, + wedgesCategoryMapping, +} from "./constants/constants"; + +export function classNames(...classes) { + return classes.filter(Boolean).join(" "); +} + +export const getNonNullValue = (value) => { + if (value !== "") { + return value; + } else { + return undefined; + } +}; + +export function filterEmptyFields(object) { + Object.keys(object).forEach((key) => { + if (empty(object[key])) { + delete object[key]; + } + }); + return object; +} + +export function empty(value) { + return ( + value === "" || + value === null || + value === undefined || + value === "undefined" + ); +} + +export const isImage = (file) => { + const validImageTypes = ["image/gif", "image/jpeg", "image/jpg", "image/png"]; + if (validImageTypes.includes(file.file.type)) return true; + return false; +}; + +export class Stack { + constructor() { + this._undo = []; + this._redo = []; + this._update = false; + this._updateCount = 0; + } + + updateStack(data) { + const duplicateState = this._undo.find((state) => state === data); + if (duplicateState) { + return this._undo[this._undo.length - 1]; + } + const parsed = JSON.parse(data); + const snapCloneFound = parsed.objects.find((object) => object.snapClone); + if (snapCloneFound) { + return this._undo[this._undo.length - 1]; + } + + this._undo.push(data); + this._update = true; + this._updateCount += 1; + // console.log( this._undo ) + return this._undo[this._undo.length - 1]; + } + undo() { + if (this._updateCount === 1) { + const redoLast = this._undo.splice(0, 1); + this._redo.push(redoLast[0]); + this._update = false; + // console.log( this._undo, "undo" ) + // console.log( this._redo, "redo" ) + this._update = false; + this._updateCount -= 1; + return { + currentCount: 0, + }; + } else if (this._updateCount > 1) { + const redoLast = this._undo.splice(this._undo.length - 1, 1); + this._redo.push(redoLast[0]); + const currentState = this._undo[this._undo.length - 1]; + this._updateCount -= 1; + this._update = false; + console.log("UNDO"); + // console.log( this._undo, "undo" ) + // console.log( this._redo, "redo" ) + return { + currentState, + currentCount: this._undo.length, + }; + } else { + return { + currentCount: -1, + }; + } + } + redo() { + console.log(this._update, "update"); + if (this._update) { + if (this._redo.length > 0) { + this._redo = []; + } + return { + currentState: null, + }; + } else { + if (this._redo.length > 0) { + const undoLast = this._redo.splice(this._redo.length - 1, 1); + this._undo.push(undoLast[0]); + this._updateCount += 1; + this._update = false; + + console.log("REDO"); + // console.log( this._undo, "undo" ) + // console.log( this._redo, "redo" ) + return { + currentState: undoLast, + }; + } else { + return { currentState: null }; + } + } + } +} + +export const getMaterial = (materials) => { + return materialsMapping[materials]; +}; +export const getWedgesAndRampsMaterial = (materials) => { + return wedgesAndRampsMaterialsMapping[materials]; +}; +export const getCategory = (category) => { + return categoryMapping[category]; +}; +export const getWedgesCategory = (category) => { + return wedgesCategoryMapping[category]; +}; +export const getRampsCategory = (category) => { + return rampsCategoryMapping[category]; +}; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..159a23b --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./src/**/*.{js,jsx,ts,tsx}", "./node_modules/tw-elements/dist/js/**/*.js"], + theme: { + extend: {}, + }, + plugins: [require("tw-elements/dist/plugin")], +}; diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..1e82720 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,20 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import path from "path"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + Components: path.resolve(__dirname, "./src/components"), + Pages: path.resolve(__dirname, "./src/pages"), + Utils: path.resolve(__dirname, "./src/utils"), + Assets: path.resolve(__dirname, "./src/assets"), + Src: path.resolve(__dirname, "./src") + } + }, + server: { + port: 3001 + } +});