commit a78b168b600bb9888ef6649fc37c6596f897ba5d Author: MOHAN Date: Sat Jun 13 13:15:55 2026 +0530 Initial commit — Dine360 Ads Frontend Co-Authored-By: Claude Sonnet 4.6 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..d704378 --- /dev/null +++ b/.htaccess @@ -0,0 +1,6 @@ + + Options -MultiViews + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.html [QSA,L] + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd3b758 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript and enable type-aware lint rules. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..ec2b712 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,33 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' + +export default [ + { ignores: ['dist'] }, + { + files: ['**/*.{js,jsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...js.configs.recommended.rules, + ...reactHooks.configs.recommended.rules, + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +] diff --git a/index.html b/index.html new file mode 100644 index 0000000..9815ea1 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Dine 360 Ads + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6b8a275 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3816 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@heroicons/react": "^2.2.0", + "@tailwindcss/vite": "^4.0.14", + "autoprefixer": "^10.4.21", + "axios": "^1.8.3", + "framer-motion": "^12.9.4", + "lucide-react": "^0.484.0", + "postcss": "^8.5.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "^5.5.0", + "react-router-dom": "^7.3.0", + "react-select": "^5.10.1", + "react-toastify": "^11.0.5", + "sweetalert2": "^11.17.2", + "tailwindcss": "^4.0.14" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "vite": "^6.2.0" + } + }, + "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==", + "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==", + "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-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==", + "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==", + "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==", + "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==", + "dependencies": { + "@babel/types": "^7.26.10" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.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.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "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==", + "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==", + "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/traverse/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==", + "engines": { + "node": ">=4" + } + }, + "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==", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", + "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", + "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + }, + "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/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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/@rollup/rollup-android-arm-eabi": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", + "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", + "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", + "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", + "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", + "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", + "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", + "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", + "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", + "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", + "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", + "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", + "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", + "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", + "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", + "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", + "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", + "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", + "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", + "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.14.tgz", + "integrity": "sha512-Ux9NbFkKWYE4rfUFz6M5JFLs/GEYP6ysxT8uSyPn6aTbh2K3xDE1zz++eVK4Vwx799fzMF8CID9sdHn4j/Ab8w==", + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "tailwindcss": "4.0.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.14.tgz", + "integrity": "sha512-M8VCNyO/NBi5vJ2cRcI9u8w7Si+i76a7o1vveoGtbbjpEYJZYiyc7f2VGps/DqawO56l3tImIbq2OT/533jcrA==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.0.14", + "@tailwindcss/oxide-darwin-arm64": "4.0.14", + "@tailwindcss/oxide-darwin-x64": "4.0.14", + "@tailwindcss/oxide-freebsd-x64": "4.0.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.14", + "@tailwindcss/oxide-linux-x64-musl": "4.0.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.0.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.14.tgz", + "integrity": "sha512-VBFKC2rFyfJ5J8lRwjy6ub3rgpY186kAcYgiUr8ArR8BAZzMruyeKJ6mlsD22Zp5ZLcPW/FXMasJiJBx0WsdQg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.14.tgz", + "integrity": "sha512-U3XOwLrefGr2YQZ9DXasDSNWGPZBCh8F62+AExBEDMLDfvLLgI/HDzY8Oq8p/JtqkAY38sWPOaNnRwEGKU5Zmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.14.tgz", + "integrity": "sha512-V5AjFuc3ndWGnOi1d379UsODb0TzAS2DYIP/lwEbfvafUaD2aNZIcbwJtYu2DQqO2+s/XBvDVA+w4yUyaewRwg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.14.tgz", + "integrity": "sha512-tXvtxbaZfcPfqBwW3f53lTcyH6EDT+1eT7yabwcfcxTs+8yTPqxsDUhrqe9MrnEzpNkd+R/QAjJapfd4tjWdLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.14.tgz", + "integrity": "sha512-cSeLNWWqIWeSTmBntQvyY2/2gcLX8rkPFfDDTQVF8qbRcRMVPLxBvFVJyfSAYRNch6ZyVH2GI6dtgALOBDpdNA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.14.tgz", + "integrity": "sha512-bwDWLBalXFMDItcSXzFk6y7QKvj6oFlaY9vM+agTlwFL1n1OhDHYLZkSjaYsh6KCeG0VB0r7H8PUJVOM1LRZyg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.14.tgz", + "integrity": "sha512-gVkJdnR/L6iIcGYXx64HGJRmlme2FGr/aZH0W6u4A3RgPMAb+6ELRLi+UBiH83RXBm9vwCfkIC/q8T51h8vUJQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.14.tgz", + "integrity": "sha512-EE+EQ+c6tTpzsg+LGO1uuusjXxYx0Q00JE5ubcIGfsogSKth8n8i2BcS2wYTQe4jXGs+BQs35l78BIPzgwLddw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.14.tgz", + "integrity": "sha512-KCCOzo+L6XPT0oUp2Jwh233ETRQ/F6cwUnMnR0FvMUCbkDAzHbcyOgpfuAtRa5HD0WbTbH4pVD+S0pn1EhNfbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.14.tgz", + "integrity": "sha512-AHObFiFL9lNYcm3tZSPqa/cHGpM5wOrNmM2uOMoKppp+0Hom5uuyRh0QkOp7jftsHZdrZUpmoz0Mp6vhh2XtUg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.14.tgz", + "integrity": "sha512-rNXXMDJfCJLw/ZaFTOLOHoGULxyXfh2iXTGiChFiYTSgKBKQHIGEpV0yn5N25WGzJJ+VBnRjHzlmDqRV+d//oQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.14.tgz", + "integrity": "sha512-y69ztPTRFy+13EPS/7dEFVl7q2Goh1pQueVO8IfGeyqSpcx/joNJXFk0lLhMgUbF0VFJotwRSb9ZY7Xoq3r26Q==", + "dependencies": { + "@tailwindcss/node": "4.0.14", + "@tailwindcss/oxide": "4.0.14", + "lightningcss": "1.29.2", + "tailwindcss": "4.0.14" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/react": { + "version": "19.0.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", + "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", + "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", + "dev": true, + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "dev": true, + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "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/axios": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz", + "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "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/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==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001704", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001704.tgz", + "integrity": "sha512-+L2IgBbV6gXB4ETf0keSvLr7JUrRVbIaB/lrQ1+z8mRcQiisG5k+lG6O4n6Y5q6f5EuNfaYXKgymucphlEXQew==", + "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/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": 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/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/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/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "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==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "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==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.118", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.118.tgz", + "integrity": "sha512-yNDUus0iultYyVoEFLnQeei7LOQkL8wg8GQpkPCRrOlJXlcCwa6eGKZkxQ9ciHsqZyYbj8Jd94X1CTPzGm+uIA==" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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==", + "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==", + "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==", + "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==", + "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.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", + "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.1.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.22.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.19.tgz", + "integrity": "sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ==", + "dev": true, + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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==", + "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/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.9.4", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.9.4.tgz", + "integrity": "sha512-yaeGDmGQ3eCQEwZ95/pRQMaSh/Q4E2CK6JYOclG/PdjyQad0MULJ+JFVV8911Fl5a6tF6o0wgW8Dpl5Qx4Adjg==", + "dependencies": { + "motion-dom": "^12.9.4", + "motion-utils": "^12.9.4", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "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/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-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "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==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "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-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "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==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "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/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "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/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "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/lucide-react": { + "version": "0.484.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.484.0.tgz", + "integrity": "sha512-oZy8coK9kZzvqhSgfbGkPtTgyjpBvs3ukLgDPv14dSOZtBtboryWF5o8i3qen7QbGg7JhiJBz5mK1p8YoMZTLQ==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "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==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/motion-dom": { + "version": "12.9.4", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.9.4.tgz", + "integrity": "sha512-25TWkQPj5I18m+qVjXGtCsxboY11DaRC5HMjd29tHKExazW4Zf4XtAagBdLpyKsVuAxEQ6cx5/E4AB21PFpLnQ==", + "dependencies": { + "motion-utils": "^12.9.4" + } + }, + "node_modules/motion-utils": { + "version": "12.9.4", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.9.4.tgz", + "integrity": "sha512-BW3I65zeM76CMsfh3kHid9ansEJk9Qvl+K5cu4DVHKGsI52n76OJ4z2CUJUV+Mn3uEP9k1JJA3tClG0ggSrRcg==" + }, + "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/nanoid": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", + "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "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==" + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "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-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "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/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-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/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "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/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "peerDependencies": { + "react": "*" + } + }, + "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-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.3.0.tgz", + "integrity": "sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.3.0.tgz", + "integrity": "sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==", + "dependencies": { + "react-router": "7.3.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-select": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.1.tgz", + "integrity": "sha512-roPEZUL4aRZDx6DcsD+ZNreVl+fM8VsKn0Wtex1v4IazH60ILp5xhdlp464IsEAlJdXeD+BhDAFsBVMfvLQueA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-toastify": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", + "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.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/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/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", + "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.35.0", + "@rollup/rollup-android-arm64": "4.35.0", + "@rollup/rollup-darwin-arm64": "4.35.0", + "@rollup/rollup-darwin-x64": "4.35.0", + "@rollup/rollup-freebsd-arm64": "4.35.0", + "@rollup/rollup-freebsd-x64": "4.35.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", + "@rollup/rollup-linux-arm-musleabihf": "4.35.0", + "@rollup/rollup-linux-arm64-gnu": "4.35.0", + "@rollup/rollup-linux-arm64-musl": "4.35.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", + "@rollup/rollup-linux-riscv64-gnu": "4.35.0", + "@rollup/rollup-linux-s390x-gnu": "4.35.0", + "@rollup/rollup-linux-x64-gnu": "4.35.0", + "@rollup/rollup-linux-x64-musl": "4.35.0", + "@rollup/rollup-win32-arm64-msvc": "4.35.0", + "@rollup/rollup-win32-ia32-msvc": "4.35.0", + "@rollup/rollup-win32-x64-msvc": "4.35.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "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/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/sweetalert2": { + "version": "11.17.2", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.17.2.tgz", + "integrity": "sha512-HKxDr1IyV3Lxr3W6sb61qm/p2epFIEdr5EKwteRFHnIg6f8nHFl2kX++DBVz16Mac+fFiU3hMpjq1L6yE2Ge5w==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, + "node_modules/tailwindcss": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.14.tgz", + "integrity": "sha512-92YT2dpt671tFiHH/e1ok9D987N9fHD5VWoly1CdPD/Cd1HMglvZwP3nx2yTj2lbXDAHt8QssZkxTLCCTNL+xw==" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "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/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.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==", + "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/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", + "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", + "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.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/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fa309fc --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@heroicons/react": "^2.2.0", + "@tailwindcss/vite": "^4.0.14", + "autoprefixer": "^10.4.21", + "axios": "^1.8.3", + "framer-motion": "^12.9.4", + "lucide-react": "^0.484.0", + "postcss": "^8.5.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "^5.5.0", + "react-router-dom": "^7.3.0", + "react-select": "^5.10.1", + "react-toastify": "^11.0.5", + "sweetalert2": "^11.17.2", + "tailwindcss": "^4.0.14" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "vite": "^6.2.0" + } +} diff --git a/public/canada_cities.json b/public/canada_cities.json new file mode 100644 index 0000000..e0cac6a --- /dev/null +++ b/public/canada_cities.json @@ -0,0 +1,1765 @@ +{ + "Ontario": [ + "Toronto", + "Ottawa", + "Hamilton", + "Mississauga", + "Brampton", + "Kitchener", + "London", + "Markham", + "Oshawa", + "Vaughan", + "Windsor", + "St. Catharines", + "Oakville", + "Richmond Hill", + "Burlington", + "Sudbury", + "Barrie", + "Guelph", + "Whitby", + "Cambridge", + "Milton", + "Ajax", + "Waterloo", + "Thunder Bay", + "Brantford", + "Chatham", + "Clarington", + "Pickering", + "Niagara Falls", + "Newmarket", + "Peterborough", + "Kawartha Lakes", + "Caledon", + "Belleville", + "Sarnia", + "Sault Ste. Marie", + "Welland", + "Halton Hills", + "Aurora", + "North Bay", + "Stouffville", + "Cornwall", + "Georgina", + "Woodstock", + "Quinte West", + "St. Thomas", + "New Tecumseth", + "Innisfil", + "Bradford West Gwillimbury", + "Timmins", + "Lakeshore", + "Brant", + "Leamington", + "East Gwillimbury", + "Orangeville", + "Orillia", + "Stratford", + "Fort Erie", + "LaSalle", + "Centre Wellington", + "Grimsby", + "King", + "Woolwich", + "Clarence-Rockland", + "Midland", + "Lincoln", + "Wasaga Beach", + "Collingwood", + "Strathroy-Caradoc", + "Thorold", + "Amherstburg", + "Tecumseh", + "Essa", + "Owen Sound", + "Brockville", + "Kingsville", + "Springwater", + "Scugog", + "Uxbridge", + "Wilmot", + "Essex", + "Oro-Medonte", + "Cobourg", + "South Frontenac", + "Port Colborne", + "Huntsville", + "Russell", + "Niagara-on-the-Lake", + "Middlesex Centre", + "Selwyn", + "Tillsonburg", + "Pelham", + "Petawawa", + "North Grenville", + "Loyalist", + "Port Hope", + "Pembroke", + "Bracebridge", + "Greater Napanee", + "Kenora", + "Mississippi Mills", + "St. Clair", + "West Lincoln", + "West Nipissing / Nipissing Ouest", + "Clearview", + "Thames Centre", + "Carleton Place", + "Guelph/Eramosa", + "Central Elgin", + "Saugeen Shores", + "Ingersoll", + "South Stormont", + "Severn", + "South Glengarry", + "North Perth", + "Trent Hills", + "The Nation / La Nation", + "West Grey", + "Gravenhurst", + "Perth East", + "Wellington North", + "Brighton", + "Tiny", + "Hawkesbury", + "Brock", + "Erin", + "Kincardine", + "Elliot Lake", + "Arnprior", + "North Dundas", + "Wellesley", + "Georgian Bluffs", + "Norwich", + "Meaford", + "Adjala-Tosorontio", + "Hamilton Township", + "South Dundas", + "Lambton Shores", + "North Dumfries", + "Mapleton", + "Rideau Lakes", + "North Glengarry", + "South Huron", + "Penetanguishene", + "Tay", + "Cavan Monaghan", + "Temiskaming Shores", + "Grey Highlands", + "Alfred and Plantagenet", + "Elizabethtown-Kitley", + "Smiths Falls", + "Ramara", + "Leeds and the Thousand Islands", + "Brockton", + "Laurentian Valley", + "Mono", + "Malahide", + "Huron East", + "Beckwith", + "Shelburne", + "West Perth", + "Champlain", + "Minto", + "South Bruce Peninsula", + "Renfrew", + "Plympton-Wyoming", + "Kapuskasing", + "Zorra", + "Kirkland Lake", + "Aylmer", + "Puslinch", + "Drummond/North Elmsley", + "Hanover", + "Dryden", + "Fort Frances", + "Goderich", + "Stone Mills", + "South-West Oxford", + "Douro-Dummer", + "McNab/Braeside", + "Central Huron", + "Blandford-Blenheim", + "Bayham", + "Augusta", + "St. Marys", + "Southgate", + "Bluewater", + "East Zorra-Tavistock", + "Otonabee-South Monaghan", + "Huron-Kinloss", + "The Blue Mountains", + "Whitewater Region", + "Edwardsburgh/Cardinal", + "Wainfleet", + "North Stormont", + "Alnwick/Haldimand", + "Arran-Elderslie", + "Parry Sound", + "Muskoka Falls", + "Perth", + "Cramahe", + "North Middlesex", + "Dysart et al", + "Hindon Hill", + "Tweed", + "Oliver Paipoonge", + "Petrolia", + "Southwest Middlesex", + "Front of Yonge", + "Tay Valley", + "South Bruce", + "Ashfield-Colborne-Wawanosh", + "Trent Lakes", + "Gananoque", + "Lanark Highlands", + "Cochrane", + "Sioux Lookout", + "Hearst", + "Breslau", + "Stirling-Rawdon", + "Espanola", + "West Elgin", + "East Ferris", + "North Huron", + "Southwold", + "Centre Hastings", + "Lucan Biddulph", + "Greenstone", + "Tyendinaga", + "Iroquois Falls", + "Havelock-Belmont-Methuen", + "Central Frontenac", + "Seguin", + "Madawaska Valley", + "Deep River", + "Asphodel-Norwood", + "Red Lake", + "Hastings Highlands", + "Prescott", + "Northern Bruce Peninsula", + "Casselman", + "Callander", + "Amaranth", + "Marmora and Lake", + "Bancroft", + "Howick", + "Dutton/Dunwich", + "Perth South", + "Montague", + "Warwick", + "Bonnechere Valley", + "Morris-Turnberry", + "Mulmur", + "Blind River", + "Powassan", + "Highlands East", + "East Hawkesbury", + "Marathon", + "Shuniah", + "Sables-Spanish Rivers", + "Lake of Bays", + "Merrickville", + "Adelaide-Metcalfe", + "Melancthon", + "Laurentian Hills", + "Grand Valley", + "Admaston/Bromley", + "North Algona Wilberforce", + "Wawa", + "Horton", + "Enniskillen", + "Atikokan", + "Markstay", + "Northeastern Manitoulin and the Islands", + "McDougall", + "French River / Riviere des Francais", + "East Garafraxa", + "Greater Madawaska", + "Georgian Bay", + "North Kawartha", + "Perry", + "Black River-Matheson", + "Killaloe, Hagarty and Richards", + "Alvinston", + "Algonquin Highlands", + "Addington Highlands", + "Neebing", + "Bonfield", + "Central Manitoulin", + "Madoc", + "Mattawa", + "Dawn-Euphemia", + "Chapleau", + "Manitouwadge", + "Wellington", + "Frontenac Islands", + "Point Edward", + "North Frontenac", + "Komoka", + "Deseronto", + "Nipissing", + "Huron Shores", + "Nipigon", + "Burford", + "Terrace Bay", + "Macdonald, Meredith and Aberdeen Additional", + "Brudenell, Lyndoch and Raglan", + "Moosonee", + "Englehart", + "Strong", + "Lappe", + "Armour", + "Faraday", + "Bayfield", + "St.-Charles", + "Emo", + "Smooth Rock Falls", + "Chisholm", + "Thessalon", + "Conestogo", + "St. Joseph", + "Moonbeam", + "Claremont", + "Ignace", + "Armstrong", + "Hillsburgh", + "Sagamok", + "Hensall", + "Carling", + "Laird", + "Tara", + "Cobalt", + "South River", + "McKellar", + "South Algonquin", + "Sioux Narrows-Nestor Falls", + "Beachburg", + "Schreiber", + "Plantagenet", + "Papineau-Cameron", + "Assiginack", + "Prince", + "Athens", + "Chatsworth", + "Magnetawan" + ], + "Quebec": [ + "Montreal", + "Quebec City", + "Laval", + "Gatineau", + "Longueuil", + "Sherbrooke", + "Levis", + "Saguenay", + "Trois-Rivieres", + "Terrebonne", + "Saint-Jerome", + "Saint-Jean-sur-Richelieu", + "Brossard", + "Repentigny", + "Drummondville", + "Chateauguay", + "Granby", + "Mirabel", + "Blainville", + "Lac-Brome", + "Saint-Hyacinthe", + "Beloeil", + "Mascouche", + "Shawinigan", + "Joliette", + "Rimouski", + "Dollard-des-Ormeaux", + "Victoriaville", + "Saint-Eustache", + "Vaudreuil-Dorion", + "Salaberry-de-Valleyfield", + "Rouyn-Noranda", + "Boucherville", + "Sorel-Tracy", + "Cote-Saint-Luc", + "Pointe-Claire", + "Val-d'Or", + "Chambly", + "Alma", + "Sainte-Julie", + "Saint-Constant", + "Magog", + "Boisbriand", + "Sainte-Therese", + "La Prairie", + "Saint-Bruno-de-Montarville", + "Thetford Mines", + "Sept-Iles", + "Hudson", + "Saint-Lin--Laurentides", + "L'Assomption", + "Candiac", + "Saint-Lambert", + "Saint-Lazare", + "Varennes", + "Mont-Royal", + "Baie-Comeau", + "Riviere-du-Loup", + "Saint-Augustin-de-Desmaures", + "Sainte-Marthe-sur-le-Lac", + "Westmount", + "Les Coteaux", + "Kirkland", + "Dorval", + "Beaconsfield", + "Mont-Saint-Hilaire", + "Deux-Montagnes", + "Saint-Colomban", + "Sainte-Catherine", + "Saint-Basile-le-Grand", + "L'Ancienne-Lorette", + "Saint-Charles-Borromee", + "Cowansville", + "Sainte-Anne-des-Plaines", + "Gaspe", + "Pincourt", + "Mercier", + "Lavaltrie", + "Lachute", + "Rosemere", + "Matane", + "Mont-Laurier", + "Mistassini", + "Beauharnois", + "Becancour", + "Sainte-Sophie", + "Val-des-Monts", + "Saint-Amable", + "Sainte-Marie", + "Amos", + "Prevost", + "Sainte-Adele", + "Sainte-Agathe-des-Monts", + "Les Iles-de-la-Madeleine", + "Carignan", + "L'Ile-Perrot", + "Montmagny", + "Cantley", + "Notre-Dame-de-l'Ile-Perrot", + "Bromont", + "La Tuque", + "Rawdon", + "Saint-Felicien", + "Roberval", + "Bois-des-Filion", + "Marieville", + "Saint-Sauveur", + "Stoneham-et-Tewkesbury", + "Mont-Tremblant", + "Saint-Zotique", + "Saint-Raymond", + "Lorraine", + "Notre-Dame-des-Prairies", + "Sainte-Julienne", + "Donnacona", + "L'Epiphanie", + "Pont-Rouge", + "Coaticook", + "La Peche", + "Otterburn Park", + "Sainte-Brigitte-de-Laval", + "Sainte-Catherine-de-la-Jacques-Cartier", + "Farnham", + "Delson", + "La Malbaie", + "Boischatel", + "Beauport", + "Saint-Hippolyte", + "Old Chelsea", + "Saint-Apollinaire", + "Nicolet", + "Contrecoeur", + "La Sarre", + "Chandler", + "Acton Vale", + "Saint-Philippe", + "Rigaud", + "Louiseville", + "Chibougamau", + "Coteau-du-Lac", + "Saint-Remi", + "Les Cedres", + "Baie-Saint-Paul", + "Brownsburg", + "Asbestos", + "Hampstead", + "Saint-Joseph-du-Lac", + "Plessisville", + "Sainte-Anne-des-Monts", + "Saint-Lambert-de-Lauzon", + "Val-Shefford", + "Port-Cartier", + "Saint-Paul", + "Shannon", + "Saint-Honore", + "Beauceville", + "Beaupre", + "Charlemagne", + "Mont-Joli", + "Pointe-Calumet", + "Pontiac", + "L'Ange-Gardien", + "Saint-Felix-de-Valois", + "McMasterville", + "Saint-Calixte", + "Lac-Megantic", + "Saint-Henri", + "Vercheres", + "Richelieu", + "Princeville", + "Saint-Cesaire", + "Val-David", + "Notre-Dame-du-Mont-Carmel", + "Sainte-Martine", + "Saint-Roch-de-l'Achigan", + "Saint-Pie", + "Windsor", + "Montreal-Ouest", + "Temiscouata-sur-le-Lac", + "Sainte-Anne-de-Bellevue", + "Mont-Orford", + "Saint-Germain-de-Grantham", + "Saint-Cyrille-de-Wendover", + "Chisasibi", + "Chertsey", + "Lanoraie", + "Warwick", + "Napierville", + "Waterloo", + "Saint-Joseph-de-Beauce", + "Berthierville", + "Riviere-Rouge", + "Saint-Denis-de-Brompton", + "Amqui", + "Saint-Mathias-sur-Richelieu", + "Saint-Boniface", + "Chateau-Richer", + "Montreal-Est", + "Saint-Antonin", + "Saint-Jean-de-Matha", + "La Pocatiere", + "Roxton Pond", + "Saint-Etienne-des-Gres", + "Saint-Donat", + "Metabetchouan-Lac-a-la-Croix", + "Maniwaki", + "Danville", + "Lac-Etchemin", + "Saint-Jacques", + "L'Islet-sur-Mer", + "Carleton-sur-Mer", + "Oka", + "Morin-Heights", + "Crabtree", + "Saint-Tite", + "New Richmond", + "Baie-d'Urfe", + "Saint-Andre-Avellin", + "Saint-Ambroise-de-Kildare", + "East Angus", + "Saint-Adolphe-d'Howard", + "Saint-Prosper", + "Ormstown", + "Saint-Agapit", + "Saint-Ambroise", + "Mistissini", + "Saint-Faustin--Lac-Carre", + "Saint-Pascal", + "Dunham", + "Havre-Saint-Pierre", + "Saint-Anselme", + "Trois-Pistoles", + "Grande-Riviere", + "Malartic", + "Saint-Maurice", + "Ascot Corner", + "Fossambault-sur-le-Lac", + "Sainte-Anne-des-Lacs", + "Saint-Sulpice", + "Saint-Alphonse-de-Granby", + "Sainte-Claire", + "Perce", + "Saint-Jean-Port-Joli", + "Saint-Andre-d'Argenteuil", + "Saint-Come--Liniere", + "Forestville", + "Compton", + "Richmond", + "Saint-Gabriel-de-Valcartier", + "Paspebiac", + "Saint-Thomas", + "Saint-Jean-Baptiste", + "Portneuf", + "Normandin", + "Saint-Alphonse-Rodriguez", + "Val-Morin", + "Clermont", + "Saint-Christophe-d'Arthabaska", + "Mont-Saint-Gregoire", + "Thurso", + "Saint-Gabriel", + "Saint-Liboire", + "Degelis", + "Saint-Alexis-des-Monts", + "Cap-Saint-Ignace", + "Saint-Anaclet-de-Lessard", + "Stoke", + "Cap Sante", + "Saint-David-de-Falardeau", + "Saint-Ferreol-les-Neiges", + "Senneterre", + "Saint-Mathieu-de-Beloeil", + "Sainte-Marie-Madeleine", + "Sainte-Melanie", + "Saint-Paul-d'Abbotsford", + "Saint-Michel", + "Saint-Marc-des-Carrieres", + "Stanstead", + "Sainte-Anne-de-Beaupre", + "Sainte-Luce", + "Saint-Joseph-de-Sorel", + "Ferme-Neuve", + "Yamachiche", + "Adstock", + "Bonaventure", + "Pohenegamook", + "Saint-Isidore", + "Sainte-Marguerite-du-Lac-Masson", + "Saint-Prime", + "Kuujjuaq", + "Grenville-sur-la-Rouge", + "Saint-Dominique", + "Macamic", + "Sainte-Anne-de-Sorel", + "Rougemont", + "Piedmont", + "Lac-des-Ecorces", + "Saint-Pamphile", + "Bedford", + "Weedon-Centre", + "Lacolle", + "Saint-Gabriel-de-Brandon", + "Huntingdon", + "Saint-Bruno", + "Laurier-Station", + "Saint-Anicet", + "Cap-Chat", + "Notre-Dame-de-Lourdes", + "Ville-Marie", + "Wickham", + "Neuville", + "Maria", + "Saint-Chrysostome", + "Saint-Damase", + "Disraeli", + "Saint-Alexandre", + "Herbertville", + "Sainte-Thecle", + "Fermont", + "La Presentation", + "Sainte-Catherine-de-Hatley", + "Saint-Basile", + "Saint-Raphael", + "Saint-Martin", + "Causapscal", + "Brigham", + "Sainte-Victoire-de-Sorel", + "Port-Daniel--Gascons", + "Labelle", + "Saint-Michel-des-Saints", + "Saint-Victor", + "Saint-Ephrem-de-Beauce", + "Lery", + "Temiscaming", + "Sainte-Genevieve-de-Berthier", + "Sainte-Madeleine", + "Sainte-Croix", + "Valcourt", + "Saint-Mathieu", + "Waterville", + "Mansfield-et-Pontefract", + "Saint-Denis", + "Gore", + "Saint-Gedeon-de-Beauce", + "Saint-Leonard-d'Aston", + "Fort-Coulonge", + "Albanel", + "Pessamit", + "Maskinonge", + "Saint-Charles-de-Bellechasse", + "Hatley", + "East Broughton", + "Saint-Polycarpe", + "Deschambault", + "Wendake", + "Saint-Come", + "Waskaganish", + "Lebel-sur-Quevillon", + "Pierreville", + "Saint-Gilles", + "Saint-Bernard", + "Sainte-Cecile-de-Milton", + "Saint-Roch-de-Richelieu", + "Saint-Nazaire", + "Saint-Elzear", + "Hinchinbrooke", + "Saint-Francois-Xavier-de-Brompton", + "Papineauville", + "Saint-Ignace-de-Loyola", + "Sainte-Anne-de-Sabrevois", + "Sainte-Anne-de-la-Perade", + "Saint-Damien-de-Buckland", + "Saint-Ferdinand", + "Saint-Fulgence", + "Manouane", + "Saint-Gervais", + "Saint-Alexandre-de-Kamouraska", + "Saint-Marc-sur-Richelieu", + "Mandeville", + "Caplan", + "Saint-Damien", + "Lac-Nominingue", + "Obedjiwan", + "Saint-Gedeon", + "Kingsey Falls", + "L'Ascension-de-Notre-Seigneur", + "Barraute", + "Saint-Liguori", + "Saint-Patrice-de-Sherrington", + "Saint-Esprit", + "Mashteuiatsh", + "Saint-Francois-du-Lac", + "Vallee-Jonction", + "Saint-Fabien", + "Lac-Superieur", + "Les Escoumins", + "Terrasse-Vaudreuil", + "Riviere-Beaudette", + "Saint-Barthelemy", + "Austin", + "Saint-Paul-de-l'Ile-aux-Noix", + "Saint-Cyprien-de-Napierville", + "Deleage", + "Potton", + "Sainte-Beatrix", + "Saint-Georges-de-Cacouna", + "Sainte-Justine", + "Saint-Valerien-de-Milton", + "Saint-Cuthbert", + "Saint-Blaise-sur-Richelieu", + "Saint-Joseph-de-Coleraine", + "Pointe-Lebel", + "Grenville", + "Saint-Michel-de-Bellechasse", + "Sainte-Angele-de-Monnoir", + "Champlain", + "Sacre-Coeur-Saguenay", + "Saint-Lucien", + "Saint-Robert", + "La Guadeloupe", + "Sutton", + "Saint-Placide", + "Povungnituk", + "Pointe-des-Cascades", + "Chambord", + "Dudswell", + "Saint-Narcisse", + "Waswanipi", + "Inukjuak", + "Saint-Zacharie", + "Hemmingford", + "Saint-Pierre-de-l'Ile-d'Orleans", + "Saint-Clet", + "Saint-Ours", + "Sainte-Anne-de-la-Pocatiere", + "Notre-Dame-du-Bon-Conseil", + "Sainte-Clotilde", + "Nouvelle", + "Yamaska", + "Saint-Antoine-de-Tilly", + "Saint-Elie-de-Caxton", + "Price", + "Saint-Jacques-le-Mineur", + "Val-Joli", + "Saint-Antoine-sur-Richelieu", + "Saint-Pacome", + "Saint-Stanislas-de-Kostka", + "Frontenac", + "Sainte-Emelie-de-l'Energie", + "Saint-Charles-sur-Richelieu", + "Sainte-Helene-de-Bagot", + "Franklin Centre", + "Mille-Isles", + "Lyster", + "Sainte-Clotilde-de-Horton", + "Saint-Benoit-Labre", + "Maliotenam", + "Chapais", + "Saint-Honore-de-Shenley", + "Cleveland", + "Messines", + "Saint-Laurent-de-l'Ile-d'Orleans", + "Saint-Jean-de-Dieu", + "Larouche", + "Saint-Francois-de-la-Riviere-du-Sud", + "Eeyou Istchee Baie-James", + "Shawville", + "Lambton", + "Saint-Flavien", + "Sainte-Marcelline-de-Kildare", + "Riviere-Blanche", + "Saint-Felix-de-Kingsey", + "Sainte-Elisabeth", + "Uashat", + "Saint-Bernard-de-Lacolle", + "Saint-Guillaume", + "Venise-en-Quebec", + "Saint-Paulin", + "Saint-Albert", + "Matagami", + "Amherst", + "Notre-Dame-du-Laus", + "Saint-Tite-des-Caps", + "Saint-Casimir", + "Saint-Malachie", + "Salluit", + "Saint-Louis-de-Gonzague", + "Saint-Urbain", + "Tring-Jonction", + "Saint-Joachim", + "Saint-Theodore-d'Acton", + "L' Isle-Verte", + "Palmarolle", + "Saint-Odilon-de-Cranbourne", + "La Dore", + "Lac-au-Saumon", + "Wotton", + "Wemindji", + "Pointe-aux-Outardes", + "Riviere-Heva", + "Scott", + "Godmanchester", + "Saint-Simon", + "Tingwick", + "Saint-Aubert", + "Saint-Mathieu-du-Parc", + "Saint-Ubalde", + "Berthier-sur-Mer", + "Frampton", + "Chute-aux-Outardes", + "New Carlisle", + "Saint-Majorique-de-Grantham", + "Wentworth-Nord", + "Sainte-Ursule", + "Nantes", + "Lac-aux-Sables", + "Vaudreuil-sur-le-Lac", + "Amulet", + "L'Avenir", + "Pointe-a-la-Croix", + "Herouxville", + "L'Isle-aux-Allumettes", + "Sainte-Brigide-d'Iberville", + "Les Eboulements", + "Sainte-Barbe", + "Saint-Louis-du-Ha! Ha!", + "Ragueneau", + "Saint-Edouard", + "Riviere-Bleue", + "Noyan", + "Notre-Dame-du-Portage", + "Saint-Hugues", + "Sainte-Anne-du-Sault", + "La Conception", + "L'Isle-aux-Coudres", + "Sainte-Lucie-des-Laurentides", + "Saint-Alexis", + "Roxton Falls", + "Clarendon", + "Saint-Ludger", + "Racine", + "Saint-Zenon", + "Saint-Armand", + "Saint-Edouard-de-Lotbiniere", + "Saint-Arsene", + "Listuguj", + "Saint-Hubert-de-Riviere-du-Loup", + "Saint-Jude", + "La Minerve", + "Trecesson", + "Notre-Dame-des-Pins", + "Saint-Alban", + "Saint-Pierre-les-Becquets", + "Labrecque", + "Sainte-Henedine", + "L'Anse-Saint-Jean", + "Akwesasne", + "Saint-Valere", + "Saint-Norbert-d'Arthabaska", + "Saint-Hilarion", + "Saint-Modeste", + "Saint-Simeon", + "Saint-Barnabe", + "Bury", + "Lac-Bouchette", + "Saint-Lazare-de-Bellechasse", + "Saint-Michel-du-Squatec", + "Saint-Joachim-de-Shefford", + "Grand-Remous", + "Saint-Gabriel-de-Rimouski", + "Sainte-Marie-Salome", + "Saint-Cyprien", + "Tres-Saint-Sacrement", + "Saints-Anges", + "Saint-Urbain-Premier", + "Sainte-Agathe-de-Lotbiniere", + "Grande-Vallee", + "Mont-Carmel", + "Saint-Eugene", + "Notre-Dame-des-Neiges", + "Saint-Leon-de-Standon", + "Sayabec", + "Sainte-Sabine", + "Saint-Maxime-du-Mont-Louis", + "Blanc-Sablon", + "Ayer's Cliff", + "Les Mechins", + "Sainte-Marguerite", + "Saint-Claude", + "Sainte-Jeanne-d'Arc", + "Sainte-Felicite", + "Girardville", + "Saint-Bruno-de-Guigues", + "Upton", + "Saint-Narcisse-de-Beaurivage", + "Plaisance", + "Roxton-Sud", + "Saint-Frederic", + "Saint-Narcisse-de-Rimouski", + "Saint-Patrice-de-Beaurivage", + "Sainte-Marthe", + "Notre-Dame-du-Nord", + "Saint-Aime-des-Lacs", + "Lac-Drolet", + "Coleraine", + "Saint-Bonaventure", + "Saint-Wenceslas", + "Sainte-Genevieve-de-Batiscan", + "Saint-Justin", + "Saint-Norbert", + "Riviere-Ouelle", + "Stukely-Sud", + "Saint-Georges-de-Clarenceville", + "Sainte-Therese-de-Gaspe", + "Sainte-Petronille", + "Desbiens", + "La Macaza", + "Saint-Vallier", + "Bristol", + "Saint-Sylvestre", + "Saint-Stanislas", + "Longue-Rive", + "Saint-Leonard-de-Portneuf", + "Brebeuf", + "Baie-du-Febvre", + "Durham-Sud", + "Melbourne", + "Hebertville", + "Lorrainville", + "Saint-Rene-de-Matane", + "Eastman", + "Wemotaci", + "Cookshire", + "Laurierville", + "Ripon", + "Henryville", + "Gracefield", + "Yamaska-Est", + "Frelighsburg" + ], + "British Columbia": [ + "Vancouver", + "Surrey", + "Victoria", + "Burnaby", + "Richmond", + "Kelowna", + "Abbotsford", + "Coquitlam", + "Saanich", + "White Rock", + "Delta", + "Nanaimo", + "Kamloops", + "Chilliwack", + "Maple Ridge", + "New Westminster", + "Prince George", + "Port Coquitlam", + "North Vancouver", + "Vernon", + "Courtenay", + "Langford Station", + "West Vancouver", + "Mission", + "Campbell River", + "Penticton", + "East Kelowna", + "Port Moody", + "North Cowichan", + "Langley", + "Parksville", + "Duncan", + "Squamish", + "Port Alberni", + "Fort St. John", + "Cranbrook", + "Salmon Arm", + "Pitt Meadows", + "Colwood", + "Oak Bay", + "Esquimalt", + "Central Saanich", + "Lake Country", + "Sooke", + "Comox", + "Terrace", + "Powell River", + "Trail", + "Dawson Creek", + "Sidney", + "Prince Rupert", + "North Saanich", + "Quesnel", + "Williams Lake", + "Whistler", + "Summerland", + "View Royal", + "Nelson", + "Ladysmith", + "Coldstream", + "Sechelt", + "Castlegar", + "Gibsons", + "Qualicum Beach", + "Kitimat", + "Kimberley", + "Merritt", + "Kent", + "Hope", + "Peachland", + "Oliver", + "Fernie", + "Creston", + "Northern Rockies", + "Smithers", + "Armstrong", + "Spallumcheen", + "Osoyoos", + "Metchosin", + "Westbank", + "Cumberland", + "Vanderhoof", + "Bowen Island", + "Grand Forks", + "Port Hardy", + "Sparwood", + "Rossland", + "Mackenzie", + "Golden", + "Fruitvale", + "Invermere", + "Ellison", + "Lake Cowichan", + "Cedar", + "Enderby", + "Houston", + "Pemberton", + "Errington", + "Princeton", + "Cowichan Bay", + "Royston", + "Elkford", + "Highlands", + "Sicamous", + "Chase", + "Tumbler Ridge", + "Anmore", + "Clearwater", + "Lillooet", + "Logan Lake", + "Port McNeill", + "Tofino", + "Burns Lake", + "Saltair", + "Lumby", + "One Hundred Mile House", + "Ucluelet", + "Chetwynd", + "Harrison Hot Springs", + "Nisga'a", + "Lakeview", + "Keremeos", + "Warfield", + "Popkum", + "Coombs", + "Naramata", + "Nakusp", + "Fort St. James", + "Hilliers", + "Ashcroft", + "Grindrod", + "Windermere", + "Gold River", + "Dunsmuir", + "Barriere", + "Lions Bay", + "Telkwa", + "Ootischenia", + "Taylor", + "Sorrento", + "Youbou", + "Kaleden", + "Salmo", + "Valemount", + "Hudson Hope" + ], + "Alberta": [ + "Calgary", + "Edmonton", + "Red Deer", + "Lethbridge", + "Airdrie", + "Wood Buffalo", + "St. Albert", + "Grande Prairie", + "Medicine Hat", + "Spruce Grove", + "Leduc", + "Cochrane", + "Okotoks", + "Fort Saskatchewan", + "Chestermere", + "Beaumont", + "Lloydminster", + "Camrose", + "Stony Plain", + "Sylvan Lake", + "Canmore", + "Cold Lake", + "Brooks", + "Strathmore", + "High River", + "Lacombe", + "Wetaskiwin", + "Morinville", + "Blackfalds", + "Hinton", + "Whitecourt", + "Olds", + "Taber", + "Coaldale", + "Edson", + "Banff", + "Drumheller", + "Innisfail", + "Drayton Valley", + "Ponoka", + "Peace River", + "Slave Lake", + "Rocky Mountain House", + "Devon", + "Wainwright", + "Bonnyville", + "Stettler", + "St. Paul", + "Vegreville", + "Crowsnest Pass", + "Redcliff", + "Didsbury", + "Westlock", + "Jasper", + "Barrhead", + "Vermilion", + "Carstairs", + "Raymond", + "Claresholm", + "Pincher Creek", + "Crossfield", + "Cardston", + "Grande Cache", + "High Level", + "Penhold", + "Gibbons", + "Three Hills", + "Fort Macleod", + "Athabasca", + "Coalhurst", + "Sundre", + "Grimshaw", + "Black Diamond", + "Sexsmith", + "Rimbey", + "High Prairie", + "Turner Valley", + "Hanna", + "Beaverlodge", + "Magrath", + "Calmar", + "Nanton", + "Redwater", + "Tofield", + "Provost", + "Bow Island", + "Fox Creek", + "Millet", + "Picture Butte", + "Vulcan", + "Valleyview", + "Lamont", + "Wabasca", + "Springbrook", + "Wembley", + "Bon Accord", + "Elk Point", + "Nobleford", + "Two Hills", + "Bruederheim", + "Mayerthorpe", + "Swan Hills", + "Vauxhall", + "Bowden", + "Legal", + "Bassano", + "Manning", + "Irricana", + "Eckville", + "Alberta Beach", + "Duchess", + "Viking", + "Bentley", + "Trochu", + "Falher", + "Onoway", + "Oyen" + ], + "Manitoba": [ + "Winnipeg", + "Brandon", + "Steinbach", + "Springfield", + "Hanover", + "Winkler", + "Portage La Prairie", + "Thompson", + "Tache", + "St. Andrews", + "St. Clements", + "Selkirk", + "Morden", + "East St. Paul", + "Stanley", + "Macdonald", + "Dauphin", + "Rockwood", + "Ritchot", + "The Pas", + "West St. Paul", + "La Broquerie", + "Niverville", + "Brokenhead", + "Stonewall", + "Ste. Anne", + "Flin Flon (Part)", + "Neepawa", + "Cornwallis", + "Headingley", + "Altona", + "Swan River", + "De Salaberry", + "Lorette", + "Killarney - Turtle Mountain", + "Woodlands", + "Bifrost-Riverton", + "Cartier", + "Hillsburg-Roblin-Shell River", + "WestLake-Gladstone", + "Mitchell", + "Beausejour", + "Lac du Bonnet", + "Virden", + "Morris", + "Carman", + "North Cypress-Langford", + "Minnedosa", + "Dufferin", + "Kelsey", + "Gimli", + "West Interlake", + "Prairie View", + "Deloraine-Winchester", + "Oakland-Wawanesa", + "Brenda-Waskada", + "Russell-Binscarth", + "Ellice-Archie", + "Souris-Glenwood", + "Riverdale", + "Pembina", + "Wallace-Woodworth", + "Lorne", + "Yellowhead", + "Swan Valley West", + "Grey", + "Gilbert Plains", + "Norfolk-Treherne", + "Emerson-Franklin", + "Sifton", + "Grassland", + "Louise", + "Ste. Rose", + "Cartwright-Roblin", + "Mossey River", + "Lakeshore", + "Riding Mountain West", + "Clanwilliam-Erickson", + "Glenboro-South Cypress", + "North Norfolk", + "Reinland", + "Minitonas-Bowsman", + "Carberry", + "Armstrong", + "Grunthal", + "Piney", + "Blumenort", + "Fisher", + "Wasagamack", + "Whitehead", + "Rosedale", + "Stuartburn", + "Oakview", + "Harrison Park", + "Boissevain", + "Pinawa", + "Pipestone", + "Prairie Lakes", + "St. Francois Xavier", + "Grahamdale", + "Reynolds", + "St. Laurent", + "Landmark", + "Powerview-Pine Falls", + "St-Pierre-Jolys", + "Arborg", + "Elton", + "Rosser", + "Montcalm", + "Coldwell", + "Alonsa", + "Teulon", + "Minto-Odanah", + "Glenella-Lansdowne", + "Two Borders", + "Winnipeg Beach", + "Victoria", + "Roland", + "Melita", + "Argyle", + "Hamiota", + "Gillam", + "Grand View", + "McCreary", + "Rossburn", + "Ethelbert" + ], + "Nova Scotia": [ + "Halifax", + "Cape Breton", + "Truro", + "New Glasgow", + "Inverness", + "Kentville", + "Chester", + "Queens", + "Amherst", + "Bridgewater", + "Church Point", + "Argyle", + "Yarmouth", + "Barrington", + "Antigonish", + "Windsor", + "Wolfville", + "Stellarton", + "Westville", + "Port Hawkesbury", + "Pictou", + "Berwick", + "Trenton", + "Lunenburg", + "Digby", + "Middleton", + "Shelburne", + "Lantz", + "Falmouth", + "Stewiacke", + "Parrsboro", + "Oxford", + "Centreville", + "Wedgeport", + "Mahone Bay" + ], + "Saskatchewan": [ + "Saskatoon", + "Regina", + "Prince Albert", + "Moose Jaw", + "Lloydminster", + "Swift Current", + "Yorkton", + "North Battleford", + "Warman", + "Weyburn", + "Estevan", + "Martensville", + "Corman Park No. 344", + "Melfort", + "Humboldt", + "Meadow Lake", + "La Ronge", + "Flin Flon", + "White City", + "Kindersley", + "Melville", + "Edenwold No. 158", + "Nipawin", + "Battleford", + "Prince Albert No. 461", + "Buckland No. 491", + "Tisdale", + "La Loche", + "Vanscoy No. 345", + "Pelican Narrows", + "Pilot Butte", + "Unity", + "Meadow Lake No. 588", + "Moosomin", + "Esterhazy", + "Rosetown", + "Assiniboia", + "Rosthern No. 403", + "Outlook", + "Canora", + "Biggar", + "Maple Creek", + "Dundurn No. 314", + "Britannia No. 502", + "Rama", + "Swift Current No. 137", + "Blucher", + "Lumsden No. 189", + "Fort Qu'Appelle", + "Indian Head", + "Watrous", + "Orkney No. 244", + "Kamsack", + "Lumsden", + "Regina Beach", + "Shaunavon", + "Wynyard", + "Dalmeny", + "Balgonie", + "Rosthern", + "Shellbrook No. 493", + "Carlyle", + "Langham", + "Hudson Bay", + "Frenchman Butte", + "Wilton No. 472", + "Torch River No. 488", + "Shellbrook", + "Macklin", + "Creighton", + "Laird No. 404", + "Canwood No. 494", + "Spiritwood No. 496", + "Oxbow", + "Wadena", + "Wilkie", + "Ile-a-la-Crosse", + "Estevan No. 5", + "Lanigan", + "South Qu'Appelle No. 157", + "Mervin No. 499", + "Osler", + "Beaver River", + "Moose Jaw No. 161", + "Langenburg", + "Maidstone", + "Kipling", + "Carnduff", + "Foam Lake", + "Hudson Bay No. 394", + "Waldheim", + "Buffalo Narrows", + "Air Ronge", + "Weyburn No. 67", + "Grenfell", + "St. Louis No. 431", + "Pinehouse", + "Preeceville", + "Maple Creek No. 111", + "Birch Hills", + "Kerrobert", + "Eston", + "Kindersley No. 290", + "Davidson", + "Battle River No. 438", + "Delisle", + "Longlaketon No. 219", + "Nipawin No. 487", + "Duck Lake No. 463", + "Gravelbourg", + "Lajord No. 128" + ], + "Newfoundland and Labrador": [ + "St. John's", + "Conception Bay South", + "Paradise", + "Mount Pearl Park", + "Corner Brook", + "Grand Falls", + "Gander", + "Labrador City", + "Portugal Cove-St. Philip's", + "Happy Valley", + "Torbay", + "Stephenville", + "Bay Roberts", + "Clarenville", + "Carbonear", + "Marystown", + "Deer Lake", + "Goulds", + "Channel-Port aux Basques", + "Pasadena", + "Placentia", + "Bonavista", + "Lewisporte", + "Bishops Falls", + "Harbour Grace", + "Springdale", + "Botwood", + "Spaniards Bay", + "Holyrood", + "Logy Bay-Middle Cove-Outer Cove", + "Burin", + "Grand Bank", + "St. Anthony", + "Fogo Island", + "Twillingate", + "New-Wes-Valley", + "Wabana", + "Glovertown", + "Pouch Cove", + "Kippens", + "Wabush", + "Trinity Bay North", + "Victoria", + "Flat Rock", + "Stephenville Crossing", + "Witless Bay", + "Harbour Breton", + "Massey Drive", + "Bay Bulls", + "Upper Island Cove", + "Clarkes Beach", + "Gambo", + "Humbermouth", + "Baie Verte", + "Burgeo", + "Irishtown-Summerside", + "St. George's", + "St. Lawrence", + "St. Alban's", + "Centreville-Wareham-Trinity", + "Nain", + "Harbour Main-Chapel's Cove-Lakeview", + "Fortune", + "Dildo" + ], + "New Brunswick": [ + "Moncton", + "Saint John", + "Fredericton", + "Dieppe", + "Quispamsis", + "Riverview", + "Miramichi", + "Edmundston", + "Bathurst", + "Oromocto", + "Campbellton", + "Shediac", + "Beaubassin East / Beaubassin-est", + "Douglas", + "Sussex", + "Tracadie", + "Sackville", + "Grand Falls", + "Woodstock", + "Burton", + "Saint Marys", + "Memramcook", + "Grand Bay-Westfield", + "Shippagan", + "Coverdale", + "Hanwell", + "Saint Stephen", + "Hampton", + "Beresford", + "Caraquet", + "New Maryland", + "Dundas", + "Simonds", + "Alnwick", + "Studholm", + "Bright", + "Kingston", + "Dalhousie", + "Wellington", + "Kingsclear", + "Wakefield", + "Cocagne", + "Shippegan", + "Lincoln", + "Cap Pele", + "Salisbury", + "Buctouche", + "Grand Manan", + "Saint George", + "Paquetville", + "Minto", + "Upper Miramichi", + "Hardwicke", + "Saint-Quentin", + "Pennfield Ridge", + "Northesk", + "Kent", + "Westfield Beach", + "Allardville", + "Saint-Charles", + "Saint Mary", + "Petit Rocher", + "Eel River Crossing", + "Manners Sutton", + "Richibucto", + "Saint-Louis", + "Saint Andrews", + "Maugerville", + "Brighton", + "Saint-Antoine", + "Northampton", + "Wicklow", + "Neguac", + "Balmoral", + "Southesk", + "Saint-Jacques", + "Florenceville", + "Perth", + "Saint-Joseph", + "Belledune", + "Nauwigewauk", + "Glenelg", + "Saint David", + "Springfield", + "St. George", + "Gordon", + "Southampton", + "Denmark", + "Sussex Corner", + "Petitcodiac", + "Bas Caraquet", + "Upham", + "Cardwell", + "Hillsborough", + "Weldford", + "Norton", + "Charlo", + "Richmond", + "Saint-Leonard", + "Lameque", + "Musquash", + "Queensbury", + "New Bandon", + "Peel", + "Saint James", + "Saint Martins", + "Rogersville", + "McAdam", + "Newcastle", + "Bertrand", + "Saint-Andre", + "Greenwich", + "Chipman", + "Noonan", + "Atholville", + "Durham", + "Havelock", + "Botsford", + "Plaster Rock", + "Wilmot", + "Kedgwick", + "Dorchester", + "Rothesay" + ], + "Prince Edward Island": [ + "Charlottetown", + "Summerside", + "Stratford", + "Cornwall", + "Montague", + "Kensington", + "Miltonvale Park", + "Alberton", + "Souris", + "Malpeque" + ], + "Yukon": [ + "Whitehorse", + "Dawson" + ], + "Northwest Territories": [ + "Yellowknife", + "Hay River", + "Inuvik", + "Fort Smith", + "Behchoko", + "Fort Simpson" + ], + "Nunavut": [ + "Iqaluit", + "Rankin Inlet", + "Arviat", + "Baker Lake", + "Cambridge Bay", + "Igloolik", + "Pond Inlet", + "Pangnirtung", + "Cape Dorset", + "Gjoa Haven", + "Repulse Bay", + "Clyde River", + "Taloyoak", + "Kugluktuk" + ] +} \ No newline at end of file diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..9ea56f7 Binary files /dev/null and b/public/logo.png differ diff --git a/src/API/api.js b/src/API/api.js new file mode 100644 index 0000000..a32f161 --- /dev/null +++ b/src/API/api.js @@ -0,0 +1,53 @@ +import axios from "axios"; + +var API_BASE_URL = "https://ads.dine360ads.com/api/api"; + //API_BASE_URL = "http://82.25.95.117:5000/api"; +//API_BASE_URL = "http://localhost:5000/api"; // Update as needed + +export const api = { + get: async (endpoint) => { + // Show loading + try { + const response = await axios.get(`${API_BASE_URL}${endpoint}`); + return response.data; + } catch (error) { + console.error("GET Error:", error); + throw error; + } finally { + // Hide loading + } + }, + + post: async (endpoint, data) => { + try { + const response = await axios.post(`${API_BASE_URL}${endpoint}`, data); + return response.data; + } catch (error) { + console.error("POST Error:", error); + throw error; + } finally { + } + }, + + put: async (endpoint, data) => { + try { + const response = await axios.put(`${API_BASE_URL}${endpoint}`, data); + return response.data; + } catch (error) { + console.error("PUT Error:", error); + throw error; + } finally { + } + }, + + delete: async (endpoint) => { + try { + const response = await axios.delete(`${API_BASE_URL}${endpoint}`); + return response.data; + } catch (error) { + console.error("DELETE Error:", error); + throw error; + } finally { + } + }, +}; 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..7f77291 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,105 @@ +import { BrowserRouter as Router, Routes, Route, useLocation, Navigate } from "react-router-dom"; +import NotFound from "./Pages/NotFound"; +import Login from "./Pages/Login"; +import AdminDashboard from "./Pages/AdminDashboard"; +import AdsPage from "./Pages/Ads"; +import PartnersPage from "./Pages/PartnersPage"; +import AddPartner from "./Pages/AddPartner"; +import ManagePartner from "./Pages/ManagePartner"; +import ClientsPage from "./Pages/ClientsPage"; +import AddClient from "./Pages/AddClient"; +import ManageClient from "./Pages/ManageClient"; +import ClientPartnerMapping from "./Pages/ClientPartnerMapping"; +import NewAdConfiguration from "./Pages/NewAdConfiguration"; +import Header from "./Components/Header"; +import ManageFilesOrder from "./Pages/ManageFilesOrderPage"; +import SettingsPage from "./Pages/SettingsPage"; +import YouTubePlayer from "./Pages/YT"; + +const Layout = () => { + const location = useLocation(); + const getLoginState = () => { + const storedLogin = JSON.parse(localStorage.getItem('loggedIn')); + if (storedLogin && storedLogin.value) { + const expirationTime = 1 * 60 * 60 * 1000; // 1 hour expiration + if (Date.now() - storedLogin.timestamp < expirationTime) { + return true; + } else { + localStorage.removeItem('loggedIn'); // Expired, remove + return false; + } + } + return false; + }; + + const isLoggedIn = getLoginState(); + + const hideHeaderRoutes = ["/", "/login"]; + const isAdsPage = location.pathname.startsWith("/ads/"); + + + + // App.js + const ProtectedRoute = ({ children }) => { + const location = useLocation(); + const storedLogin = localStorage.getItem('loggedIn'); + let isLoggedIn = false; // Default to false + + if (storedLogin) { + try { + const parsedLogin = JSON.parse(storedLogin); + isLoggedIn = parsedLogin.value; // Access the 'value' property + } catch (error) { + console.error("Error parsing login data:", error); + // Handle parsing error (e.g., clear localStorage) + localStorage.removeItem('loggedIn'); + } + } + + console.log(isLoggedIn); // Log the boolean value + + const isStaticFile = location.pathname.endsWith('.css') || location.pathname.endsWith('.js'); + + if (isStaticFile) { + return children; // Allow access to static files + } + + return isLoggedIn ? children : ; + }; + + return ( + <> + {!hideHeaderRoutes.includes(location.pathname) && !isAdsPage &&
} + + } /> + } /> + } /> + } /> + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + } /> + + + ); +}; + +function App() { + return ( + + + + ); +} + +export default App; \ No newline at end of file diff --git a/src/Components/AdminDashboardComponent.jsx b/src/Components/AdminDashboardComponent.jsx new file mode 100644 index 0000000..24b2461 --- /dev/null +++ b/src/Components/AdminDashboardComponent.jsx @@ -0,0 +1,95 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { useNavigate } from 'react-router-dom'; + +export default function AdminDashboardComponent() { + const navigate = useNavigate(); + return ( + + <> +
+ + navigate("/Partners")} + > +
+ +
+ {/* */} +

Partners

+
+
+ + navigate("/Clients")} + > +
+ + +
+ {/* */} +

Clients

+
+
+ + navigate("/Client-Partner-Mapping")} + > +
+ +
+ {/* */} +

Ads Configuration

+
+
+ + navigate("/Settings")} + > +
+ +
+ {/* */} +

Configure General Settings

+
+
+ +
+ + + ) +} diff --git a/src/Components/ClientsPageCardComponent.jsx b/src/Components/ClientsPageCardComponent.jsx new file mode 100644 index 0000000..fd13643 --- /dev/null +++ b/src/Components/ClientsPageCardComponent.jsx @@ -0,0 +1,87 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useNavigate } from 'react-router-dom'; +import { useLoading } from '../Context/LoadingContext'; + +export default function ClientsCardComponent({ Data, setUpd }) { + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + + const handleDelete = async (clientid) => { + console.log(clientid) + try { + setLoading(true); + const response = await api.delete(`/admin/delete-client/${clientid}`); + console.log(response); + setUpd(clientid) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + + + return ( + + <> +
+ + navigate("/add-client")} + > +
+ +

Add New Client

+
+
+ {Data?.map((client) => ( + navigate(`/manage-client/${client.transid}`)} + > + + {/* Red Delete Button at Top Right Corner */} + + +
+ +
+

{client.name}

+
+
+ + ))} +
+ + + ) +} diff --git a/src/Components/Header.jsx b/src/Components/Header.jsx new file mode 100644 index 0000000..af6f363 --- /dev/null +++ b/src/Components/Header.jsx @@ -0,0 +1,74 @@ +import { Link } from "react-router-dom"; + +const Header = () => { + return ( +
+
+ + {/* Logo and Title */} +
+ Logo +

+ Dine 360 Ads +

+
+ + {/* Navigation Menu */} + + + {/* Logout Button Styled as Link */} + + Logout + +
+
+ ); +}; + +export default Header; diff --git a/src/Components/HoveringCardComponent.jsx b/src/Components/HoveringCardComponent.jsx new file mode 100644 index 0000000..bce271a --- /dev/null +++ b/src/Components/HoveringCardComponent.jsx @@ -0,0 +1,57 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; + +export default function HoveringCardComponent({ Data }) { + return ( + + <> +
+ + navigate("/add-client")} + > +
+ +

Add New Client

+
+
+ {Data?.map((client) => ( + navigate(`/manage-client/${client.id}`)} + > +
+ +
+

{client.name}

+

🕒 {client.open_time} - {client.close_time}

+ +
+ + {client.is_active ? "Active" : "Inactive"} +
+
+
+ ))} +
+ + + ) +} diff --git a/src/Components/LoadingScreen.jsx b/src/Components/LoadingScreen.jsx new file mode 100644 index 0000000..d8a45b3 --- /dev/null +++ b/src/Components/LoadingScreen.jsx @@ -0,0 +1,20 @@ +import { motion } from "framer-motion"; + +const LoadingScreen = () => { + return ( + + + + ); +}; + +export default LoadingScreen; diff --git a/src/Components/MappingComponent.jsx b/src/Components/MappingComponent.jsx new file mode 100644 index 0000000..1897434 --- /dev/null +++ b/src/Components/MappingComponent.jsx @@ -0,0 +1,87 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useNavigate } from 'react-router-dom'; +import { useLoading } from '../Context/LoadingContext'; + +export default function MappingComponent({ Data, setUpd }) { + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + + const handleDelete = async (clientid) => { + console.log(clientid) + try { + setLoading(true); + const response = await api.delete(`/admin/delete-client/${clientid}`); + console.log(response); + setUpd(clientid) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + + + return ( + + <> +
+ + navigate("/new-ad-configuration")} + > +
+ +

Add / Edit Ad Configuration

+
+
+ {Data?.map((client) => ( + navigate(`/ads-order-configuration/${client.transid}`)} + > + + + {/* */} + +
+ +
+

{client.name}

+
+
+ + ))} +
+ + + ) +} diff --git a/src/Components/NewMappingCardComponent copy.jsx b/src/Components/NewMappingCardComponent copy.jsx new file mode 100644 index 0000000..1cee580 --- /dev/null +++ b/src/Components/NewMappingCardComponent copy.jsx @@ -0,0 +1,74 @@ +import React, { useEffect, useState } from "react"; +import { motion } from "framer-motion"; +import { useNavigate } from "react-router-dom"; +import { useLoading } from "../Context/LoadingContext"; +import NewMappingSubPartnersComponent from "./NewMappingSubPartnersComponent"; +import { api } from "../API/api" +export default function NewMappingCardComponent({ Data, setUpd }) { + const navigate = useNavigate(); + const { setLoading } = useLoading(); + const [activeCard, setActiveCard] = useState(null); // Track active sub-card + const [partners, setPartners] = useState(null); + + const toggleSubCard = (transid) => { + setActiveCard(activeCard === transid ? null : transid); // Toggle logic + }; + + + useEffect(() => { + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get("/admin/partners"); + setPartners(response); + + + } catch (error) { + console.error("Error fetching clients:", error); + } finally { + setLoading(false); + } + }; + fetchClients(); + }, []); + + return ( +
+ {Data?.map((client,i) => ( +
+ toggleSubCard(client.transid)} + > +
+
+

{client.name}

+
+ + {activeCard === client.transid && ( + + + + )} +
+ + +
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/Components/NewMappingSubPartnersComponent.jsx b/src/Components/NewMappingSubPartnersComponent.jsx new file mode 100644 index 0000000..c2c62c1 --- /dev/null +++ b/src/Components/NewMappingSubPartnersComponent.jsx @@ -0,0 +1,177 @@ +import { useEffect, useState } from "react"; +import { motion } from "framer-motion"; +import NewMappingSubScreensComponent from "./NewMappingSubScreensComponent"; +import { useLoading } from '../Context/LoadingContext'; +import { api } from "../API/api"; + +export default function NewMappingSubPartnersComponent({ client, partners, setUpd }) { + const [expandedPartners, setExpandedPartners] = useState({}); + const { setLoading } = useLoading(); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const [files, setFiles] = useState([]); + const [selectedPartners, setSelectedPartners] = useState([]); + const [searchTerm, setSearchTerm] = useState(''); + const [showSelectedList, setShowSelectedList] = useState(false); + const [showButtonText, setShowButtonText] = useState("Show Selected Partners"); + const [showButtonColor, setShowButtonColor] = useState("bg-blue-600"); + const [cityFilter, setCityFilter] = useState(''); + const [provinceFilter, setProvinceFilter] = useState(''); + + useEffect(() => { + fetchFiles(); + }, []); + + const fetchFiles = async () => { + try { + setLoading(true); + const response = await api.get(`/client/files/${client.transid}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false); + }; + + const handlePartnerSelection = (partnerId) => { + setSelectedPartners((prev) => { + if (prev.includes(partnerId)) { + return prev.filter((id) => id !== partnerId); + } else { + return [...prev, partnerId]; + } + }); + }; + + const handleShowSelected = () => { + setShowSelectedList(!showSelectedList); + setShowButtonText(showSelectedList ? "Show Selected Partners" : "Hide Selected Partners"); + setShowButtonColor(showSelectedList ? "bg-blue-600" : "bg-green-600"); + }; + + const filteredPartners = partners?.filter((partner) => + partner.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + const sortedPartners = filteredPartners?.slice().sort((a, b) => { + const aSelected = selectedPartners.includes(a.transid); + const bSelected = selectedPartners.includes(b.transid); + if (aSelected && !bSelected) return -1; + if (!aSelected && bSelected) return 1; + return 0; + }).filter(partner => { + if (cityFilter && partner.city !== cityFilter) return false; + if (provinceFilter && partner.state !== provinceFilter) return false; + return true; + }); + + const uniqueCities = [...new Set(partners?.map(partner => partner.city).filter(Boolean))]; + const uniqueProvinces = [...new Set(partners?.map(partner => partner.state).filter(Boolean))]; + + return ( +
e.stopPropagation()}> +

Client Ads List

+
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name; + const fileUrl = BACKEND + file.file_path; + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + + {fileName} + + {isImage && ({fileName})} + {isVideo && ()} +
  • + ); + }) + ) : ( +

    No Ads uploaded yet.

    + )} +
+ +

Available Partners

+ +
+ { + e.stopPropagation(); + setSearchTerm(e.target.value); + }} + className="w-full bg-gray-700 p-2 rounded-lg text-white" + /> + + +
+ +
    + {sortedPartners?.length > 0 ? ( + sortedPartners?.map((partner, index) => ( +
    + +
    + )) + ) : ( +

    No Partners found.

    + )} +
+ + + + {showSelectedList && selectedPartners.length > 0 && ( +
+

Sub Screens:

+ {selectedPartners.map((partnerId) => { + const partner = partners.find((p) => p.transid === partnerId); + return ( +
+ +
+ ); + })} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/Components/NewMappingSubPartnersComponent_28_03_25_Bak.jsx b/src/Components/NewMappingSubPartnersComponent_28_03_25_Bak.jsx new file mode 100644 index 0000000..9cbcfad --- /dev/null +++ b/src/Components/NewMappingSubPartnersComponent_28_03_25_Bak.jsx @@ -0,0 +1,96 @@ +import { useEffect, useState } from "react"; +import { motion } from "framer-motion"; +import NewMappingSubScreensComponent from "./NewMappingSubScreensComponent"; // Ensure this exists +import { useLoading } from '../Context/LoadingContext'; +import { api } from "../API/api"; + +export default function NewMappingSubPartnersComponent({ client, partners, setUpd }) { + const [expandedPartners, setExpandedPartners] = useState({}); + const { setLoading } = useLoading(); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const toggleSubScreens = (event, partnerId) => { + + event.stopPropagation(); // ⛔️ Prevents event from closing parent card! + setExpandedPartners((prev) => ({ + ...prev, + [partnerId]: !prev[partnerId], + })); + }; + + const [files, setFiles] = useState([]); + useEffect(() => { + fetchFiles(); + }, []); + + // Fetch Client Files + const fetchFiles = async () => { + try { + setLoading(true); + const response = await api.get(`/client/files/${client.transid}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false); + }; + return ( +
e.stopPropagation()}> + +

Client Ads List

+
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name; + const fileUrl = BACKEND + file.file_path; + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + + {fileName} + + {isImage && ({fileName})} + {isVideo && ()} +
  • + ); + }) + ) : ( +

    No Ads uploaded yet.

    + )} +
+ +

Available Partners

+
    + {partners?.length > 0 ? ( + partners?.map((partner, index) => ( +
    + {/* Clickable Partner Name */} +
  • toggleSubScreens(e, partner.transid)} + > + {index + 1}. {partner.name} +
  • + + {/* Conditionally Show SubScreens */} + {expandedPartners[partner.transid] && ( + + + + )} +
    + )) + ) : ( +

    No Partners are Registered Yet.

    + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/Components/NewMappingSubScreensComponent.jsx b/src/Components/NewMappingSubScreensComponent.jsx new file mode 100644 index 0000000..12a7810 --- /dev/null +++ b/src/Components/NewMappingSubScreensComponent.jsx @@ -0,0 +1,332 @@ +import React, { useEffect, useState } from "react"; +import { useLoading } from '../Context/LoadingContext'; +import { api } from "../API/api"; +import { useMemo } from "react"; + +export default function NewMappingSubScreensComponent({ partner, client, files }) { + const daysOfWeek = ["M", "T", "W", "Th", "F", "S", "Su"]; + const { setLoading } = useLoading(); + const [screens, setScreens] = useState([]); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const [selectedFiles, setSelectedFiles] = useState({}); + const [screenSelections, setScreenSelections] = useState({}); + const [FileDurations, setFileDurations] = useState({}); + const [selectAllFiles, setSelectAllFiles] = useState({}); + const [selectAllDays, setSelectAllDays] = useState({}); + const [databaseData, setDatabaseData] = useState([]); + const [selectAllColumnFiles, setSelectAllColumnFiles] = useState(false); + + const fetchScreens = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/get-screen/${partner.transid}`); + setScreens(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false); + }; + + const fetchMappingsFromDB = async (clientId, partnerId) => { + try { + setLoading(true); + const response = await api.get(`/admin/client-partner-mappings?clientid=${clientId}&partnerid=${partnerId}`); + setDatabaseData(response); + } catch (error) { + console.error("Error fetching mappings:", error); + alert("Error fetching mappings from the database."); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + if (client && partner) { + fetchMappingsFromDB(client.transid, partner.transid); + } + }, [client, partner]); + + const handleFileSelection = (screenId, fileId) => { + setSelectedFiles(prev => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [fileId]: !prev[screenId]?.[fileId], + }, + })); + }; + + const handleScreenCheckboxChange = (screenId, fileId, day) => { + setScreenSelections(prev => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [fileId]: { + ...prev[screenId]?.[fileId], + [day]: !prev[screenId]?.[fileId]?.[day], + }, + }, + })); + }; + + const handleSelectAllFiles = (screenId, checked) => { + setSelectAllFiles(prev => ({ ...prev, [screenId]: checked })); + setSelectedFiles(prev => { + const screenFiles = files.reduce((acc, file) => ({ ...acc, [file.transid]: checked }), {}); + return { ...prev, [screenId]: screenFiles }; + }); + }; + + const handleSelectAllDays = (screenId, fileId, checked) => { + setSelectAllDays(prev => ({ ...prev, [screenId]: { ...prev[screenId], [fileId]: checked } })); + setScreenSelections(prev => { + const screenDays = daysOfWeek.reduce((acc, day) => ({ ...acc, [day]: checked }), {}); + return { ...prev, [screenId]: { ...prev[screenId], [fileId]: screenDays } }; + }); + }; + const areAllFilesSelected = () => + screens.length > 0 && + screens.every(screen => + files.every(file => + selectedFiles[screen.transid]?.[file.transid] === true + ) + );const allFilesSelected = useMemo( + () => areAllFilesSelected(), + [screens, files, selectedFiles] +); + + const handleSelectAllColumnFiles = (checked) => { + setSelectAllColumnFiles(checked); + setSelectedFiles(prev => { + const updatedSelectedFiles = {}; + screens.forEach(screen => { + updatedSelectedFiles[screen.transid] = {}; + files.forEach(file => { + updatedSelectedFiles[screen.transid][file.transid] = checked; + }); + }); + return updatedSelectedFiles; + }); + }; + + const handleDurationChange = (screenId, fileId, duration) => { + setFileDurations(prev => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [fileId]: duration, + }, + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + + let finalData = []; + screens.forEach(screen => { + const filesSelectedForScreen = selectedFiles[screen.transid] || {}; + + Object.keys(filesSelectedForScreen).forEach(fileId => { + if (filesSelectedForScreen[fileId]) { + const file = files.find(f => f.transid === fileId); + if (!file) return; + const daysSelected = screenSelections[screen.transid]?.[fileId] || {}; + const imageduration = FileDurations[screen.transid]?.[fileId] || 10; + finalData.push({ + clientid: client.transid, + partnerid: partner.transid, + screenid: screen.transid, + fileid: file.transid, + file_path: file.file_path, + ismonday: daysSelected["M"] ? 1 : 0, + istuesday: daysSelected["T"] ? 1 : 0, + iswednesday: daysSelected["W"] ? 1 : 0, + isthursday: daysSelected["Th"] ? 1 : 0, + isfriday: daysSelected["F"] ? 1 : 0, + issaturday: daysSelected["S"] ? 1 : 0, + issunday: daysSelected["Su"] ? 1 : 0, + imageduration: imageduration + }); + } + }); + }); + + console.log("Final Data to Insert:", finalData); + + try { + await api.post("/admin/add-client-partner-mapping", finalData); + alert("Client Partner Mapping data added successfully!"); + fetchMappingsFromDB(client.transid, partner.transid); + } catch (error) { + console.error("Error adding client partner mapping:", error); + alert("Error adding client partner mapping. Please check console for details."); + } + setLoading(false); + }; + + useEffect(() => { + fetchScreens(); + + const initialSelectedFiles = {}; + const initialScreenSelections = {}; + const initialFileDurations = {}; + databaseData?.forEach(item => { + if (!initialSelectedFiles[item.screenid]) { + initialSelectedFiles[item.screenid] = {}; + } + initialSelectedFiles[item.screenid][item.fileid] = true; + + if (!initialScreenSelections[item.screenid]) { + initialScreenSelections[item.screenid] = {}; + } + if (!initialScreenSelections[item.screenid][item.fileid]) { + initialScreenSelections[item.screenid][item.fileid] = {}; + } + initialScreenSelections[item.screenid][item.fileid]["M"] = item.ismonday === 1; + initialScreenSelections[item.screenid][item.fileid]["T"] = item.istuesday === 1; + initialScreenSelections[item.screenid][item.fileid]["W"] = item.iswednesday === 1; + initialScreenSelections[item.screenid][item.fileid]["Th"] = item.isthursday === 1; + initialScreenSelections[item.screenid][item.fileid]["F"] = item.isfriday === 1; + initialScreenSelections[item.screenid][item.fileid]["S"] = item.issaturday === 1; + initialScreenSelections[item.screenid][item.fileid]["Su"] = item.issunday === 1; + if (!initialFileDurations[item.screenid]) { + initialFileDurations[item.screenid] = {}; + } + if (!initialFileDurations[item.screenid][item.fileid]) { + initialFileDurations[item.screenid][item.fileid] = {}; + } + initialFileDurations[item.screenid][item.fileid] = item.imageduration; + }); + setFileDurations(initialFileDurations) + console.log(initialFileDurations) + setSelectedFiles(initialSelectedFiles); + setScreenSelections(initialScreenSelections); + }, [databaseData]); + + +const areAllDaysChecked = (screenId, fileId) => + daysOfWeek.every(day => + screenSelections[screenId]?.[fileId]?.[day] === true + ); + + const handleDeleteClient = async (e) => { + e.preventDefault(); + setLoading(true); + + if (client && partner) { + fetchMappingsFromDB(client.transid, partner.transid); + } else { + alert("Client / Partner data Not Loaded Yet..."); + return + } + + try { + await api.delete(`/admin/delete-client-partner-mapping/${partner.transid}/${client.transid}`); + + alert("Client has been removed from the partner successfully!"); + + } catch (error) { + console.error("Error removing client partner mapping:", error); + alert("Error removing client partner mapping. Please check console for details."); + } + setLoading(false); + }; + + + return ( +
+

{partner.name} - Assign Screens

+
+ + + + + + {daysOfWeek.map(day => ( + + ))} + + + + {screens.map(screen => ( + files.map(file => ( + + + + + {daysOfWeek.map(day => ( + + ))} + + )) + ))} + +
Screen Name + + {day}
{screen.name} +
+
+ + +
+ + handleDurationChange(screen.transid, file.transid, e.target.value)} + maxLength={3} + pattern="\d{1,3}" + inputMode="numeric" + placeholder="000" + title="Enter up to 3 digits only" + className="w-16 p-2 text-center text-sm border border-gray-300 rounded-md shadow-inner" + /> +
+
+ handleScreenCheckboxChange(screen.transid, file.transid, day)} + /> +
+
+
+
+ + {files.length > 0 && ( + + )} + {files.length > 0 && ( + + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/Components/NewMappingSubScreensComponent_29_03_25_Bak.jsx b/src/Components/NewMappingSubScreensComponent_29_03_25_Bak.jsx new file mode 100644 index 0000000..4e12933 --- /dev/null +++ b/src/Components/NewMappingSubScreensComponent_29_03_25_Bak.jsx @@ -0,0 +1,304 @@ +// Part 1: Component Logic and State Management +import React, { useEffect, useState } from "react"; +import { useLoading } from '../../../Context/LoadingContext'; +import { api } from "../../../API/api"; + +export default function NewMappingSubScreensComponent({ partner, client, files }) { + const daysOfWeek = ["M", "T", "W", "Th", "F", "S", "Su"]; + const { setLoading } = useLoading(); + const [screens, setScreens] = useState([]); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const [selectedFiles, setSelectedFiles] = useState({}); + const [screenSelections, setScreenSelections] = useState({}); + const [selectAllFiles, setSelectAllFiles] = useState({}); + const [selectAllDays, setSelectAllDays] = useState({}); + const [databaseData, setDatabaseData] = useState([]); + + + + const fetchScreens = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/get-screen/${partner.transid}`); + setScreens(response); + + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false); + }; + + + + const fetchMappingsFromDB = async (clientId, partnerId) => { + try { + setLoading(true); + const response = await api.get(`/admin/client-partner-mappings?clientid=${clientId}&partnerid=${partnerId}`); // Use the correct API endpoint + setDatabaseData(response); // Assuming you have a state variable called databaseData and a setter function called setDatabaseData + } catch (error) { + console.error("Error fetching mappings:", error); + alert("Error fetching mappings from the database."); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + // Assuming client.transid and partner.transid are available in your component's props or state + if (client && partner) { + fetchMappingsFromDB(client.transid, partner.transid); + } + }, [client, partner]); + + + const handleFileSelection = (screenId, fileId) => { + setSelectedFiles(prev => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [fileId]: !prev[screenId]?.[fileId], + }, + })); + }; + + const handleScreenCheckboxChange = (screenId, day) => { + setScreenSelections(prev => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [day]: !prev[screenId]?.[day], + }, + })); + }; + + const handleSelectAllFiles = (screenId, checked) => { + setSelectAllFiles(prev => ({ ...prev, [screenId]: checked })); + setSelectedFiles(prev => { + const screenFiles = files.reduce((acc, file) => ({ ...acc, [file.transid]: checked }), {}); + return { ...prev, [screenId]: screenFiles }; + }); + }; + + const handleSelectAllDays = (screenId, checked) => { + setSelectAllDays(prev => ({ ...prev, [screenId]: checked })); + setScreenSelections(prev => { + const screenDays = daysOfWeek.reduce((acc, day) => ({ ...acc, [day]: checked }), {}); + return { ...prev, [screenId]: screenDays }; + }); + }; + + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + setLoading(true); + + let finalData = []; + screens.forEach(screen => { + const filesSelectedForScreen = selectedFiles[screen.transid] || {}; + const daysSelected = screenSelections[screen.transid] || {}; + + // Check if at least one file and one day are selected + const isFileSelected = Object.values(filesSelectedForScreen).some(Boolean); + const isDaySelected = Object.values(daysSelected).some(Boolean); + + if (isFileSelected && isDaySelected) { + Object.keys(filesSelectedForScreen).forEach(fileId => { + if (filesSelectedForScreen[fileId]) { + const file = files.find(f => f.transid === fileId); + if (!file) return; + finalData.push({ + clientid: client.transid, + partnerid: partner.transid, + screenid: screen.transid, + fileid: file.transid, + file_path: file.file_path, + ismonday: daysSelected["M"] ? 1 : 0, + istuesday: daysSelected["T"] ? 1 : 0, + iswednesday: daysSelected["W"] ? 1 : 0, + isthursday: daysSelected["Th"] ? 1 : 0, + isfriday: daysSelected["F"] ? 1 : 0, + issaturday: daysSelected["S"] ? 1 : 0, + issunday: daysSelected["Su"] ? 1 : 0, + }); + } + }); + } + //if nothing is selected for the screen, or only files or only days are selected then the screen is not added to the finalData. + }); + console.log("Final Data to Insert:", finalData); + setLoading(true); + + try { + await api.post("/admin/add-client-partner-mapping", finalData); // Use your API helper and the correct endpoint + alert("Client Partner Mapping data added successfully!"); + fetchMappingsFromDB() + // Optionally, you might want to navigate or refresh data here. + // navigate("/mappings"); // Example navigation + } catch (error) { + console.error("Error adding client partner mapping:", error); + alert("Error adding client partner mapping. Please check console for details."); + } + setLoading(false); + setLoading(false); + }; + + + + useEffect(() => { + fetchScreens(); + + // Initialize state from databaseData + const initialSelectedFiles = {}; + const initialScreenSelections = {}; + + databaseData?.forEach(item => { + if (!initialSelectedFiles[item.screenid]) { + initialSelectedFiles[item.screenid] = {}; + } + if (!initialSelectedFiles[item.screenid][item.fileid]) { + initialSelectedFiles[item.screenid][item.fileid] = true; + } + + if (!initialScreenSelections[item.screenid]) { + initialScreenSelections[item.screenid] = {}; + } + initialScreenSelections[item.screenid]["M"] = item.ismonday === 1; + initialScreenSelections[item.screenid]["T"] = item.istuesday === 1; + initialScreenSelections[item.screenid]["W"] = item.iswednesday === 1; + initialScreenSelections[item.screenid]["Th"] = item.isthursday === 1; + initialScreenSelections[item.screenid]["F"] = item.isfriday === 1; + initialScreenSelections[item.screenid]["S"] = item.issaturday === 1; + initialScreenSelections[item.screenid]["Su"] = item.issunday === 1; + }); + + setSelectedFiles(initialSelectedFiles); + setScreenSelections(initialScreenSelections); + + }, [databaseData]); + + // Part 2: JSX Rendering + return ( +
+

{partner.name} - Assign Screens

+
+ + + + + + {daysOfWeek.map(day => ( + + ))} + + + + {screens.map(screen => ( + + + + {daysOfWeek.map(day => ( + + ))} + + ))} + +
Screen NameAds List{day}
+ {screen.name} + + +
+ + {files.map(file => ( + + ))} +
+
+ handleScreenCheckboxChange(screen.transid, day)} + /> +
+
+
+
+

Client Ads List

+
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name; + const fileUrl = BACKEND + file.file_path; + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + + {fileName} + + + {isImage && ( + {fileName} + )} + + {isVideo && ( + + )} +
  • + ); + }) + ) : ( +

    + No Ads uploaded yet. +

    + )} +
+ {files.length > 0 && ( + + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/Components/NewMappingSubScreensComponent_Bak.jsx b/src/Components/NewMappingSubScreensComponent_Bak.jsx new file mode 100644 index 0000000..8accde5 --- /dev/null +++ b/src/Components/NewMappingSubScreensComponent_Bak.jsx @@ -0,0 +1,193 @@ +import React, { useEffect, useState } from "react"; +import { useLoading } from '../Context/LoadingContext'; +import { api } from "../API/api"; + +export default function NewMappingSubScreensComponent({ partner, client, files }) { + const daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + + const { setLoading } = useLoading(); + const [screens, setScreens] = useState([]); + + const fetchScreens = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/get-screen/${partner.transid}`); + setScreens(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + const screens1 = [ + { id: 1, name: "Screen A" }, + { id: 2, name: "Screen B" }, + { id: 3, name: "Screen C" }, + ]; // Replace with actual screen names if dynamic + + + const BACKEND = 'https://ads.dine360ads.com/api//'; + + const [selectedFiles, setSelectedFiles] = useState([]); + const [screenSelections, setScreenSelections] = useState({}); // Stores selected checkboxes + + + // Handle file checkbox selection + const handleFileSelection = (fileId) => { + setSelectedFiles((prev) => + prev.includes(fileId) ? prev.filter((id) => id !== fileId) : [...prev, fileId] + ); + }; + + // Handle weekday checkbox selection for screens + const handleScreenCheckboxChange = (screenId, day) => { + setScreenSelections((prev) => ({ + ...prev, + [screenId]: { + ...prev[screenId], + [day]: !prev[screenId]?.[day], // Toggle checkbox + }, + })); + }; + + // Handle Submit - Collect data to insert into database + const handleSubmit = () => { + if (selectedFiles.length === 0) { + alert("No files selected!"); + return; + } + + let finalData = []; + + selectedFiles.forEach((fileId) => { + const file = files.find((f) => f.transid === fileId); + if (!file) return; + + screens.forEach((screen) => { + const daysSelected = screenSelections[screen.transid] || {}; + + finalData.push({ + clientid: client.transid, + partnerid: partner.transid, + screenid: screen.transid, + fileid: file.transid, + file_path: file.file_path, + ismonday: daysSelected["Monday"] ? 1 : 0, + istuesday: daysSelected["Tuesday"] ? 1 : 0, + iswednesday: daysSelected["Wednesday"] ? 1 : 0, + isthursday: daysSelected["Thursday"] ? 1 : 0, + isfriday: daysSelected["Friday"] ? 1 : 0, + issaturday: daysSelected["Saturday"] ? 1 : 0, + issunday: daysSelected["Sunday"] ? 1 : 0, + }); + }); + }); + + console.log("Final Data to Insert:", finalData); + alert("Data formatted successfully! Check console for details."); + }; + + useEffect(() => { + fetchScreens() + }, []); + + return ( +
+

{partner.name} - Assign Screens

+
+ + + + + + {daysOfWeek.map((day) => ( + + ))} + + + + {screens.map((screen) => ( + + + + + {daysOfWeek.map((day) => ( + + ))} + + ))} + +
Screen NameAds List{day}
{screen.name}{screen.adslist} + handleScreenCheckboxChange(screen.transid, day)} + /> +
+
+
+ + {/* File Selection */} +
+

Client Ads List

+ +
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name; + const fileUrl = BACKEND + file.file_path; + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + {/* Checkbox at Top Left */} + handleFileSelection(file.transid)} + /> + + + {fileName} + + + {isImage && ( + {fileName} + )} + + {isVideo && ( + + )} +
  • + ); + }) + ) : ( +

    + No Ads uploaded yet. +

    + )} +
+ + {files.length > 0 && ( + + )} +
+
+ ); +} diff --git a/src/Components/PageCardComponent.jsx b/src/Components/PageCardComponent.jsx new file mode 100644 index 0000000..57e8917 --- /dev/null +++ b/src/Components/PageCardComponent.jsx @@ -0,0 +1,87 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useNavigate } from 'react-router-dom'; +import { useLoading } from '../Context/LoadingContext'; + +export default function ClientsCardComponent({ Data,setUpd }) { + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + + const handleDelete = async (clientid) => { + console.log(clientid) + try { + setLoading(true); + const response = await api.delete(`/admin/delete-client/${clientid}`); + console.log(response); + setUpd(clientid) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + + + return ( + + <> +
+ + navigate("/add-client")} + > +
+ +

Add New Client

+
+
+ {Data?.map((client) => ( + navigate(`/manage-client/${client.transid}`)} + > + + {/* Red Delete Button at Top Right Corner */} + + +
+ +
+

{client.name}

+
+
+ + ))} +
+ + + ) +} diff --git a/src/Components/PartnersPageCardComponent.jsx b/src/Components/PartnersPageCardComponent.jsx new file mode 100644 index 0000000..dcdbb8e --- /dev/null +++ b/src/Components/PartnersPageCardComponent.jsx @@ -0,0 +1,92 @@ +import React from 'react' +import { motion } from "framer-motion"; + +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useNavigate } from 'react-router-dom'; +import { useLoading } from '../Context/LoadingContext'; + +export default function PartnersCardComponent({ Data, setUpd }) { + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + + const handleDelete = async (partnerid) => { + console.log(partnerid) + try { + setLoading(true); + const response = await api.delete(`/admin/delete-partner/${partnerid}`); + console.log(response); + setUpd(partnerid) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + + + + return ( + + <> +
+ + navigate("/add-partner")} + > +
+ +

Add New Partner

+
+
+ {Data?.map((client) => ( + navigate(`/manage-partner/${client.transid}`)} + > + + {/* Red Delete Button at Top Right Corner */} + +
+ +
+

{client.name}

+

🕒 {client.open_time} - {client.close_time}

+ + {/*
+ + {client.is_active ? "Active" : "Inactive"} +
*/} +
+
+ ))} +
+ + + ) +} diff --git a/src/Components/ViewPartnerAdsConfiguration.jsx b/src/Components/ViewPartnerAdsConfiguration.jsx new file mode 100644 index 0000000..6a2f052 --- /dev/null +++ b/src/Components/ViewPartnerAdsConfiguration.jsx @@ -0,0 +1,131 @@ +import React, { useEffect, useState } from "react"; +import { useLoading } from '../Context/LoadingContext'; +import { api } from "../API/api"; + +export default function ViewPartnerAdsConfiguration({ data }) { + const daysOfWeek = ["M", "T", "W", "Th", "F", "S", "Su"]; + const { setLoading } = useLoading(); + const [screens, setScreens] = useState([]); + const [selectedFiles, setSelectedFiles] = useState({}); + const [screenSelections, setScreenSelections] = useState({}); + const [selectAllFiles, setSelectAllFiles] = useState({}); + const [selectAllDays, setSelectAllDays] = useState({}); + const [selectAllColumnFiles, setSelectAllColumnFiles] = useState(false); + + // Extract unique screens from the data prop + useEffect(() => { + if (data) { + console.log(data) + const uniqueScreens = [...new Map(data.map(item => [item.screenid, { + transid: item.screenid, + name: item.screenname || item.screenid // Use screenname if available, otherwise screenid + }])).values()]; + console.log(uniqueScreens) + setScreens(uniqueScreens); + } + }, [data]); + + useEffect(() => { + if (data) { + const initialSelectedFiles = {}; + const initialScreenSelections = {}; + + data.forEach(item => { + if (!initialSelectedFiles[item.screenid]) { + initialSelectedFiles[item.screenid] = {}; + } + initialSelectedFiles[item.screenid][item.fileid] = true; + + if (!initialScreenSelections[item.screenid]) { + initialScreenSelections[item.screenid] = {}; + } + if (!initialScreenSelections[item.screenid][item.fileid]) { + initialScreenSelections[item.screenid][item.fileid] = {}; + } + initialScreenSelections[item.screenid][item.fileid]["M"] = item.ismonday === 1; + initialScreenSelections[item.screenid][item.fileid]["T"] = item.istuesday === 1; + initialScreenSelections[item.screenid][item.fileid]["W"] = item.iswednesday === 1; + initialScreenSelections[item.screenid][item.fileid]["Th"] = item.isthursday === 1; + initialScreenSelections[item.screenid][item.fileid]["F"] = item.isfriday === 1; + initialScreenSelections[item.screenid][item.fileid]["S"] = item.issaturday === 1; + initialScreenSelections[item.screenid][item.fileid]["Su"] = item.issunday === 1; + }); + + setSelectedFiles(initialSelectedFiles); + setScreenSelections(initialScreenSelections); + } + }, [data]); + + + + + + + return ( + +
+ {/* //

Ad Configurations

*/} + {screens.map(screen => { + console.log(screen) + const filesForScreen = data.filter(item => item.screenid === screen.transid); + const uniqueFilesForScreen = [...new Set(filesForScreen.map(item => ({ + transid: item.fileid, + file_name: item.file_path.split('/').pop() // Extract filename from path + })))]; + + return ( +
+

{screen.name}

+
+ + + + + {daysOfWeek.map(day => ( + + ))} + + + + {uniqueFilesForScreen.map(file => { + // Find the first occurrence of this file for this screen to get initial day states + const fileData = filesForScreen.find(item => item.fileid === file.transid); + if (!fileData) return null; // Should not happen if uniqueFilesForScreen is correct + + return ( + + + {daysOfWeek.map(day => ( + + ))} + + ); + })} + +
Ad Name{day}
+ + + null} + /> +
+
+
+ ); + })} + +
+
+ ); +} \ No newline at end of file diff --git a/src/Context/LoadingContext.jsx b/src/Context/LoadingContext.jsx new file mode 100644 index 0000000..7b6c780 --- /dev/null +++ b/src/Context/LoadingContext.jsx @@ -0,0 +1,17 @@ +import { createContext, useState, useContext } from "react"; +import LoadingScreen from "../Components/LoadingScreen"; + +const LoadingContext = createContext(); + +export const LoadingProvider = ({ children }) => { + const [loading, setLoading] = useState(false); + + return ( + + {loading && } {/* Show loading screen when loading is true */} + {children} + + ); +}; + +export const useLoading = () => useContext(LoadingContext); diff --git a/src/Pages/AddClient.jsx b/src/Pages/AddClient.jsx new file mode 100644 index 0000000..9d90b71 --- /dev/null +++ b/src/Pages/AddClient.jsx @@ -0,0 +1,129 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; + +const AddClient = () => { + const [formData, setFormData] = useState({ name: "", emailid: "", phoneno: "", address: "" }); + const { setLoading } = useLoading(); + const navigate = useNavigate(); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleFileChange = (e) => { + setFormData({ ...formData, image: e.target.files[0] }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + try { + await api.post("/admin/add-client", formData); + navigate("/clients"); + } catch (error) { + console.error("Error adding Partner:", error); + } + setLoading(false); + }; + + return ( +
+ navigate("/clients")} + > + Back + + + ➕ Add New Client + +
+ +
+ + + + + {/* + + */} + + + + + + + + + + + + + + +
+ + Submit + +
+
+ ); +}; + +export default AddClient diff --git a/src/Pages/AddPartner.jsx b/src/Pages/AddPartner.jsx new file mode 100644 index 0000000..1c2a20c --- /dev/null +++ b/src/Pages/AddPartner.jsx @@ -0,0 +1,310 @@ +import { useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import Select from 'react-select'; +import canada_cities from '../assets/canada_cities.json'; + +const AddPartner = () => { + const [uploading, setUploading] = useState(false); + const [formData, setFormData] = useState({ + name: "", + open_time: "", + close_time: "", + image: null, + address: "", + city: "", + state: "", + pincode: "", + screens: "", + }); + const { setLoading } = useLoading(); + const navigate = useNavigate(); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + + const handleFileUpload = async (file,id) => { + if (!file) return; + + setUploading(true); + const formData = new FormData(); + formData.append("file", file); + formData.append("file_name", file.name); + formData.append("client_id", id); // Attach client ID + + try { + console.log(formData) + setLoading(true) + await api.post("/files/update-partner-logo", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + navigate("/partners"); + + // Refresh file list after each successful upload + //fetchFiles(); + } catch (error) { + console.error(`File upload failed for ${file.name}:`, error); + // Optionally, you could add some user feedback here for individual file failures + } finally { + setUploading(false); // Keep this false, as we're handling individual uploads + setLoading(false) + } + }; + + const handleFileChange = async (e) => { + + setFormData({ ...formData, image: e.target.files[0] }); + }; + const handleSubmit = async (e) => { + e.preventDefault(); + try { + console.log("iuytg") + setLoading(true); + var data = await api.post("/admin/add-partner", formData); + console.log(data) + console.log("iuytg") + await handleFileUpload(formData.image,data.id); + navigate("/Partners"); + } catch (error) { + console.error("Error adding Partner:", error); + } + setLoading(false); + }; + + const [selectedProvince, setSelectedProvince] = useState(null); + const [selectedCity, setSelectedCity] = useState(null); + + const provinceOptions = useMemo( + () => + Object.keys(canada_cities).map((province) => ({ + value: province, + label: province, + })), + [canada_cities] + ); + + const cityOptions = useMemo( + () => + selectedProvince + ? canada_cities[selectedProvince.value].map((city) => ({ + value: city, + label: city, + })) + : [], + [selectedProvince, canada_cities] + ); + + const handleProvinceChange = (selectedOption) => { + setSelectedProvince(selectedOption); + setSelectedCity(null); + setFormData({ ...formData, state: selectedOption?.value || "" }); // Update state in formData + }; + + const handleCityChange = (selectedOption) => { + setSelectedCity(selectedOption); + setFormData({ ...formData, city: selectedOption?.value || "" }); // Update city in formData + }; + + return ( +
+ navigate("/admin-dashboard")} + > + Back + + + ➕ Add New Partner + +
+
+ + + + + + + + + + + + + + + + + ({ + ...provided, + backgroundColor: '#374151', + color: 'white', + borderRadius: '0.5rem', + padding: '0.5rem', + border: 'none', + }), + option: (provided, state) => ({ + ...provided, + backgroundColor: state.isSelected ? '#1f2937' : '#374151', + color: 'white', + }), + singleValue: (provided) => ({ + ...provided, + color: 'white', + }), + input: (provided) => ({ + ...provided, + color: 'white', + }), + placeholder: (provided) => ({ + ...provided, + color: 'white', + }), + }} + placeholder="Select City" + isDisabled={!selectedProvince} + /> + + + + + + +
+ + Submit + +
+
+ ); +}; + +export default AddPartner; \ No newline at end of file diff --git a/src/Pages/AdminDashboard.jsx b/src/Pages/AdminDashboard.jsx new file mode 100644 index 0000000..cacff3d --- /dev/null +++ b/src/Pages/AdminDashboard.jsx @@ -0,0 +1,55 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import HoveringCardComponent from "../Components/HoveringCardComponent"; +import AdminDashboardComponent from "../Components/AdminDashboardComponent"; + +const AdminDashboard = () => { + const [clients, setClients] = useState([]); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + // useEffect(() => { + // const fetchClients = async () => { + // try { + // setLoading(true); + // const response = await api.get("/admin/clients"); + + // const updatedClients = response.map(client => ({ + // ...client, + // is_active: client.status === "Offline" ? null : true, + // })); + + // setClients(updatedClients); + + + // } catch (error) { + // console.error("Error fetching clients:", error); + // } finally { + // setLoading(false); + // } + // }; + // fetchClients(); + // }, []); + + return ( +
+ + 🏢 Admin Dashboard - Client List + + +
+ +
+
+ ); +}; + +export default AdminDashboard; diff --git a/src/Pages/Ads copy 2.jsx b/src/Pages/Ads copy 2.jsx new file mode 100644 index 0000000..17fa9ad --- /dev/null +++ b/src/Pages/Ads copy 2.jsx @@ -0,0 +1,131 @@ +import { useEffect, useState, useRef } from "react"; +import { useParams } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { api } from "../API/api"; + +const AdsPage = () => { + const { partnerid, screenName } = useParams(); + const [ads, setAds] = useState([]); + const [idx, setIdx] = useState(0); + const vidRef = useRef(null); + const [isVidPlay, setVidPlay] = useState(false); + const [adsLoaded, setAdsLoaded] = useState(false); + const [cycleCount, setCycleCount] = useState(0); + + useEffect(() => { + (async () => { + try { + console.log("Fetching New Ads List"); + alert("Fetching new ads list..."); + setAds([]); + const fetchedAds = await api.get(`/client/ads/${partnerid}/${screenName}`); + console.log("Fetched Ads:", fetchedAds); + alert(`Fetched ${fetchedAds.length} ads`); + + const sortedAds = fetchedAds.sort((a, b) => a.transid - b.transid); + setAds(sortedAds); + } catch (e) { + console.error("Ads error:", e); + alert("Error fetching ads: " + e.message); + } + setAdsLoaded(true); + })(); + }, [partnerid, screenName, cycleCount]); + + useEffect(() => { + if (!adsLoaded || !ads.length) return; + const ad = ads[idx]; + alert(`Displaying ad ${idx + 1}/${ads.length}: ${ad.file_path}`); + + const isVid = /\.(mp4|webm|ogg|mkv)$/i.test(ad.file_path); + let timer; + + if (isVid) { + alert(`🟢 Preparing to play video: ${ad.file_path}`); + setVidPlay(true); + if (vidRef.current) { + vidRef.current.src = `https://ads.dine360ads.com/api/${ad.file_path}`; + vidRef.current.load(); + vidRef.current + .play() + .then(() => { + alert(`✅ Video started playing: ${ad.file_path}`); + }) + .catch((err) => { + alert(`❌ Video failed to play: ${err.message}`); + }); + } + } else { + setVidPlay(false); + alert(`🖼️ Showing image: ${ad.file_path}`); + timer = setTimeout(() => { + if (idx === ads.length - 1) { + setCycleCount((prev) => prev + 1); + } + setIdx((p) => (p + 1) % ads.length); + }, 5000); + } + + return () => clearTimeout(timer); + }, [ads, idx, adsLoaded]); + + const vidEnd = () => { + alert("🔁 Video ended, moving to next ad..."); + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + const handleVideoError = () => { + alert("❗ Video playback error! Skipping to next ad."); + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + const handleVideoPause = () => { + alert("⏸️ Video paused."); + }; + + const handleVideoPlay = () => { + alert("▶️ Video is playing."); + }; + + const handleVideoLoaded = () => { + alert("🔄 Video loaded successfully."); + }; + + return ( +
+ + {adsLoaded && ads.length > 0 && ( + isVidPlay ? ( + +
+ ); +}; + +export default AdsPage; diff --git a/src/Pages/Ads.jsx b/src/Pages/Ads.jsx new file mode 100644 index 0000000..24643c5 --- /dev/null +++ b/src/Pages/Ads.jsx @@ -0,0 +1,162 @@ +import { useEffect, useState, useRef } from "react"; +import { useParams } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { api } from "../API/api"; + +const AdsPage = () => { + const { partnerid, screenName } = useParams(); + const [ads, setAds] = useState([]); + const [idx, setIdx] = useState(0); + const vidRef = useRef(null); + const [isVidPlay, setVidPlay] = useState(false); + const [adsLoaded, setAdsLoaded] = useState(false); + const [cycleCount, setCycleCount] = useState(0); + const [delay, setDelay] = useState(1); // Default delay + // const [imageDuration, setImageDuration] = useState(5); // No longer a common default + + useEffect(() => { + (async () => { + try { + console.log('Fetching New Files List'); + setAds([]); + const fetchedAds = await api.get(`/client/ads/${partnerid}/${screenName}`); + const sortedAds = fetchedAds.sort((a, b) => a.transid - b.transid); + console.log(sortedAds); + setAds(sortedAds); + } catch (e) { + console.error("Ads error:", e); + } + setAdsLoaded(true); + })(); + + // Fetch settings (delay still needed for logging interval) + (async () => { + try { + const settings = await api.get("/client/get-settings"); + if (settings && settings.length >= 2) { + setDelay(parseInt(settings[1].value, 10) || 1); + // setImageDuration is no longer needed here + } + } catch (e) { + console.error("Settings error:", e); + } + })(); + }, [partnerid, screenName, cycleCount]); + + useEffect(() => { + if (!adsLoaded || !ads.length) return; + const ad = ads[idx]; + const isVid = /\.(mp4|webm|ogg|mkv)$/i.test(ad.file_path); + let timer; + + if (isVid) { + setVidPlay(true); + vidRef.current?.play().catch(() => {}); + } else { + setVidPlay(false); + // Use the image duration specific to the current ad + const currentImageDuration = ad.imageduration !== undefined ? parseInt(ad.imageduration, 10) : 5; // Default to 5 if not present + + timer = setTimeout(() => { + if (idx === ads.length - 1) { + setCycleCount((prev) => prev + 1); + } + setIdx((p) => (p + 1) % ads.length); + }, currentImageDuration * 1000); + } + + return () => clearTimeout(timer); + }, [ads, idx, adsLoaded]); // Removed imageDuration from dependency array + + const vidEnd = () => { + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + const logAd = async () => { + if (!adsLoaded || !ads.length) return console.log("Ads skip log."); + try { + if (ads[idx]) { + await api.post("/client/add-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "active", + }); + console.log("Logged"); + } else console.log("Ad idx out."); + } catch (e) { + console.error("Log error:", e); + } + }; + + useEffect(() => { + if (!adsLoaded) return; + + const logTimer = setInterval(() => { + if (!document.hidden) { + logAd(); + } else { + console.log("Skipped logging: Tab is inactive"); + } + }, 60 * delay * 1000); + + return () => clearInterval(logTimer); + }, [adsLoaded, delay]); + + useEffect(() => { + const handleVisibilityChange = async () => { + if (document.hidden) { + try { + console.log("User minimized or switched tab"); + await api.post("/client/idle-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "inactive", + }); + } catch (e) { + console.error("Visibility Log error:", e); + } + } else { + console.log("User visible"); + logAd(); + } + }; + + document.addEventListener("visibilitychange", handleVisibilityChange); + return () => document.removeEventListener("visibilitychange", handleVisibilityChange); + }, [ads, adsLoaded, screenName]); + + return ( +
+ + {adsLoaded && ads.length > 0 && ( + isVidPlay ? ( + +
+ ); +}; + +export default AdsPage; \ No newline at end of file diff --git a/src/Pages/Ads_Bak_with common ad duration.jsx b/src/Pages/Ads_Bak_with common ad duration.jsx new file mode 100644 index 0000000..7713bec --- /dev/null +++ b/src/Pages/Ads_Bak_with common ad duration.jsx @@ -0,0 +1,159 @@ +import { useEffect, useState, useRef } from "react"; +import { useParams } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { api } from "../API/api"; + +const AdsPage = () => { + const { partnerid, screenName } = useParams(); + const [ads, setAds] = useState([]); + const [idx, setIdx] = useState(0); + const vidRef = useRef(null); + const [isVidPlay, setVidPlay] = useState(false); + const [adsLoaded, setAdsLoaded] = useState(false); + const [cycleCount, setCycleCount] = useState(0); + const [delay, setDelay] = useState(1); // Default delay + const [imageDuration, setImageDuration] = useState(5); // Default image duration + + useEffect(() => { + (async () => { + try { + console.log('Fetching New Files List'); + setAds([]); + const fetchedAds = await api.get(`/client/ads/${partnerid}/${screenName}`); + const sortedAds = fetchedAds.sort((a, b) => a.transid - b.transid); + console.log(sortedAds); + setAds(sortedAds); + } catch (e) { + console.error("Ads error:", e); + } + setAdsLoaded(true); + })(); + + // Fetch settings + (async () => { + try { + const settings = await api.get("/client/get-settings"); + if (settings && settings.length >= 2) { + setDelay(parseInt(settings[1].value, 10) || 1); + setImageDuration(parseInt(settings[0].value, 10) || 5); + } + } catch (e) { + console.error("Settings error:", e); + } + })(); + }, [partnerid, screenName, cycleCount]); + + useEffect(() => { + if (!adsLoaded || !ads.length) return; + const ad = ads[idx]; + const isVid = /\.(mp4|webm|ogg|mkv)$/i.test(ad.file_path); + let timer; + + if (isVid) { + setVidPlay(true); + vidRef.current?.play().catch(() => {}); + } else { + setVidPlay(false); + timer = setTimeout(() => { + if (idx === ads.length - 1) { + setCycleCount((prev) => prev + 1); + } + setIdx((p) => (p + 1) % ads.length); + }, imageDuration * 1000); + } + + return () => clearTimeout(timer); + }, [ads, idx, adsLoaded, imageDuration]); + + const vidEnd = () => { + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + const logAd = async () => { + if (!adsLoaded || !ads.length) return console.log("Ads skip log."); + try { + if (ads[idx]) { + await api.post("/client/add-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "active", + }); + console.log("Logged"); + } else console.log("Ad idx out."); + } catch (e) { + console.error("Log error:", e); + } + }; + + useEffect(() => { + if (!adsLoaded) return; + + const logTimer = setInterval(() => { + if (!document.hidden) { + logAd(); + } else { + console.log("Skipped logging: Tab is inactive"); + } + }, 60 * delay * 1000); + + return () => clearInterval(logTimer); + }, [adsLoaded, delay]); + + useEffect(() => { + const handleVisibilityChange = async () => { + if (document.hidden) { + try { + console.log("User minimized or switched tab"); + await api.post("/client/idle-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "inactive", + }); + } catch (e) { + console.error("Visibility Log error:", e); + } + } else { + console.log("User visible"); + logAd(); + } + }; + + document.addEventListener("visibilitychange", handleVisibilityChange); + return () => document.removeEventListener("visibilitychange", handleVisibilityChange); + }, [ads, adsLoaded, screenName]); + + return ( +
+ + {adsLoaded && ads.length > 0 && ( + isVidPlay ? ( + +
+ ); +}; + +export default AdsPage; \ No newline at end of file diff --git a/src/Pages/Ads_log.jsx b/src/Pages/Ads_log.jsx new file mode 100644 index 0000000..92cb02f --- /dev/null +++ b/src/Pages/Ads_log.jsx @@ -0,0 +1,240 @@ +import { useEffect, useState, useRef } from "react"; +import { useParams } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { api } from "../API/api"; +import Swal from "sweetalert2"; + +const AdsPage = () => { + const { partnerid, screenName } = useParams(); + const [ads, setAds] = useState([]); + const [idx, setIdx] = useState(0); + const vidRef = useRef(null); + const [isVidPlay, setVidPlay] = useState(false); + const [adsLoaded, setAdsLoaded] = useState(false); + const [cycleCount, setCycleCount] = useState(0); + const [toastQueue, setToastQueue] = useState([]); + const [isToastActive, setIsToastActive] = useState(false); + + const [delay, setDelay] = useState(1); // Default delay + const [imageDuration, setImageDuration] = useState(5); // Default image duration + + + const addLog = (message, icon = "info") => { + //setToastQueue((prev) => [...prev, { message, icon }]); + }; + + const showNextToast = () => { + if (toastQueue.length === 0 || isToastActive) return; + + setIsToastActive(true); + const { message, icon } = toastQueue[0]; + + Swal.fire({ + title: message, + icon: icon, + toast: true, + position: "top-end", + showConfirmButton: false, + timer: 2000, + timerProgressBar: true, + didClose: () => { + setToastQueue((prev) => prev.slice(1)); + setIsToastActive(false); + }, + }); + }; + + useEffect(() => { + if (!isToastActive && toastQueue.length > 0) { + showNextToast(); + } + }, [toastQueue, isToastActive]); + + useEffect(() => { + (async () => { + try { + addLog("Fetching new ads list..."); + setAds([]); + + const fetchedAds = await api.get(`/client/ads/${partnerid}/${screenName}`); + addLog(`Fetched ${fetchedAds.length} ads`, "success"); + + const sortedAds = fetchedAds.sort((a, b) => a.transid - b.transid); + setAds(sortedAds); + } catch (e) { + console.error("Ads error:", e); + addLog("Error fetching ads: " + e.message, "error"); + } + setAdsLoaded(true); + })(); + + + (async () => { + try { + const settings = await api.get("/client/get-settings"); + if (settings && settings.length >= 2) { + setDelay(parseInt(settings[1].value, 10) || 1); + setImageDuration(parseInt(settings[0].value, 10) || 5); + } + } catch (e) { + console.error("Settings error:", e); + } + })(); + }, [partnerid, screenName, cycleCount]); + + useEffect(() => { + if (!adsLoaded || ads.length === 0) return; + + const ad = ads[idx]; + addLog(`Displaying ad ${idx + 1}/${ads.length}`); + + const isVid = /\.(mp4|webm|ogg|mkv)$/i.test(ad.file_path); + let timer; + + if (isVid) { + addLog(`🟢 Preparing to play video: ${ad.file_path}`); + setVidPlay(true); + + if (vidRef.current) { + vidRef.current.src = `https://ads.dine360ads.com/api/${ad.file_path}`; + vidRef.current.load(); + vidRef.current + .play() + .then(() => addLog(`✅ Video started playing`, "success")) + .catch((err) => addLog(`❌ Video failed to play: ${err.message}`, "error")); + } + } else { + setVidPlay(false); + addLog(`🖼️ Showing image`); + + timer = setTimeout(() => { + if (idx === ads.length - 1) { + setCycleCount((prev) => prev + 1); + } + setIdx((p) => (p + 1) % ads.length); + }, imageDuration * 1000); + } + + return () => clearTimeout(timer); + }, [ads, idx, adsLoaded]); + + const vidEnd = () => { + addLog("🔁 Video ended, moving to next ad..."); + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + const handleVideoError = () => { + addLog("❗ Video playback error! Skipping to next ad.", "error"); + setVidPlay(false); + setIdx((p) => (p + 1) % ads.length); + }; + + + const logAd = async () => { + if (!adsLoaded || !ads.length) return console.log("Ads skip log."); + try { + if (ads[idx]) { + await api.post("/client/add-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "active", + }); + console.log("Logged"); + } else console.log("Ad idx out."); + } catch (e) { + console.error("Log error:", e); + } + }; + + useEffect(() => { + if (!adsLoaded) return; + + const logTimer = setInterval(() => { + if (!document.hidden) { + logAd(); + } else { + console.log("Skipped logging: Tab is inactive"); + } + }, 60 * delay * 1000); + + return () => clearInterval(logTimer); + }, [adsLoaded, delay]); + + useEffect(() => { + const handleVisibilityChange = async () => { + if (document.hidden) { + try { + console.log("User minimized or switched tab"); + await api.post("/client/idle-screen-log", { + screen_id: ads[0]?.screenid, + screen_name: screenName, + partner_id: ads[0]?.partnerid, + status: "inactive", + }); + } catch (e) { + console.error("Visibility Log error:", e); + } + } else { + console.log("User visible"); + logAd(); + } + }; + + document.addEventListener("visibilitychange", handleVisibilityChange); + return () => document.removeEventListener("visibilitychange", handleVisibilityChange); + }, [ads, adsLoaded, screenName]); + + return ( +
+ + {adsLoaded && ads.length > 0 && ( + isVidPlay ? ( + // +
+ ); +}; + +export default AdsPage; diff --git a/src/Pages/ClientPartnerMapping.jsx b/src/Pages/ClientPartnerMapping.jsx new file mode 100644 index 0000000..73b3cf2 --- /dev/null +++ b/src/Pages/ClientPartnerMapping.jsx @@ -0,0 +1,53 @@ + +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import PartnersCardComponent from "../Components/PartnersPageCardComponent"; +import ClientsCardComponent from "../Components/ClientsPageCardComponent"; +import MappingComponent from "../Components/MappingComponent"; + +const ClientPartnerMapping = () => { + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + useEffect(() => { + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get("/admin/partners"); + + setClients(response); + + + } catch (error) { + console.error("Error fetching clients:", error); + } finally { + setLoading(false); + } + }; + fetchClients(); + }, [upd]); + + return ( +
+ + Ads Configuration + + + + +
+ ); +}; + +export default ClientPartnerMapping + diff --git a/src/Pages/ClientsPage.jsx b/src/Pages/ClientsPage.jsx new file mode 100644 index 0000000..95d8bf9 --- /dev/null +++ b/src/Pages/ClientsPage.jsx @@ -0,0 +1,52 @@ + +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import PartnersCardComponent from "../Components/PartnersPageCardComponent"; +import ClientsCardComponent from "../Components/ClientsPageCardComponent"; + +const ClientsPage = () => { + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + useEffect(() => { + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get("/admin/clients"); + + setClients(response); + + + } catch (error) { + console.error("Error fetching clients:", error); + } finally { + setLoading(false); + } + }; + fetchClients(); + }, [upd]); + + return ( +
+ + Clients List + + + + +
+ ); +}; + +export default ClientsPage + diff --git a/src/Pages/Login copy.jsx b/src/Pages/Login copy.jsx new file mode 100644 index 0000000..c1a98a3 --- /dev/null +++ b/src/Pages/Login copy.jsx @@ -0,0 +1,131 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaLock, FaUser } from "react-icons/fa"; + +const Login = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const navigate = useNavigate(); + + const handleLogin = (e) => { + e.preventDefault(); + if (username === "admin" && password === "admin") { + localStorage.setItem('loggedIn', JSON.stringify({ + timestamp: Date.now(), + value: true, + })); + navigate("/admin-dashboard"); + } else { + setError("❌ Invalid credentials! Try again."); + } + }; + + const [floors, setFloors] = useState([]); + + useEffect(() => { + const a = "482beca79d9c005"; + const b = "b8778f51fcca82b"; + const authHeader = `token ${a}:${b}`; +const url = "http://82.25.105.135:8004/api/resource/Dine360%20Room?fields=%5B%22*%22%5D&limit_page_length=100&filters=%5B%5B%22floor%22%2C%22%3D%22%2C%223%22%5D%5D"; + + fetch(url, { + headers: { + Authorization: authHeader, + }, + }) + .then((res) => res.json()) + .then((data) => { + setFloors(data.data); + console.log("regr", data.data) + }) + .catch((err) => console.error(err)); + }, []); + + return ( +
+ + {/* Animated Heading */} + + 🔐 Admin Login + + + {/* Input Fields */} +
+
+ + setUsername(e.target.value)} + /> +
+ +
+ + setPassword(e.target.value)} + /> +
+ + {/* Error Message Animation */} + {error && ( + + {error} + + )} + + {/* Login Button */} + + 🚀 Login + +
+
+ + {/* Floating Emojis Animation */} + + 🔑 + + + + 🔥 + +
+ ); +}; + +export default Login; diff --git a/src/Pages/Login.jsx b/src/Pages/Login.jsx new file mode 100644 index 0000000..c1a98a3 --- /dev/null +++ b/src/Pages/Login.jsx @@ -0,0 +1,131 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaLock, FaUser } from "react-icons/fa"; + +const Login = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const navigate = useNavigate(); + + const handleLogin = (e) => { + e.preventDefault(); + if (username === "admin" && password === "admin") { + localStorage.setItem('loggedIn', JSON.stringify({ + timestamp: Date.now(), + value: true, + })); + navigate("/admin-dashboard"); + } else { + setError("❌ Invalid credentials! Try again."); + } + }; + + const [floors, setFloors] = useState([]); + + useEffect(() => { + const a = "482beca79d9c005"; + const b = "b8778f51fcca82b"; + const authHeader = `token ${a}:${b}`; +const url = "http://82.25.105.135:8004/api/resource/Dine360%20Room?fields=%5B%22*%22%5D&limit_page_length=100&filters=%5B%5B%22floor%22%2C%22%3D%22%2C%223%22%5D%5D"; + + fetch(url, { + headers: { + Authorization: authHeader, + }, + }) + .then((res) => res.json()) + .then((data) => { + setFloors(data.data); + console.log("regr", data.data) + }) + .catch((err) => console.error(err)); + }, []); + + return ( +
+ + {/* Animated Heading */} + + 🔐 Admin Login + + + {/* Input Fields */} +
+
+ + setUsername(e.target.value)} + /> +
+ +
+ + setPassword(e.target.value)} + /> +
+ + {/* Error Message Animation */} + {error && ( + + {error} + + )} + + {/* Login Button */} + + 🚀 Login + +
+
+ + {/* Floating Emojis Animation */} + + 🔑 + + + + 🔥 + +
+ ); +}; + +export default Login; diff --git a/src/Pages/ManageClient.jsx b/src/Pages/ManageClient.jsx new file mode 100644 index 0000000..37a33c7 --- /dev/null +++ b/src/Pages/ManageClient.jsx @@ -0,0 +1,202 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft, FaUpload } from "react-icons/fa"; +import { api } from "../API/api"; +import ManageFiles from "./ManageFilesPage"; +import { useLoading } from "../Context/LoadingContext"; + +const ManageClient = () => { + const { setLoading } = useLoading(); + const { id } = useParams(); + const [files, setFiles] = useState([]); + const [clients, setclients] = useState([]); + const [screens, setScreens] = useState([]); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const [isEnabled, setIsEnabled] = useState(true); + const [formData, setFormData] = useState({ + transid: "", + name: "", + emailid: "", + phoneno: "", + address: "", + }); + + + // Fetch files when component loads + useEffect(() => { + fetchClients(); + fetchScreens() + }, [id]); + + const fetchFiles = async () => { + try { + const response = await api.get(`/client/files/${id}`); + setFiles(response); + + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/get-client/${id}`); + setclients(response); + setFormData(response[0]); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + const fetchScreens = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/get-screen/${id}`); + setScreens(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + const handleUpdate = async (e) => { + e.preventDefault(); + try { + setLoading(true); + await api.post("/admin/update-client", formData); + navigate("/clients"); + } catch (error) { + console.error("Error updating Client:", error); + } + setLoading(false) + }; + + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleEdit = () => { + setIsEnabled(false); + }; + + return ( +
+ {/* Back Button */} + navigate("/admin-dashboard")} + > + Back + + + {/* Page Title */} + + Manage Client + + +
+
+ + + + + + + + + + + + + +
+ + {isEnabled ? ( + + Edit + + ) : ( + + Update + + )} +
+ +
+ +
+ +
+ +
+
+ ); +}; + +export default ManageClient; diff --git a/src/Pages/ManageFilesOrderPage.jsx b/src/Pages/ManageFilesOrderPage.jsx new file mode 100644 index 0000000..dad5ce3 --- /dev/null +++ b/src/Pages/ManageFilesOrderPage.jsx @@ -0,0 +1,253 @@ +import { useEffect, useState, useRef, useMemo } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion, AnimatePresence, Reorder } from "framer-motion"; +import { FaArrowUp, FaArrowDown } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import ViewPartnerAdsConfiguration from "../Components/ViewPartnerAdsConfiguration"; + +const ManageFilesOrder = () => { + const { id } = useParams(); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const [files, setFiles] = useState([]); + const [openScreens, setOpenScreens] = useState({}); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + // Fetch and sort files + useEffect(() => { + (async () => { + try { + setLoading(true); + const response = await api.get(`/admin/partner-ads?partnerid=${id}`); + console.log(response) + const sorted = response.sort((a, b) => { + const nameA = a?.screenname || ''; + const nameB = b?.screenname || ''; + return nameA.localeCompare(nameB, undefined, { numeric: true }); + }); + + setFiles(sorted); + console.log("FILESSSSSSSSSSSSS<",sorted) + } catch (error) { + console.error("Error fetching files:", error); + } finally { + setLoading(false); + } + })(); + }, [id, setLoading]); + + // Group files by screenname + const filesByScreen = useMemo(() => + files.reduce((acc, file) => { + const key = file.screenname; + acc[key] = acc[key] || []; + acc[key].push(file); + return acc; + }, {}), + [files] + ); + + // Toggle collapse for screen + const toggleScreen = (screen) => { + setOpenScreens(prev => ({ ...prev, [screen]: !prev[screen] })); + }; + + // Merge reordered group back into files array + const handleGroupReorder = (screen, newGroup) => { + const other = files.filter(f => f.screenname !== screen); + setFiles([...other, ...newGroup]); + }; + + // Save flattened order + const saveOrder = async () => { + try { + setLoading(true); + await api.post("/admin/reorder-partner-ads", files); + alert("Order saved successfully"); + } catch (error) { + console.error("Error saving order:", error); + alert("Error saving order. Check console for details."); + } finally { + setLoading(false); + } + }; + + // Checkbox handlers update flat files state + const handleToggleMainAd = (file, checked) => { + setFiles(files.map(f => + f.file_path === file.file_path && file.screenid === f.screenid? { ...f, ismainad: checked ? 1 : 0 } : f + )); + }; + const handleToggleCarousel = (file, checked) => { + setFiles(files.map(f => + f.file_path === file.file_path && file.screenid === f.screenid? { ...f, iscarousel: checked ? 1 : 0 } : f + )); + }; + const handleToggleInHouse = (file, checked) => { + setFiles(files.map(f => + f.file_path === file.file_path && file.screenid === f.screenid? { ...f, isinhousead: checked ? 1 : 0 } : f + )); + }; + + // Move up/down within a screen group + const groupMoveUp = (screen, index) => { + const group = filesByScreen[screen]; + if (index <= 0) return; + const newGroup = [...group]; + [newGroup[index - 1], newGroup[index]] = [newGroup[index], newGroup[index - 1]]; + handleGroupReorder(screen, newGroup); + }; + const groupMoveDown = (screen, index) => { + const group = filesByScreen[screen]; + if (index >= group.length - 1) return; + const newGroup = [...group]; + [newGroup[index], newGroup[index + 1]] = [newGroup[index + 1], newGroup[index]]; + handleGroupReorder(screen, newGroup); + }; + + return ( +
+ + 📂 Manage Ads Order + + + {/* Collapsible groups by screen */} +
+ {Object.entries(filesByScreen).map(([screen, groupFiles]) => ( +
+ + + + {openScreens[screen] && ( + handleGroupReorder(screen, newOrder)} + className="bg-gray-800 p-4 rounded-lg mt-2 space-y-2" + > + {groupFiles.map((file, index) => { + const fileName = file.file_path.split("_")[1]; + const fileUrl = BACKEND + file.file_path; + const isImage = /\.(jpe?g|png|gif)$/i.test(fileUrl); + const isVideo = /\.(mp4|webm|ogg|mkv)$/i.test(fileUrl); + + return ( + +
+ {isImage && ( + // {fileName} + {fileName} + + )} + {isVideo && ( + // + + + )} + {fileName} +
+ +
+ {/* Checkboxes */} + + + + + {/* Up/Down buttons */} + groupMoveUp(screen, index)} + disabled={index === 0} + className="p-2 rounded-full bg-gray-700 disabled:opacity-50" + > + + + groupMoveDown(screen, index)} + disabled={index === groupFiles.length - 1} + className="p-2 rounded-full bg-gray-700 disabled:opacity-50" + > + + +
+
+ ); + })} +
+ )} +
+
+ ))} + + +
+ + + 📂 Ads Configurations + + +
+ ); +}; + +export default ManageFilesOrder; \ No newline at end of file diff --git a/src/Pages/ManageFilesOrderPage_27-04-25.jsx b/src/Pages/ManageFilesOrderPage_27-04-25.jsx new file mode 100644 index 0000000..4cf0caf --- /dev/null +++ b/src/Pages/ManageFilesOrderPage_27-04-25.jsx @@ -0,0 +1,213 @@ +import { useEffect, useState, useRef } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion, AnimatePresence, Reorder } from "framer-motion"; +import { FaArrowUp, FaArrowDown } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import ViewPartnerAdsConfiguration from "../Components/ViewPartnerAdsConfiguration"; + +const ManageFilesOrder = () => { + const { id } = useParams(); + const BACKEND = 'https://ads.dine360ads.com/api//'; + const [files, setFiles] = useState([]); + const [upd, setupd] = useState(0); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + const fileRefs = useRef([]); + + useEffect(() => { + fetchFiles(); + }, [id, upd]); + + const fetchFiles = async () => { + try { + setLoading(true); + const response = await api.get(`/admin/partner-ads?partnerid=${id}`); + console.log(response) + const res = response.sort((a, b) => a.screenname.localeCompare(b.screenname, undefined, { numeric: true })); + + + setFiles(res); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false); + }; + + const ReorderAds = async (e) => { + setLoading(true); + console.log("Final Data to Insert:", files); + + try { + await api.post("/admin/reorder-partner-ads", files); + alert("Client Partner Mapping data added successfully!"); + + } catch (error) { + console.error("Error adding client partner mapping:", error); + alert("Error adding client partner mapping. Please check console for details."); + } + setLoading(false); + }; + + const moveFileUp = (index) => { + if (index > 0) { + const newFiles = [...files]; + [newFiles[index], newFiles[index - 1]] = [newFiles[index - 1], newFiles[index]]; + setFiles(newFiles); + } + }; + + const moveFileDown = (index) => { + if (index < files.length - 1) { + const newFiles = [...files]; + [newFiles[index], newFiles[index + 1]] = [newFiles[index + 1], newFiles[index]]; + setFiles(newFiles); + } + }; + + const handleToggleCarousel = (index, checked) => { + // old: no-op + setFiles(files.map((f, i) => + i === index + ? { ...f, iscarousel: checked ? 1 : 0 } + : f + )); + }; + + const handleToggleInHouse = (index, checked) => { + // old: no-op + setFiles(files.map((f, i) => + i === index + ? { ...f, isinhousead: checked ? 1 : 0 } + : f + )); + }; + + const handleToggleMainAd = (index, checked) => { + // old: no-op + setFiles(files.map((f, i) => + i === index + ? { ...f, ismainad: checked ? 1 : 0 } + : f + )); + }; + + + + return ( +
+ + 📂 Manage Ads Order + + +
+ + + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_path.split("_")[1]; + const fileUrl = BACKEND + file.file_path; + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( + +
+ {isImage && {fileName}} + {isVideo && ( + + )} + {file.screenname} - 📄 {fileName} +
+
+
+ + handleToggleMainAd(index, e.target.checked)} + /> + Set Ad as Main Ad +


+
+ + handleToggleCarousel(index, e.target.checked)} + /> + Set Ad in Image Carousel +
+
+
+
+ handleToggleInHouse(index, e.target.checked)} + /> + Set Ad as In-House Ad +
+ + moveFileUp(index)} + disabled={index === 0} + className="p-2 rounded-full bg-gray-700 disabled:opacity-50" + > + + + moveFileDown(index)} + disabled={index === files.length - 1} + className="p-2 rounded-full bg-gray-700 disabled:opacity-50" + > + + +
+
+ ); + }) + ) : ( +

No files uploaded yet.

+ )} + + +
+
+
+ + + +

+ + 📂 Ads Configurations + +
+ +
+
+ ); +}; + +export default ManageFilesOrder; \ No newline at end of file diff --git a/src/Pages/ManageFilesPage.jsx b/src/Pages/ManageFilesPage.jsx new file mode 100644 index 0000000..9c25d45 --- /dev/null +++ b/src/Pages/ManageFilesPage.jsx @@ -0,0 +1,158 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft, FaUpload } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; + +const ManageFiles = ({ id }) => { + const BACKEND = 'https://ads.dine360ads.com/api//' + const [files, setFiles] = useState([]); + const [upd, setupd] = useState(0); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + // Fetch files when component loads + useEffect(() => { + fetchFiles(); + }, [id, upd]); + + const fetchFiles = async () => { + try { + setLoading(true); + const response = await api.get(`/client/files/${id}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + const deleteFiles = async (fileid) => { + console.log(fileid) + try { + setLoading(true); + const response = await api.delete(`/files/del/${fileid}`); + console.log(response); + setupd(upd + 1) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + const handleFileUpload = async (file) => { + if (!file) return; + + setUploading(true); + const formData = new FormData(); + formData.append("file", file); + formData.append("file_name", file.name); + formData.append("client_id", id); // Attach client ID + + try { + setLoading(true) + await api.post("/files/upload", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + + // Refresh file list after each successful upload + fetchFiles(); + } catch (error) { + console.error(`File upload failed for ${file.name}:`, error); + // Optionally, you could add some user feedback here for individual file failures + } finally { + setUploading(false); // Keep this false, as we're handling individual uploads + setLoading(false) + } + }; + + const handleMultipleUpload = async (e) => { + const filesToUpload = e.target.files; + if (!filesToUpload || filesToUpload.length === 0) return; + + setUploading(true); + // Iterate through each selected file and call the upload function + for (let i = 0; i < filesToUpload.length; i++) { + await handleFileUpload(filesToUpload[i]); + } + setUploading(false); // Set uploading to false after all files are processed + }; + + return ( +
+ {/* Back Button */} + {/* navigate("/admin-dashboard")} + > + Back + */} + + {/* Page Title */} + + 📂 Manage Client Files + + + {/* Upload Button */} +
+ + +
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name + const fileUrl = BACKEND+ file.file_path // Assuming this holds the correct file URL + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + 📄 {fileName} + + {isImage && {fileName}} + + {isVideo && ( + + )} + + +
  • + ); + }) + ) : ( +

    No files uploaded yet.

    + )} +
+
+
+ ); +}; + +export default ManageFiles; \ No newline at end of file diff --git a/src/Pages/ManageFilesPage_Bak_singleFileUpload.jsx b/src/Pages/ManageFilesPage_Bak_singleFileUpload.jsx new file mode 100644 index 0000000..0be8202 --- /dev/null +++ b/src/Pages/ManageFilesPage_Bak_singleFileUpload.jsx @@ -0,0 +1,145 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft, FaUpload } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; + +const ManageFiles = ({ id }) => { + const BACKEND = 'https://ads.dine360ads.com/api//' + const [files, setFiles] = useState([]); + const [upd, setupd] = useState(0); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + // Fetch files when component loads + useEffect(() => { + fetchFiles(); + }, [id, upd]); + + const fetchFiles = async () => { + try { + setLoading(true); + const response = await api.get(`/client/files/${id}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + const deleteFiles = async (fileid) => { + console.log(fileid) + try { + setLoading(true); + const response = await api.delete(`/files/del/${fileid}`); + console.log(response); + setupd(upd + 1) + } catch (error) { + console.error("Error fetching files:", error); + } + setLoading(false) + }; + + + + const handleUpload = async (e) => { + const file = e.target.files[0]; + if (!file) return; + + setUploading(true); + const formData = new FormData(); + formData.append("file", file); + formData.append("file_name", file.name); + formData.append("client_id", id); // Attach client ID + + try { + setLoading(true) + await api.post("/files/upload", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + + // Refresh file list after upload + fetchFiles(); + } catch (error) { + console.error("File upload failed:", error); + } finally { + setUploading(false); + setLoading(false) + } + }; + + return ( +
+ {/* Back Button */} + {/* navigate("/admin-dashboard")} + > + Back + */} + + {/* Page Title */} + + 📂 Manage Client Files + + + {/* Upload Button */} +
+ + +
    + {files.length > 0 ? ( + files.map((file, index) => { + const fileName = file.file_name + const fileUrl = BACKEND+ file.file_path // Assuming this holds the correct file URL + const isImage = fileUrl.match(/\.(jpeg|jpg|png|gif)$/i); + const isVideo = fileUrl.match(/\.(mp4|webm|ogg|mkv)$/i); + + return ( +
  • + 📄 {fileName} + + {isImage && {fileName}} + + {isVideo && ( + + )} + + +
  • + ); + }) + ) : ( +

    No files uploaded yet.

    + )} +
+ + +
+
+ ); +}; + +export default ManageFiles; diff --git a/src/Pages/ManagePartner copy.jsx b/src/Pages/ManagePartner copy.jsx new file mode 100644 index 0000000..50dab23 --- /dev/null +++ b/src/Pages/ManagePartner copy.jsx @@ -0,0 +1,663 @@ +import { useEffect, useState, useMemo } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft, FaTrash, FaUpload } from "react-icons/fa"; +import { api } from "../API/api"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import Select from 'react-select'; +import canada_cities from '../assets/canada_cities.json'; +import { useLoading } from "../Context/LoadingContext"; +import { FiPlus } from "react-icons/fi"; + +const ManagePartner = () => { + const { id } = useParams(); + const [files, setFiles] = useState([]); + const [partners, setPartners] = useState([]); + const [screens, setScreens] = useState([]); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const [isEnabled, setIsEnabled] = useState(true); + const { setLoading } = useLoading(); + const [formData, setFormData] = useState({ + transid: "", + name: "", + logo_url: "", + open_time: "", + close_time: "", + address: "", + city: "", + state: "", + pincode: "", + screens: "", + yt: "", + scrolltext: "" + }); + + const [selectedProvince, setSelectedProvince] = useState(null); + const [selectedCity, setSelectedCity] = useState(null); + + const provinceOptions = useMemo( + () => + Object.keys(canada_cities).map((province) => ({ + value: province, + label: province, + })), + [canada_cities] + ); + + const cityOptions = useMemo( + () => + selectedProvince + ? canada_cities[selectedProvince.value].map((city) => ({ + value: city, + label: city, + })) + : [], + [selectedProvince, canada_cities] + ); + + useEffect(() => { + fetchPartners(); + fetchScreens(); + }, [id]); + + const fetchFiles = async () => { + try { + const response = await api.get(`/client/files/${id}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const fetchPartners = async () => { + try { + + const response = await api.get(`/admin/get-partner/${id}`); + setPartners(response); + setFormData(response[0]); + if (response[0]) { + setSelectedProvince({ value: response[0].state, label: response[0].state }); + setSelectedCity({ value: response[0].city, label: response[0].city }); + } + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const fetchScreens = async () => { + try { + const response = await api.get(`/admin/get-screen/${id}`); + setScreens(response); + console.log(response) + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const handleFileUpload = async (file) => { + if (!file) return; + + setUploading(true); + const formData = new FormData(); + formData.append("file", file); + formData.append("file_name", file.name); + formData.append("client_id", id); // Attach client ID + + try { + setLoading(true) + await api.post("/files/update-partner-logo", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + navigate("/partners"); + + // Refresh file list after each successful upload + fetchFiles(); + } catch (error) { + console.error(`File upload failed for ${file.name}:`, error); + // Optionally, you could add some user feedback here for individual file failures + } finally { + setUploading(false); // Keep this false, as we're handling individual uploads + setLoading(false) + } + }; + + const handleFileChange = async (e) => { + console.log("oiouyt") + await handleFileUpload(e.target.files[0]); + setFormData({ ...formData, image: e.target.files[0] }); + }; + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleProvinceChange = (selectedOption) => { + setSelectedProvince(selectedOption); + setSelectedCity(null); + setFormData({ ...formData, state: selectedOption?.value || "" }); + }; + + const handleCityChange = (selectedOption) => { + setSelectedCity(selectedOption); + setFormData({ ...formData, city: selectedOption?.value || "" }); + }; + + const handleEdit = () => { + setIsEnabled(false); + }; + + const handleUpdate = async (e) => { + + e.preventDefault(); + try { + console.log(formData) + + await api.post("/admin/update-partner", formData); + navigate("/partners"); + + } catch (error) { + console.error("Error updating Partner:", error); + } + }; + + const AddScreen = async () => { + + try { + console.log({ partnerid: id }) + setLoading(true); + var data = await api.post("/admin/add-screen", { partnerid: id }); + console.log(data) + + fetchScreens(); + } catch (error) { + console.error("Error adding Screen:", error); + } + setLoading(false); + } + + + const DeleteScreen = async (id) => { + + try { + + setLoading(true); + var data = await api.post("/admin/delete-screen", { screenid: id }); + console.log(data) + + fetchScreens(); + } catch (error) { + console.error("Error adding Screen:", error); + } + setLoading(false); + } + const handleToggleYouTube = async (screenid, sts, idx) => { + try { + setLoading(true); + // call your API – adjust the endpoint & payload as needed + await api.post("/admin/update-screen-youtube", { + screenid, + sts: sts ? 1 : 0, + }); + // update local state so the UI flips instantly + // setScreens((prev) => + // prev.map((s, i) => + // i === idx ? { ...s, youtubeEnabled: enable ? 1 : 0 } : s + // ) + // ); + fetchScreens() + } catch (err) { + console.error("Error toggling YouTube:", err); + } finally { + setLoading(false); + } + }; + + + + return ( +
+ {/* Back button */} + navigate("/Partners")} + > + Back + + + {/* Header */} + + Manage Partners + + + {/* Form */} + +
+ {/* Partner Name */} +
+ + +
+ + {/* Logo */} + + + {/* Open Time */} +
+ + +
+ + {/* Close Time */} +
+ + +
+ + {/* Address */} +
+ + +
+ + {/* Province */} +
+ + +
+ + {/* Pincode */} +
+ + +
+ + {/* No. of Screens */} +
+ + +
+
+ + + +
+
+ + Logo + +
+
+ + {/* Edit / Update button */} +
+ {isEnabled ? ( + + Edit + + ) : ( + + Update + + )} +
+ + + {/* Screens Preview */} + {formData.screens && ( +
+
+
+ + + Add New Screen + +
+
+ {screens.map((screen, index) => ( + //
+ //

+ // Screen {index + 1} ({id.substring(0, 2) + 'S' + (index + 1)}) + //

+ //
+ // { + // const prefix = id.substring(0, 5); + // const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + // window.open(`${window.location.origin}/ads/${prefix}/${screenName}`, '_blank'); + // }} + // > + // Preview + // + + // { + // const prefix = id.substring(0, 5); + // const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + // navigator.clipboard.writeText(`${window.location.origin}/ads/${prefix}/${screenName}`); + // alert('Link copied to clipboard!'); + // }} + // > + // Copy Link + // + + + // { + // console.log(screen) + // handleToggleYouTube( + // screen.transid, + // screen.isyoutube !== 1, + // index + // ) + // } + // } + // > + // {screen.isyoutube === 1 + // ? "Disable YouTube" + // : "Enable YouTube"} + // + + + //
+ // + // + // {screen.isactive === 1 ? "ACTIVE" : screen.isactive === 2 ? "IDLE" : "INACTIVE"} + // + + + + //
+ //

+ + //
+ //
+ //
+ //
+ // {screen.status} + //

+ // {screen.stsupdat && ( + //
+ // {new Date(screen.stsupdat).toLocaleDateString('en-GB')} {new Date(screen.stsupdat).toLocaleTimeString()} + //
+ // )} + + //
+ //
+
+

+ Screen {index + 1} ({id.substring(0, 2) + 'S' + (index + 1)}) +

+
+ { + const prefix = id.substring(0, 5); + const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + window.open(`${window.location.origin}/ads/${prefix}/${screenName}`, '_blank'); + }} + > + Preview + + + { + const prefix = id.substring(0, 5); + const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + navigator.clipboard.writeText(`${window.location.origin}/ads/${prefix}/${screenName}`); + alert('Link copied to clipboard!'); + }} + > + Copy Link + + + { + console.log(screen); + handleToggleYouTube(screen.transid, screen.isyoutube !== 1, index); + }} + > + {screen.isyoutube === 1 ? "Disable YouTube" : "Enable YouTube"} + + +
+ + + {screen.isactive === 1 ? "ACTIVE" : screen.isactive === 2 ? "IDLE" : "INACTIVE"} + +
+ + {/* Delete button at the top right */} + { + // Add your delete functionality here, e.g., open a confirmation modal + console.log('Delete clicked for screen:', screen.transid); + DeleteScreen(screen.transid) + }} + > + {/* Using FontAwesome for the trash icon */} + +
+
+
+
+ {screen.status} +
+ {screen.stsupdat && ( +
+ {new Date(screen.stsupdat).toLocaleDateString('en-GB')}{' '} + {new Date(screen.stsupdat).toLocaleTimeString()} +
+ )} +
+
+ ))} +
+ )} +
+ ); + +}; + +export default ManagePartner; \ No newline at end of file diff --git a/src/Pages/ManagePartner.jsx b/src/Pages/ManagePartner.jsx new file mode 100644 index 0000000..9347d57 --- /dev/null +++ b/src/Pages/ManagePartner.jsx @@ -0,0 +1,626 @@ +import { useEffect, useState, useMemo } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft, FaTrash, FaUpload } from "react-icons/fa"; +import { api } from "../API/api"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import Select from 'react-select'; +import canada_cities from '../assets/canada_cities.json'; +import { useLoading } from "../Context/LoadingContext"; +import { FiPlus } from "react-icons/fi"; + +const ManagePartner = () => { + const { id } = useParams(); + const [files, setFiles] = useState([]); + const [partners, setPartners] = useState([]); + const [screens, setScreens] = useState([]); + const [uploading, setUploading] = useState(false); + const navigate = useNavigate(); + const [isEnabled, setIsEnabled] = useState(true); + const { setLoading } = useLoading(); + const [formData, setFormData] = useState({ + transid: "", + name: "", + logo_url: "", + open_time: "", + close_time: "", + address: "", + city: "", + state: "", + pincode: "", + screens: "", + yt: "", + scrolltext: "" + }); + + const [selectedProvince, setSelectedProvince] = useState(null); + const [selectedCity, setSelectedCity] = useState(null); + + const provinceOptions = useMemo( + () => + Object.keys(canada_cities).map((province) => ({ + value: province, + label: province, + })), + [canada_cities] + ); + + const cityOptions = useMemo( + () => + selectedProvince + ? canada_cities[selectedProvince.value].map((city) => ({ + value: city, + label: city, + })) + : [], + [selectedProvince, canada_cities] + ); + + useEffect(() => { + fetchPartners(); + fetchScreens(); + }, [id]); + + const fetchFiles = async () => { + try { + const response = await api.get(`/client/files/${id}`); + setFiles(response); + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const fetchPartners = async () => { + try { + + const response = await api.get(`/admin/get-partner/${id}`); + setPartners(response); + setFormData(response[0]); + if (response[0]) { + setSelectedProvince({ value: response[0].state, label: response[0].state }); + setSelectedCity({ value: response[0].city, label: response[0].city }); + } + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const fetchScreens = async () => { + try { + const response = await api.get(`/admin/get-screen/${id}`); + console.log(response) + setScreens(response); + console.log(response) + } catch (error) { + console.error("Error fetching files:", error); + } + }; + + const handleFileUpload = async (file) => { + if (!file) return; + + setUploading(true); + const formData = new FormData(); + formData.append("file", file); + formData.append("file_name", file.name); + formData.append("client_id", id); // Attach client ID + + try { + setLoading(true) + await api.post("/files/update-partner-logo", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + navigate("/partners"); + + // Refresh file list after each successful upload + fetchFiles(); + } catch (error) { + console.error(`File upload failed for ${file.name}:`, error); + // Optionally, you could add some user feedback here for individual file failures + } finally { + setUploading(false); // Keep this false, as we're handling individual uploads + setLoading(false) + } + }; + + const handleFileChange = async (e) => { + console.log("oiouyt") + await handleFileUpload(e.target.files[0]); + setFormData({ ...formData, image: e.target.files[0] }); + }; + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleProvinceChange = (selectedOption) => { + setSelectedProvince(selectedOption); + setSelectedCity(null); + setFormData({ ...formData, state: selectedOption?.value || "" }); + }; + + const handleCityChange = (selectedOption) => { + setSelectedCity(selectedOption); + setFormData({ ...formData, city: selectedOption?.value || "" }); + }; + + const handleEdit = () => { + setIsEnabled(false); + }; + + const handleUpdate = async (e) => { + + e.preventDefault(); + try { + console.log(formData) + + await api.post("/admin/update-partner", formData); + navigate("/partners"); + + } catch (error) { + console.error("Error updating Partner:", error); + } + }; + + const AddScreen = async () => { + + try { + console.log({ partnerid: id }) + setLoading(true); + var data = await api.post("/admin/add-screen", { partnerid: id }); + console.log(data) + + fetchScreens(); + } catch (error) { + console.error("Error adding Screen:", error); + } + setLoading(false); + } + + + const DeleteScreen = async (id) => { + + try { + + setLoading(true); + var data = await api.post("/admin/delete-screen", { screenid: id }); + console.log(data) + + fetchScreens(); + } catch (error) { + console.error("Error adding Screen:", error); + } + setLoading(false); + } + const handleToggleYouTube = async (screenid, sts, idx) => { + try { + setLoading(true); + // call your API – adjust the endpoint & payload as needed + await api.post("/admin/update-screen-youtube", { + screenid, + sts: sts ? 1 : 0, + }); + + fetchScreens() + } catch (err) { + console.error("Error toggling YouTube:", err); + } finally { + setLoading(false); + } + }; + + + + return ( +
+ {/* Back button */} + navigate("/Partners")} + > + Back + + + {/* Header */} + + Manage Partners + + + {/* Form */} + +
+ {/* Partner Name */} +
+ + +
+ + {/* Logo */} + + + {/* Open Time */} +
+ + +
+ + {/* Close Time */} +
+ + +
+ + {/* Address */} +
+ + +
+ + {/* Province */} +
+ + +
+ + {/* Pincode */} +
+ + +
+ + {/* No. of Screens */} +
+ + +
+
+ + + +
+
+ + Logo + +
+
+ + {/* Edit / Update button */} +
+ {isEnabled ? ( + + Edit + + ) : ( + + Update + + )} +
+ + + {/* Screens Preview */} + {formData.screens && ( +
+
+
+ + + Add New Screen + +
+
+ + {screens.map((screen, index) => ( + +
+ {/* Delete Button - Top Right of Card */} + { + if (window.confirm("Are you sure you want to delete this screen?")) { + DeleteScreen(screen.transid); + } + }} + title="Delete this screen" + > + + + +

+ Screen {index + 1} ({id.substring(0, 2) + 'S' + (index + 1)}) +

+ +
+ {/* Preview Button */} + { + const prefix = id.substring(0, 5); + const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + window.open(`${window.location.origin}/ads/${prefix}/${screenName}`, '_blank'); + }} + > + Preview + + + {/* Copy Link Button */} + { + const prefix = id.substring(0, 5); + const screenName = `Screen${index + 1}`.replace(/\s+/g, ''); + navigator.clipboard.writeText(`${window.location.origin}/ads/${prefix}/${screenName}`); + alert('Link copied to clipboard!'); + }} + > + Copy Link + + + {/* YouTube Toggle Switch */} + + + + + + + + + + + {/* Status Indicator */} +
+ + + {screen.isactive === 1 ? "ACTIVE" : screen.isactive === 2 ? "IDLE" : "INACTIVE"} + +
+
+ +
+
+
+ {screen.status} +
+ {screen.stsupdat && ( +
+ {new Date(screen.stsupdat).toLocaleDateString('en-GB')}{' '} + {new Date(screen.stsupdat).toLocaleTimeString()} +
+ )} +
+
+ ))} + +
+ )} +
+ ); + +}; + +export default ManagePartner; \ No newline at end of file diff --git a/src/Pages/NewAdConfiguration.jsx b/src/Pages/NewAdConfiguration.jsx new file mode 100644 index 0000000..f284592 --- /dev/null +++ b/src/Pages/NewAdConfiguration.jsx @@ -0,0 +1,53 @@ + +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import PartnersCardComponent from "../Components/PartnersPageCardComponent"; +import ClientsCardComponent from "../Components/ClientsPageCardComponent"; +import NewMappingCardComponent from "../Components/NewMappingCardComponent copy"; + +const NewAdConfiguration = () => { + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + useEffect(() => { + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get("/admin/clients"); + + setClients(response); + + + } catch (error) { + console.error("Error fetching clients:", error); + } finally { + setLoading(false); + } + }; + fetchClients(); + }, [upd]); + + return ( +
+ + Clients List + + + + +
+ ); +}; + +export default NewAdConfiguration + diff --git a/src/Pages/NotFound.jsx b/src/Pages/NotFound.jsx new file mode 100644 index 0000000..e2fafb0 --- /dev/null +++ b/src/Pages/NotFound.jsx @@ -0,0 +1,57 @@ +import { motion } from "framer-motion"; +import { Link } from "react-router-dom"; + +const NotFound = () => { + return ( +
+ {/* Animated 404 Text */} + + 404 + + + {/* Error Message */} + + Oops! The page you are looking for does not exist. + + + {/* Animated Button */} + + + Go Back Home + + + + {/* Floating Animation */} + + +
+ ); +}; + +export default NotFound; diff --git a/src/Pages/PartnersPage.jsx b/src/Pages/PartnersPage.jsx new file mode 100644 index 0000000..18eca83 --- /dev/null +++ b/src/Pages/PartnersPage.jsx @@ -0,0 +1,99 @@ + +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaPlus, FaCircle } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; +import PartnersCardComponent from "../Components/PartnersPageCardComponent"; + +const PartnersPage = () => { + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0);upd + const navigate = useNavigate(); + const { setLoading } = useLoading(); + + useEffect(() => { + const fetchClients = async () => { + try { + setLoading(true); + const response = await api.get("/admin/partners"); + + const updatedClients = response.map(client => ({ + ...client, + is_active: client.status === "Offline" ? null : true, + })); + + setClients(updatedClients); + + + } catch (error) { + console.error("Error fetching clients:", error); + } finally { + setLoading(false); + } + }; + fetchClients(); + }, [upd]); + + return ( +
+ + Partners List + + + {/*
+ navigate("/add-client")} + > +
+ +

Add New Client

+
+
+ + + {clients?.map((client) => ( + navigate(`/manage-client/${client.id}`)} + > +
+ +
+

{client.name}

+

🕒 {client.open_time} - {client.close_time}

+ +
+ + {client.is_active ? "Active" : "Inactive"} +
+
+
+ ))} +
*/} + +
+ ); +}; + +export default PartnersPage + diff --git a/src/Pages/SettingsPage.jsx b/src/Pages/SettingsPage.jsx new file mode 100644 index 0000000..b24e72a --- /dev/null +++ b/src/Pages/SettingsPage.jsx @@ -0,0 +1,95 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { motion } from "framer-motion"; +import { FaArrowLeft } from "react-icons/fa"; +import { api } from "../API/api"; +import { useLoading } from "../Context/LoadingContext"; + +const SettingsPage = () => { + const { setLoading } = useLoading(); + const navigate = useNavigate(); + const [settingsData, setSettingsData] = useState([]); + + useEffect(() => { + fetchSettings(); + }, []); + + const fetchSettings = async () => { + try { + setLoading(true); + const response = await api.get("/client/get-settings"); + setSettingsData(response); + } catch (error) { + console.error("Error fetching settings:", error); + } + setLoading(false); + }; + + const handleUpdate = async (transid, newValue) => { + try { + setLoading(true); + await api.post("/admin/update-settings", { + transid: transid, + value: newValue, + }); + alert("General Settings Updated Successfully ") + fetchSettings(); + } catch (error) { + console.error("Error updating setting:", error); + } + setLoading(false); + }; + + return ( +
+ navigate("/admin-dashboard")} + > + Back + + + + Settings + + +
{/* Grid Layout */} + {settingsData.map((item) => ( +
+ + { + const updatedSettings = settingsData.map((setting) => + setting.transid === item.transid + ? { ...setting, value: e.target.value } + : setting + ); + setSettingsData(updatedSettings); + }} + className="block w-full bg-gray-700 p-2 rounded-lg mb-2" + /> + handleUpdate(item.transid, item.value)} + className="bg-blue-500 px-4 py-2 rounded-lg" + whileHover={{ scale: 1.05 }} + > + Update + +
+ ))} +
+
+ ); +}; + +export default SettingsPage; \ No newline at end of file diff --git a/src/Pages/YT.jsx b/src/Pages/YT.jsx new file mode 100644 index 0000000..119c860 --- /dev/null +++ b/src/Pages/YT.jsx @@ -0,0 +1,67 @@ +import React, { useEffect, useRef } from 'react'; + +const YouTubePlayer = () => { + const playerRef = useRef(null); + const youtubeUrl = 'https://www.youtube.com/watch?v=MWm-ooierpw'; + + const getVideoId = (url) => { + try { + const parsedUrl = new URL(url); + if (parsedUrl.hostname === 'youtu.be') { + return parsedUrl.pathname.slice(1); + } else if (parsedUrl.hostname.includes('youtube.com')) { + return parsedUrl.searchParams.get('v'); + } + } catch (err) { + console.error(err); + } + return null; + }; + + const videoId = getVideoId(youtubeUrl); + + useEffect(() => { + const loadYouTubeAPI = () => { + const tag = document.createElement('script'); + tag.src = 'https://www.youtube.com/iframe_api'; + const firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + }; + + loadYouTubeAPI(); + + window.onYouTubeIframeAPIReady = () => { + playerRef.current = new window.YT.Player('ytplayer', { + height: '450', + width: '800', + videoId, + playerVars: { + autoplay: 1, + mute: 1, + }, + events: { + onReady: (event) => { + event.target.playVideo(); + + // Try to unmute after 5 seconds + setTimeout(() => { + try { + event.target.unMute(); + } catch (err) { + console.log('Auto-unmute failed:', err); + } + }, 5000); // 5000ms = 5 seconds + }, + }, + }); + }; + }, [videoId]); + + return ( +
+
+
+ ); +}; + +export default YouTubePlayer; diff --git a/src/assets/canada_cities.json b/src/assets/canada_cities.json new file mode 100644 index 0000000..e0cac6a --- /dev/null +++ b/src/assets/canada_cities.json @@ -0,0 +1,1765 @@ +{ + "Ontario": [ + "Toronto", + "Ottawa", + "Hamilton", + "Mississauga", + "Brampton", + "Kitchener", + "London", + "Markham", + "Oshawa", + "Vaughan", + "Windsor", + "St. Catharines", + "Oakville", + "Richmond Hill", + "Burlington", + "Sudbury", + "Barrie", + "Guelph", + "Whitby", + "Cambridge", + "Milton", + "Ajax", + "Waterloo", + "Thunder Bay", + "Brantford", + "Chatham", + "Clarington", + "Pickering", + "Niagara Falls", + "Newmarket", + "Peterborough", + "Kawartha Lakes", + "Caledon", + "Belleville", + "Sarnia", + "Sault Ste. Marie", + "Welland", + "Halton Hills", + "Aurora", + "North Bay", + "Stouffville", + "Cornwall", + "Georgina", + "Woodstock", + "Quinte West", + "St. Thomas", + "New Tecumseth", + "Innisfil", + "Bradford West Gwillimbury", + "Timmins", + "Lakeshore", + "Brant", + "Leamington", + "East Gwillimbury", + "Orangeville", + "Orillia", + "Stratford", + "Fort Erie", + "LaSalle", + "Centre Wellington", + "Grimsby", + "King", + "Woolwich", + "Clarence-Rockland", + "Midland", + "Lincoln", + "Wasaga Beach", + "Collingwood", + "Strathroy-Caradoc", + "Thorold", + "Amherstburg", + "Tecumseh", + "Essa", + "Owen Sound", + "Brockville", + "Kingsville", + "Springwater", + "Scugog", + "Uxbridge", + "Wilmot", + "Essex", + "Oro-Medonte", + "Cobourg", + "South Frontenac", + "Port Colborne", + "Huntsville", + "Russell", + "Niagara-on-the-Lake", + "Middlesex Centre", + "Selwyn", + "Tillsonburg", + "Pelham", + "Petawawa", + "North Grenville", + "Loyalist", + "Port Hope", + "Pembroke", + "Bracebridge", + "Greater Napanee", + "Kenora", + "Mississippi Mills", + "St. Clair", + "West Lincoln", + "West Nipissing / Nipissing Ouest", + "Clearview", + "Thames Centre", + "Carleton Place", + "Guelph/Eramosa", + "Central Elgin", + "Saugeen Shores", + "Ingersoll", + "South Stormont", + "Severn", + "South Glengarry", + "North Perth", + "Trent Hills", + "The Nation / La Nation", + "West Grey", + "Gravenhurst", + "Perth East", + "Wellington North", + "Brighton", + "Tiny", + "Hawkesbury", + "Brock", + "Erin", + "Kincardine", + "Elliot Lake", + "Arnprior", + "North Dundas", + "Wellesley", + "Georgian Bluffs", + "Norwich", + "Meaford", + "Adjala-Tosorontio", + "Hamilton Township", + "South Dundas", + "Lambton Shores", + "North Dumfries", + "Mapleton", + "Rideau Lakes", + "North Glengarry", + "South Huron", + "Penetanguishene", + "Tay", + "Cavan Monaghan", + "Temiskaming Shores", + "Grey Highlands", + "Alfred and Plantagenet", + "Elizabethtown-Kitley", + "Smiths Falls", + "Ramara", + "Leeds and the Thousand Islands", + "Brockton", + "Laurentian Valley", + "Mono", + "Malahide", + "Huron East", + "Beckwith", + "Shelburne", + "West Perth", + "Champlain", + "Minto", + "South Bruce Peninsula", + "Renfrew", + "Plympton-Wyoming", + "Kapuskasing", + "Zorra", + "Kirkland Lake", + "Aylmer", + "Puslinch", + "Drummond/North Elmsley", + "Hanover", + "Dryden", + "Fort Frances", + "Goderich", + "Stone Mills", + "South-West Oxford", + "Douro-Dummer", + "McNab/Braeside", + "Central Huron", + "Blandford-Blenheim", + "Bayham", + "Augusta", + "St. Marys", + "Southgate", + "Bluewater", + "East Zorra-Tavistock", + "Otonabee-South Monaghan", + "Huron-Kinloss", + "The Blue Mountains", + "Whitewater Region", + "Edwardsburgh/Cardinal", + "Wainfleet", + "North Stormont", + "Alnwick/Haldimand", + "Arran-Elderslie", + "Parry Sound", + "Muskoka Falls", + "Perth", + "Cramahe", + "North Middlesex", + "Dysart et al", + "Hindon Hill", + "Tweed", + "Oliver Paipoonge", + "Petrolia", + "Southwest Middlesex", + "Front of Yonge", + "Tay Valley", + "South Bruce", + "Ashfield-Colborne-Wawanosh", + "Trent Lakes", + "Gananoque", + "Lanark Highlands", + "Cochrane", + "Sioux Lookout", + "Hearst", + "Breslau", + "Stirling-Rawdon", + "Espanola", + "West Elgin", + "East Ferris", + "North Huron", + "Southwold", + "Centre Hastings", + "Lucan Biddulph", + "Greenstone", + "Tyendinaga", + "Iroquois Falls", + "Havelock-Belmont-Methuen", + "Central Frontenac", + "Seguin", + "Madawaska Valley", + "Deep River", + "Asphodel-Norwood", + "Red Lake", + "Hastings Highlands", + "Prescott", + "Northern Bruce Peninsula", + "Casselman", + "Callander", + "Amaranth", + "Marmora and Lake", + "Bancroft", + "Howick", + "Dutton/Dunwich", + "Perth South", + "Montague", + "Warwick", + "Bonnechere Valley", + "Morris-Turnberry", + "Mulmur", + "Blind River", + "Powassan", + "Highlands East", + "East Hawkesbury", + "Marathon", + "Shuniah", + "Sables-Spanish Rivers", + "Lake of Bays", + "Merrickville", + "Adelaide-Metcalfe", + "Melancthon", + "Laurentian Hills", + "Grand Valley", + "Admaston/Bromley", + "North Algona Wilberforce", + "Wawa", + "Horton", + "Enniskillen", + "Atikokan", + "Markstay", + "Northeastern Manitoulin and the Islands", + "McDougall", + "French River / Riviere des Francais", + "East Garafraxa", + "Greater Madawaska", + "Georgian Bay", + "North Kawartha", + "Perry", + "Black River-Matheson", + "Killaloe, Hagarty and Richards", + "Alvinston", + "Algonquin Highlands", + "Addington Highlands", + "Neebing", + "Bonfield", + "Central Manitoulin", + "Madoc", + "Mattawa", + "Dawn-Euphemia", + "Chapleau", + "Manitouwadge", + "Wellington", + "Frontenac Islands", + "Point Edward", + "North Frontenac", + "Komoka", + "Deseronto", + "Nipissing", + "Huron Shores", + "Nipigon", + "Burford", + "Terrace Bay", + "Macdonald, Meredith and Aberdeen Additional", + "Brudenell, Lyndoch and Raglan", + "Moosonee", + "Englehart", + "Strong", + "Lappe", + "Armour", + "Faraday", + "Bayfield", + "St.-Charles", + "Emo", + "Smooth Rock Falls", + "Chisholm", + "Thessalon", + "Conestogo", + "St. Joseph", + "Moonbeam", + "Claremont", + "Ignace", + "Armstrong", + "Hillsburgh", + "Sagamok", + "Hensall", + "Carling", + "Laird", + "Tara", + "Cobalt", + "South River", + "McKellar", + "South Algonquin", + "Sioux Narrows-Nestor Falls", + "Beachburg", + "Schreiber", + "Plantagenet", + "Papineau-Cameron", + "Assiginack", + "Prince", + "Athens", + "Chatsworth", + "Magnetawan" + ], + "Quebec": [ + "Montreal", + "Quebec City", + "Laval", + "Gatineau", + "Longueuil", + "Sherbrooke", + "Levis", + "Saguenay", + "Trois-Rivieres", + "Terrebonne", + "Saint-Jerome", + "Saint-Jean-sur-Richelieu", + "Brossard", + "Repentigny", + "Drummondville", + "Chateauguay", + "Granby", + "Mirabel", + "Blainville", + "Lac-Brome", + "Saint-Hyacinthe", + "Beloeil", + "Mascouche", + "Shawinigan", + "Joliette", + "Rimouski", + "Dollard-des-Ormeaux", + "Victoriaville", + "Saint-Eustache", + "Vaudreuil-Dorion", + "Salaberry-de-Valleyfield", + "Rouyn-Noranda", + "Boucherville", + "Sorel-Tracy", + "Cote-Saint-Luc", + "Pointe-Claire", + "Val-d'Or", + "Chambly", + "Alma", + "Sainte-Julie", + "Saint-Constant", + "Magog", + "Boisbriand", + "Sainte-Therese", + "La Prairie", + "Saint-Bruno-de-Montarville", + "Thetford Mines", + "Sept-Iles", + "Hudson", + "Saint-Lin--Laurentides", + "L'Assomption", + "Candiac", + "Saint-Lambert", + "Saint-Lazare", + "Varennes", + "Mont-Royal", + "Baie-Comeau", + "Riviere-du-Loup", + "Saint-Augustin-de-Desmaures", + "Sainte-Marthe-sur-le-Lac", + "Westmount", + "Les Coteaux", + "Kirkland", + "Dorval", + "Beaconsfield", + "Mont-Saint-Hilaire", + "Deux-Montagnes", + "Saint-Colomban", + "Sainte-Catherine", + "Saint-Basile-le-Grand", + "L'Ancienne-Lorette", + "Saint-Charles-Borromee", + "Cowansville", + "Sainte-Anne-des-Plaines", + "Gaspe", + "Pincourt", + "Mercier", + "Lavaltrie", + "Lachute", + "Rosemere", + "Matane", + "Mont-Laurier", + "Mistassini", + "Beauharnois", + "Becancour", + "Sainte-Sophie", + "Val-des-Monts", + "Saint-Amable", + "Sainte-Marie", + "Amos", + "Prevost", + "Sainte-Adele", + "Sainte-Agathe-des-Monts", + "Les Iles-de-la-Madeleine", + "Carignan", + "L'Ile-Perrot", + "Montmagny", + "Cantley", + "Notre-Dame-de-l'Ile-Perrot", + "Bromont", + "La Tuque", + "Rawdon", + "Saint-Felicien", + "Roberval", + "Bois-des-Filion", + "Marieville", + "Saint-Sauveur", + "Stoneham-et-Tewkesbury", + "Mont-Tremblant", + "Saint-Zotique", + "Saint-Raymond", + "Lorraine", + "Notre-Dame-des-Prairies", + "Sainte-Julienne", + "Donnacona", + "L'Epiphanie", + "Pont-Rouge", + "Coaticook", + "La Peche", + "Otterburn Park", + "Sainte-Brigitte-de-Laval", + "Sainte-Catherine-de-la-Jacques-Cartier", + "Farnham", + "Delson", + "La Malbaie", + "Boischatel", + "Beauport", + "Saint-Hippolyte", + "Old Chelsea", + "Saint-Apollinaire", + "Nicolet", + "Contrecoeur", + "La Sarre", + "Chandler", + "Acton Vale", + "Saint-Philippe", + "Rigaud", + "Louiseville", + "Chibougamau", + "Coteau-du-Lac", + "Saint-Remi", + "Les Cedres", + "Baie-Saint-Paul", + "Brownsburg", + "Asbestos", + "Hampstead", + "Saint-Joseph-du-Lac", + "Plessisville", + "Sainte-Anne-des-Monts", + "Saint-Lambert-de-Lauzon", + "Val-Shefford", + "Port-Cartier", + "Saint-Paul", + "Shannon", + "Saint-Honore", + "Beauceville", + "Beaupre", + "Charlemagne", + "Mont-Joli", + "Pointe-Calumet", + "Pontiac", + "L'Ange-Gardien", + "Saint-Felix-de-Valois", + "McMasterville", + "Saint-Calixte", + "Lac-Megantic", + "Saint-Henri", + "Vercheres", + "Richelieu", + "Princeville", + "Saint-Cesaire", + "Val-David", + "Notre-Dame-du-Mont-Carmel", + "Sainte-Martine", + "Saint-Roch-de-l'Achigan", + "Saint-Pie", + "Windsor", + "Montreal-Ouest", + "Temiscouata-sur-le-Lac", + "Sainte-Anne-de-Bellevue", + "Mont-Orford", + "Saint-Germain-de-Grantham", + "Saint-Cyrille-de-Wendover", + "Chisasibi", + "Chertsey", + "Lanoraie", + "Warwick", + "Napierville", + "Waterloo", + "Saint-Joseph-de-Beauce", + "Berthierville", + "Riviere-Rouge", + "Saint-Denis-de-Brompton", + "Amqui", + "Saint-Mathias-sur-Richelieu", + "Saint-Boniface", + "Chateau-Richer", + "Montreal-Est", + "Saint-Antonin", + "Saint-Jean-de-Matha", + "La Pocatiere", + "Roxton Pond", + "Saint-Etienne-des-Gres", + "Saint-Donat", + "Metabetchouan-Lac-a-la-Croix", + "Maniwaki", + "Danville", + "Lac-Etchemin", + "Saint-Jacques", + "L'Islet-sur-Mer", + "Carleton-sur-Mer", + "Oka", + "Morin-Heights", + "Crabtree", + "Saint-Tite", + "New Richmond", + "Baie-d'Urfe", + "Saint-Andre-Avellin", + "Saint-Ambroise-de-Kildare", + "East Angus", + "Saint-Adolphe-d'Howard", + "Saint-Prosper", + "Ormstown", + "Saint-Agapit", + "Saint-Ambroise", + "Mistissini", + "Saint-Faustin--Lac-Carre", + "Saint-Pascal", + "Dunham", + "Havre-Saint-Pierre", + "Saint-Anselme", + "Trois-Pistoles", + "Grande-Riviere", + "Malartic", + "Saint-Maurice", + "Ascot Corner", + "Fossambault-sur-le-Lac", + "Sainte-Anne-des-Lacs", + "Saint-Sulpice", + "Saint-Alphonse-de-Granby", + "Sainte-Claire", + "Perce", + "Saint-Jean-Port-Joli", + "Saint-Andre-d'Argenteuil", + "Saint-Come--Liniere", + "Forestville", + "Compton", + "Richmond", + "Saint-Gabriel-de-Valcartier", + "Paspebiac", + "Saint-Thomas", + "Saint-Jean-Baptiste", + "Portneuf", + "Normandin", + "Saint-Alphonse-Rodriguez", + "Val-Morin", + "Clermont", + "Saint-Christophe-d'Arthabaska", + "Mont-Saint-Gregoire", + "Thurso", + "Saint-Gabriel", + "Saint-Liboire", + "Degelis", + "Saint-Alexis-des-Monts", + "Cap-Saint-Ignace", + "Saint-Anaclet-de-Lessard", + "Stoke", + "Cap Sante", + "Saint-David-de-Falardeau", + "Saint-Ferreol-les-Neiges", + "Senneterre", + "Saint-Mathieu-de-Beloeil", + "Sainte-Marie-Madeleine", + "Sainte-Melanie", + "Saint-Paul-d'Abbotsford", + "Saint-Michel", + "Saint-Marc-des-Carrieres", + "Stanstead", + "Sainte-Anne-de-Beaupre", + "Sainte-Luce", + "Saint-Joseph-de-Sorel", + "Ferme-Neuve", + "Yamachiche", + "Adstock", + "Bonaventure", + "Pohenegamook", + "Saint-Isidore", + "Sainte-Marguerite-du-Lac-Masson", + "Saint-Prime", + "Kuujjuaq", + "Grenville-sur-la-Rouge", + "Saint-Dominique", + "Macamic", + "Sainte-Anne-de-Sorel", + "Rougemont", + "Piedmont", + "Lac-des-Ecorces", + "Saint-Pamphile", + "Bedford", + "Weedon-Centre", + "Lacolle", + "Saint-Gabriel-de-Brandon", + "Huntingdon", + "Saint-Bruno", + "Laurier-Station", + "Saint-Anicet", + "Cap-Chat", + "Notre-Dame-de-Lourdes", + "Ville-Marie", + "Wickham", + "Neuville", + "Maria", + "Saint-Chrysostome", + "Saint-Damase", + "Disraeli", + "Saint-Alexandre", + "Herbertville", + "Sainte-Thecle", + "Fermont", + "La Presentation", + "Sainte-Catherine-de-Hatley", + "Saint-Basile", + "Saint-Raphael", + "Saint-Martin", + "Causapscal", + "Brigham", + "Sainte-Victoire-de-Sorel", + "Port-Daniel--Gascons", + "Labelle", + "Saint-Michel-des-Saints", + "Saint-Victor", + "Saint-Ephrem-de-Beauce", + "Lery", + "Temiscaming", + "Sainte-Genevieve-de-Berthier", + "Sainte-Madeleine", + "Sainte-Croix", + "Valcourt", + "Saint-Mathieu", + "Waterville", + "Mansfield-et-Pontefract", + "Saint-Denis", + "Gore", + "Saint-Gedeon-de-Beauce", + "Saint-Leonard-d'Aston", + "Fort-Coulonge", + "Albanel", + "Pessamit", + "Maskinonge", + "Saint-Charles-de-Bellechasse", + "Hatley", + "East Broughton", + "Saint-Polycarpe", + "Deschambault", + "Wendake", + "Saint-Come", + "Waskaganish", + "Lebel-sur-Quevillon", + "Pierreville", + "Saint-Gilles", + "Saint-Bernard", + "Sainte-Cecile-de-Milton", + "Saint-Roch-de-Richelieu", + "Saint-Nazaire", + "Saint-Elzear", + "Hinchinbrooke", + "Saint-Francois-Xavier-de-Brompton", + "Papineauville", + "Saint-Ignace-de-Loyola", + "Sainte-Anne-de-Sabrevois", + "Sainte-Anne-de-la-Perade", + "Saint-Damien-de-Buckland", + "Saint-Ferdinand", + "Saint-Fulgence", + "Manouane", + "Saint-Gervais", + "Saint-Alexandre-de-Kamouraska", + "Saint-Marc-sur-Richelieu", + "Mandeville", + "Caplan", + "Saint-Damien", + "Lac-Nominingue", + "Obedjiwan", + "Saint-Gedeon", + "Kingsey Falls", + "L'Ascension-de-Notre-Seigneur", + "Barraute", + "Saint-Liguori", + "Saint-Patrice-de-Sherrington", + "Saint-Esprit", + "Mashteuiatsh", + "Saint-Francois-du-Lac", + "Vallee-Jonction", + "Saint-Fabien", + "Lac-Superieur", + "Les Escoumins", + "Terrasse-Vaudreuil", + "Riviere-Beaudette", + "Saint-Barthelemy", + "Austin", + "Saint-Paul-de-l'Ile-aux-Noix", + "Saint-Cyprien-de-Napierville", + "Deleage", + "Potton", + "Sainte-Beatrix", + "Saint-Georges-de-Cacouna", + "Sainte-Justine", + "Saint-Valerien-de-Milton", + "Saint-Cuthbert", + "Saint-Blaise-sur-Richelieu", + "Saint-Joseph-de-Coleraine", + "Pointe-Lebel", + "Grenville", + "Saint-Michel-de-Bellechasse", + "Sainte-Angele-de-Monnoir", + "Champlain", + "Sacre-Coeur-Saguenay", + "Saint-Lucien", + "Saint-Robert", + "La Guadeloupe", + "Sutton", + "Saint-Placide", + "Povungnituk", + "Pointe-des-Cascades", + "Chambord", + "Dudswell", + "Saint-Narcisse", + "Waswanipi", + "Inukjuak", + "Saint-Zacharie", + "Hemmingford", + "Saint-Pierre-de-l'Ile-d'Orleans", + "Saint-Clet", + "Saint-Ours", + "Sainte-Anne-de-la-Pocatiere", + "Notre-Dame-du-Bon-Conseil", + "Sainte-Clotilde", + "Nouvelle", + "Yamaska", + "Saint-Antoine-de-Tilly", + "Saint-Elie-de-Caxton", + "Price", + "Saint-Jacques-le-Mineur", + "Val-Joli", + "Saint-Antoine-sur-Richelieu", + "Saint-Pacome", + "Saint-Stanislas-de-Kostka", + "Frontenac", + "Sainte-Emelie-de-l'Energie", + "Saint-Charles-sur-Richelieu", + "Sainte-Helene-de-Bagot", + "Franklin Centre", + "Mille-Isles", + "Lyster", + "Sainte-Clotilde-de-Horton", + "Saint-Benoit-Labre", + "Maliotenam", + "Chapais", + "Saint-Honore-de-Shenley", + "Cleveland", + "Messines", + "Saint-Laurent-de-l'Ile-d'Orleans", + "Saint-Jean-de-Dieu", + "Larouche", + "Saint-Francois-de-la-Riviere-du-Sud", + "Eeyou Istchee Baie-James", + "Shawville", + "Lambton", + "Saint-Flavien", + "Sainte-Marcelline-de-Kildare", + "Riviere-Blanche", + "Saint-Felix-de-Kingsey", + "Sainte-Elisabeth", + "Uashat", + "Saint-Bernard-de-Lacolle", + "Saint-Guillaume", + "Venise-en-Quebec", + "Saint-Paulin", + "Saint-Albert", + "Matagami", + "Amherst", + "Notre-Dame-du-Laus", + "Saint-Tite-des-Caps", + "Saint-Casimir", + "Saint-Malachie", + "Salluit", + "Saint-Louis-de-Gonzague", + "Saint-Urbain", + "Tring-Jonction", + "Saint-Joachim", + "Saint-Theodore-d'Acton", + "L' Isle-Verte", + "Palmarolle", + "Saint-Odilon-de-Cranbourne", + "La Dore", + "Lac-au-Saumon", + "Wotton", + "Wemindji", + "Pointe-aux-Outardes", + "Riviere-Heva", + "Scott", + "Godmanchester", + "Saint-Simon", + "Tingwick", + "Saint-Aubert", + "Saint-Mathieu-du-Parc", + "Saint-Ubalde", + "Berthier-sur-Mer", + "Frampton", + "Chute-aux-Outardes", + "New Carlisle", + "Saint-Majorique-de-Grantham", + "Wentworth-Nord", + "Sainte-Ursule", + "Nantes", + "Lac-aux-Sables", + "Vaudreuil-sur-le-Lac", + "Amulet", + "L'Avenir", + "Pointe-a-la-Croix", + "Herouxville", + "L'Isle-aux-Allumettes", + "Sainte-Brigide-d'Iberville", + "Les Eboulements", + "Sainte-Barbe", + "Saint-Louis-du-Ha! Ha!", + "Ragueneau", + "Saint-Edouard", + "Riviere-Bleue", + "Noyan", + "Notre-Dame-du-Portage", + "Saint-Hugues", + "Sainte-Anne-du-Sault", + "La Conception", + "L'Isle-aux-Coudres", + "Sainte-Lucie-des-Laurentides", + "Saint-Alexis", + "Roxton Falls", + "Clarendon", + "Saint-Ludger", + "Racine", + "Saint-Zenon", + "Saint-Armand", + "Saint-Edouard-de-Lotbiniere", + "Saint-Arsene", + "Listuguj", + "Saint-Hubert-de-Riviere-du-Loup", + "Saint-Jude", + "La Minerve", + "Trecesson", + "Notre-Dame-des-Pins", + "Saint-Alban", + "Saint-Pierre-les-Becquets", + "Labrecque", + "Sainte-Henedine", + "L'Anse-Saint-Jean", + "Akwesasne", + "Saint-Valere", + "Saint-Norbert-d'Arthabaska", + "Saint-Hilarion", + "Saint-Modeste", + "Saint-Simeon", + "Saint-Barnabe", + "Bury", + "Lac-Bouchette", + "Saint-Lazare-de-Bellechasse", + "Saint-Michel-du-Squatec", + "Saint-Joachim-de-Shefford", + "Grand-Remous", + "Saint-Gabriel-de-Rimouski", + "Sainte-Marie-Salome", + "Saint-Cyprien", + "Tres-Saint-Sacrement", + "Saints-Anges", + "Saint-Urbain-Premier", + "Sainte-Agathe-de-Lotbiniere", + "Grande-Vallee", + "Mont-Carmel", + "Saint-Eugene", + "Notre-Dame-des-Neiges", + "Saint-Leon-de-Standon", + "Sayabec", + "Sainte-Sabine", + "Saint-Maxime-du-Mont-Louis", + "Blanc-Sablon", + "Ayer's Cliff", + "Les Mechins", + "Sainte-Marguerite", + "Saint-Claude", + "Sainte-Jeanne-d'Arc", + "Sainte-Felicite", + "Girardville", + "Saint-Bruno-de-Guigues", + "Upton", + "Saint-Narcisse-de-Beaurivage", + "Plaisance", + "Roxton-Sud", + "Saint-Frederic", + "Saint-Narcisse-de-Rimouski", + "Saint-Patrice-de-Beaurivage", + "Sainte-Marthe", + "Notre-Dame-du-Nord", + "Saint-Aime-des-Lacs", + "Lac-Drolet", + "Coleraine", + "Saint-Bonaventure", + "Saint-Wenceslas", + "Sainte-Genevieve-de-Batiscan", + "Saint-Justin", + "Saint-Norbert", + "Riviere-Ouelle", + "Stukely-Sud", + "Saint-Georges-de-Clarenceville", + "Sainte-Therese-de-Gaspe", + "Sainte-Petronille", + "Desbiens", + "La Macaza", + "Saint-Vallier", + "Bristol", + "Saint-Sylvestre", + "Saint-Stanislas", + "Longue-Rive", + "Saint-Leonard-de-Portneuf", + "Brebeuf", + "Baie-du-Febvre", + "Durham-Sud", + "Melbourne", + "Hebertville", + "Lorrainville", + "Saint-Rene-de-Matane", + "Eastman", + "Wemotaci", + "Cookshire", + "Laurierville", + "Ripon", + "Henryville", + "Gracefield", + "Yamaska-Est", + "Frelighsburg" + ], + "British Columbia": [ + "Vancouver", + "Surrey", + "Victoria", + "Burnaby", + "Richmond", + "Kelowna", + "Abbotsford", + "Coquitlam", + "Saanich", + "White Rock", + "Delta", + "Nanaimo", + "Kamloops", + "Chilliwack", + "Maple Ridge", + "New Westminster", + "Prince George", + "Port Coquitlam", + "North Vancouver", + "Vernon", + "Courtenay", + "Langford Station", + "West Vancouver", + "Mission", + "Campbell River", + "Penticton", + "East Kelowna", + "Port Moody", + "North Cowichan", + "Langley", + "Parksville", + "Duncan", + "Squamish", + "Port Alberni", + "Fort St. John", + "Cranbrook", + "Salmon Arm", + "Pitt Meadows", + "Colwood", + "Oak Bay", + "Esquimalt", + "Central Saanich", + "Lake Country", + "Sooke", + "Comox", + "Terrace", + "Powell River", + "Trail", + "Dawson Creek", + "Sidney", + "Prince Rupert", + "North Saanich", + "Quesnel", + "Williams Lake", + "Whistler", + "Summerland", + "View Royal", + "Nelson", + "Ladysmith", + "Coldstream", + "Sechelt", + "Castlegar", + "Gibsons", + "Qualicum Beach", + "Kitimat", + "Kimberley", + "Merritt", + "Kent", + "Hope", + "Peachland", + "Oliver", + "Fernie", + "Creston", + "Northern Rockies", + "Smithers", + "Armstrong", + "Spallumcheen", + "Osoyoos", + "Metchosin", + "Westbank", + "Cumberland", + "Vanderhoof", + "Bowen Island", + "Grand Forks", + "Port Hardy", + "Sparwood", + "Rossland", + "Mackenzie", + "Golden", + "Fruitvale", + "Invermere", + "Ellison", + "Lake Cowichan", + "Cedar", + "Enderby", + "Houston", + "Pemberton", + "Errington", + "Princeton", + "Cowichan Bay", + "Royston", + "Elkford", + "Highlands", + "Sicamous", + "Chase", + "Tumbler Ridge", + "Anmore", + "Clearwater", + "Lillooet", + "Logan Lake", + "Port McNeill", + "Tofino", + "Burns Lake", + "Saltair", + "Lumby", + "One Hundred Mile House", + "Ucluelet", + "Chetwynd", + "Harrison Hot Springs", + "Nisga'a", + "Lakeview", + "Keremeos", + "Warfield", + "Popkum", + "Coombs", + "Naramata", + "Nakusp", + "Fort St. James", + "Hilliers", + "Ashcroft", + "Grindrod", + "Windermere", + "Gold River", + "Dunsmuir", + "Barriere", + "Lions Bay", + "Telkwa", + "Ootischenia", + "Taylor", + "Sorrento", + "Youbou", + "Kaleden", + "Salmo", + "Valemount", + "Hudson Hope" + ], + "Alberta": [ + "Calgary", + "Edmonton", + "Red Deer", + "Lethbridge", + "Airdrie", + "Wood Buffalo", + "St. Albert", + "Grande Prairie", + "Medicine Hat", + "Spruce Grove", + "Leduc", + "Cochrane", + "Okotoks", + "Fort Saskatchewan", + "Chestermere", + "Beaumont", + "Lloydminster", + "Camrose", + "Stony Plain", + "Sylvan Lake", + "Canmore", + "Cold Lake", + "Brooks", + "Strathmore", + "High River", + "Lacombe", + "Wetaskiwin", + "Morinville", + "Blackfalds", + "Hinton", + "Whitecourt", + "Olds", + "Taber", + "Coaldale", + "Edson", + "Banff", + "Drumheller", + "Innisfail", + "Drayton Valley", + "Ponoka", + "Peace River", + "Slave Lake", + "Rocky Mountain House", + "Devon", + "Wainwright", + "Bonnyville", + "Stettler", + "St. Paul", + "Vegreville", + "Crowsnest Pass", + "Redcliff", + "Didsbury", + "Westlock", + "Jasper", + "Barrhead", + "Vermilion", + "Carstairs", + "Raymond", + "Claresholm", + "Pincher Creek", + "Crossfield", + "Cardston", + "Grande Cache", + "High Level", + "Penhold", + "Gibbons", + "Three Hills", + "Fort Macleod", + "Athabasca", + "Coalhurst", + "Sundre", + "Grimshaw", + "Black Diamond", + "Sexsmith", + "Rimbey", + "High Prairie", + "Turner Valley", + "Hanna", + "Beaverlodge", + "Magrath", + "Calmar", + "Nanton", + "Redwater", + "Tofield", + "Provost", + "Bow Island", + "Fox Creek", + "Millet", + "Picture Butte", + "Vulcan", + "Valleyview", + "Lamont", + "Wabasca", + "Springbrook", + "Wembley", + "Bon Accord", + "Elk Point", + "Nobleford", + "Two Hills", + "Bruederheim", + "Mayerthorpe", + "Swan Hills", + "Vauxhall", + "Bowden", + "Legal", + "Bassano", + "Manning", + "Irricana", + "Eckville", + "Alberta Beach", + "Duchess", + "Viking", + "Bentley", + "Trochu", + "Falher", + "Onoway", + "Oyen" + ], + "Manitoba": [ + "Winnipeg", + "Brandon", + "Steinbach", + "Springfield", + "Hanover", + "Winkler", + "Portage La Prairie", + "Thompson", + "Tache", + "St. Andrews", + "St. Clements", + "Selkirk", + "Morden", + "East St. Paul", + "Stanley", + "Macdonald", + "Dauphin", + "Rockwood", + "Ritchot", + "The Pas", + "West St. Paul", + "La Broquerie", + "Niverville", + "Brokenhead", + "Stonewall", + "Ste. Anne", + "Flin Flon (Part)", + "Neepawa", + "Cornwallis", + "Headingley", + "Altona", + "Swan River", + "De Salaberry", + "Lorette", + "Killarney - Turtle Mountain", + "Woodlands", + "Bifrost-Riverton", + "Cartier", + "Hillsburg-Roblin-Shell River", + "WestLake-Gladstone", + "Mitchell", + "Beausejour", + "Lac du Bonnet", + "Virden", + "Morris", + "Carman", + "North Cypress-Langford", + "Minnedosa", + "Dufferin", + "Kelsey", + "Gimli", + "West Interlake", + "Prairie View", + "Deloraine-Winchester", + "Oakland-Wawanesa", + "Brenda-Waskada", + "Russell-Binscarth", + "Ellice-Archie", + "Souris-Glenwood", + "Riverdale", + "Pembina", + "Wallace-Woodworth", + "Lorne", + "Yellowhead", + "Swan Valley West", + "Grey", + "Gilbert Plains", + "Norfolk-Treherne", + "Emerson-Franklin", + "Sifton", + "Grassland", + "Louise", + "Ste. Rose", + "Cartwright-Roblin", + "Mossey River", + "Lakeshore", + "Riding Mountain West", + "Clanwilliam-Erickson", + "Glenboro-South Cypress", + "North Norfolk", + "Reinland", + "Minitonas-Bowsman", + "Carberry", + "Armstrong", + "Grunthal", + "Piney", + "Blumenort", + "Fisher", + "Wasagamack", + "Whitehead", + "Rosedale", + "Stuartburn", + "Oakview", + "Harrison Park", + "Boissevain", + "Pinawa", + "Pipestone", + "Prairie Lakes", + "St. Francois Xavier", + "Grahamdale", + "Reynolds", + "St. Laurent", + "Landmark", + "Powerview-Pine Falls", + "St-Pierre-Jolys", + "Arborg", + "Elton", + "Rosser", + "Montcalm", + "Coldwell", + "Alonsa", + "Teulon", + "Minto-Odanah", + "Glenella-Lansdowne", + "Two Borders", + "Winnipeg Beach", + "Victoria", + "Roland", + "Melita", + "Argyle", + "Hamiota", + "Gillam", + "Grand View", + "McCreary", + "Rossburn", + "Ethelbert" + ], + "Nova Scotia": [ + "Halifax", + "Cape Breton", + "Truro", + "New Glasgow", + "Inverness", + "Kentville", + "Chester", + "Queens", + "Amherst", + "Bridgewater", + "Church Point", + "Argyle", + "Yarmouth", + "Barrington", + "Antigonish", + "Windsor", + "Wolfville", + "Stellarton", + "Westville", + "Port Hawkesbury", + "Pictou", + "Berwick", + "Trenton", + "Lunenburg", + "Digby", + "Middleton", + "Shelburne", + "Lantz", + "Falmouth", + "Stewiacke", + "Parrsboro", + "Oxford", + "Centreville", + "Wedgeport", + "Mahone Bay" + ], + "Saskatchewan": [ + "Saskatoon", + "Regina", + "Prince Albert", + "Moose Jaw", + "Lloydminster", + "Swift Current", + "Yorkton", + "North Battleford", + "Warman", + "Weyburn", + "Estevan", + "Martensville", + "Corman Park No. 344", + "Melfort", + "Humboldt", + "Meadow Lake", + "La Ronge", + "Flin Flon", + "White City", + "Kindersley", + "Melville", + "Edenwold No. 158", + "Nipawin", + "Battleford", + "Prince Albert No. 461", + "Buckland No. 491", + "Tisdale", + "La Loche", + "Vanscoy No. 345", + "Pelican Narrows", + "Pilot Butte", + "Unity", + "Meadow Lake No. 588", + "Moosomin", + "Esterhazy", + "Rosetown", + "Assiniboia", + "Rosthern No. 403", + "Outlook", + "Canora", + "Biggar", + "Maple Creek", + "Dundurn No. 314", + "Britannia No. 502", + "Rama", + "Swift Current No. 137", + "Blucher", + "Lumsden No. 189", + "Fort Qu'Appelle", + "Indian Head", + "Watrous", + "Orkney No. 244", + "Kamsack", + "Lumsden", + "Regina Beach", + "Shaunavon", + "Wynyard", + "Dalmeny", + "Balgonie", + "Rosthern", + "Shellbrook No. 493", + "Carlyle", + "Langham", + "Hudson Bay", + "Frenchman Butte", + "Wilton No. 472", + "Torch River No. 488", + "Shellbrook", + "Macklin", + "Creighton", + "Laird No. 404", + "Canwood No. 494", + "Spiritwood No. 496", + "Oxbow", + "Wadena", + "Wilkie", + "Ile-a-la-Crosse", + "Estevan No. 5", + "Lanigan", + "South Qu'Appelle No. 157", + "Mervin No. 499", + "Osler", + "Beaver River", + "Moose Jaw No. 161", + "Langenburg", + "Maidstone", + "Kipling", + "Carnduff", + "Foam Lake", + "Hudson Bay No. 394", + "Waldheim", + "Buffalo Narrows", + "Air Ronge", + "Weyburn No. 67", + "Grenfell", + "St. Louis No. 431", + "Pinehouse", + "Preeceville", + "Maple Creek No. 111", + "Birch Hills", + "Kerrobert", + "Eston", + "Kindersley No. 290", + "Davidson", + "Battle River No. 438", + "Delisle", + "Longlaketon No. 219", + "Nipawin No. 487", + "Duck Lake No. 463", + "Gravelbourg", + "Lajord No. 128" + ], + "Newfoundland and Labrador": [ + "St. John's", + "Conception Bay South", + "Paradise", + "Mount Pearl Park", + "Corner Brook", + "Grand Falls", + "Gander", + "Labrador City", + "Portugal Cove-St. Philip's", + "Happy Valley", + "Torbay", + "Stephenville", + "Bay Roberts", + "Clarenville", + "Carbonear", + "Marystown", + "Deer Lake", + "Goulds", + "Channel-Port aux Basques", + "Pasadena", + "Placentia", + "Bonavista", + "Lewisporte", + "Bishops Falls", + "Harbour Grace", + "Springdale", + "Botwood", + "Spaniards Bay", + "Holyrood", + "Logy Bay-Middle Cove-Outer Cove", + "Burin", + "Grand Bank", + "St. Anthony", + "Fogo Island", + "Twillingate", + "New-Wes-Valley", + "Wabana", + "Glovertown", + "Pouch Cove", + "Kippens", + "Wabush", + "Trinity Bay North", + "Victoria", + "Flat Rock", + "Stephenville Crossing", + "Witless Bay", + "Harbour Breton", + "Massey Drive", + "Bay Bulls", + "Upper Island Cove", + "Clarkes Beach", + "Gambo", + "Humbermouth", + "Baie Verte", + "Burgeo", + "Irishtown-Summerside", + "St. George's", + "St. Lawrence", + "St. Alban's", + "Centreville-Wareham-Trinity", + "Nain", + "Harbour Main-Chapel's Cove-Lakeview", + "Fortune", + "Dildo" + ], + "New Brunswick": [ + "Moncton", + "Saint John", + "Fredericton", + "Dieppe", + "Quispamsis", + "Riverview", + "Miramichi", + "Edmundston", + "Bathurst", + "Oromocto", + "Campbellton", + "Shediac", + "Beaubassin East / Beaubassin-est", + "Douglas", + "Sussex", + "Tracadie", + "Sackville", + "Grand Falls", + "Woodstock", + "Burton", + "Saint Marys", + "Memramcook", + "Grand Bay-Westfield", + "Shippagan", + "Coverdale", + "Hanwell", + "Saint Stephen", + "Hampton", + "Beresford", + "Caraquet", + "New Maryland", + "Dundas", + "Simonds", + "Alnwick", + "Studholm", + "Bright", + "Kingston", + "Dalhousie", + "Wellington", + "Kingsclear", + "Wakefield", + "Cocagne", + "Shippegan", + "Lincoln", + "Cap Pele", + "Salisbury", + "Buctouche", + "Grand Manan", + "Saint George", + "Paquetville", + "Minto", + "Upper Miramichi", + "Hardwicke", + "Saint-Quentin", + "Pennfield Ridge", + "Northesk", + "Kent", + "Westfield Beach", + "Allardville", + "Saint-Charles", + "Saint Mary", + "Petit Rocher", + "Eel River Crossing", + "Manners Sutton", + "Richibucto", + "Saint-Louis", + "Saint Andrews", + "Maugerville", + "Brighton", + "Saint-Antoine", + "Northampton", + "Wicklow", + "Neguac", + "Balmoral", + "Southesk", + "Saint-Jacques", + "Florenceville", + "Perth", + "Saint-Joseph", + "Belledune", + "Nauwigewauk", + "Glenelg", + "Saint David", + "Springfield", + "St. George", + "Gordon", + "Southampton", + "Denmark", + "Sussex Corner", + "Petitcodiac", + "Bas Caraquet", + "Upham", + "Cardwell", + "Hillsborough", + "Weldford", + "Norton", + "Charlo", + "Richmond", + "Saint-Leonard", + "Lameque", + "Musquash", + "Queensbury", + "New Bandon", + "Peel", + "Saint James", + "Saint Martins", + "Rogersville", + "McAdam", + "Newcastle", + "Bertrand", + "Saint-Andre", + "Greenwich", + "Chipman", + "Noonan", + "Atholville", + "Durham", + "Havelock", + "Botsford", + "Plaster Rock", + "Wilmot", + "Kedgwick", + "Dorchester", + "Rothesay" + ], + "Prince Edward Island": [ + "Charlottetown", + "Summerside", + "Stratford", + "Cornwall", + "Montague", + "Kensington", + "Miltonvale Park", + "Alberton", + "Souris", + "Malpeque" + ], + "Yukon": [ + "Whitehorse", + "Dawson" + ], + "Northwest Territories": [ + "Yellowknife", + "Hay River", + "Inuvik", + "Fort Smith", + "Behchoko", + "Fort Simpson" + ], + "Nunavut": [ + "Iqaluit", + "Rankin Inlet", + "Arviat", + "Baker Lake", + "Cambridge Bay", + "Igloolik", + "Pond Inlet", + "Pangnirtung", + "Cape Dorset", + "Gjoa Haven", + "Repulse Bay", + "Clyde River", + "Taloyoak", + "Kugluktuk" + ] +} \ No newline at end of file diff --git a/src/assets/dine_360_ads_fav_icon.png b/src/assets/dine_360_ads_fav_icon.png new file mode 100644 index 0000000..9ea56f7 Binary files /dev/null and b/src/assets/dine_360_ads_fav_icon.png differ diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..a461c50 --- /dev/null +++ b/src/index.css @@ -0,0 +1 @@ +@import "tailwindcss"; \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..f297e12 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,11 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { LoadingProvider } from "./Context/LoadingContext"; +import './index.css' + +ReactDOM.createRoot(document.getElementById("root")).render( + + + +); diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..a2d3dc2 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(),tailwindcss(),], +})