diff --git a/RestroHub-FrontEnd/eslint.config.js b/RestroHub-FrontEnd/eslint.config.js new file mode 100644 index 00000000..b3a5154d --- /dev/null +++ b/RestroHub-FrontEnd/eslint.config.js @@ -0,0 +1,59 @@ +import js from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; + +const browserGlobals = { + IntersectionObserver: "readonly", + Blob: "readonly", + FileReader: "readonly", + FormData: "readonly", + URL: "readonly", + alert: "readonly", + clearTimeout: "readonly", + console: "readonly", + document: "readonly", + fetch: "readonly", + localStorage: "readonly", + navigator: "readonly", + setTimeout: "readonly", + window: "readonly", +}; + +export default [ + { + ignores: ["dist", "node_modules"], + }, + { + files: ["src/**/*.{js,jsx}"], + languageOptions: { + ecmaVersion: 2022, + globals: browserGlobals, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + sourceType: "module", + }, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...js.configs.recommended.rules, + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^[A-Z_]", + varsIgnorePattern: "^[A-Z_]", + }, + ], + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + }, +]; diff --git a/RestroHub-FrontEnd/package-lock.json b/RestroHub-FrontEnd/package-lock.json index f9ad811a..c4908341 100644 --- a/RestroHub-FrontEnd/package-lock.json +++ b/RestroHub-FrontEnd/package-lock.json @@ -23,7 +23,7 @@ "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", "react-qr-code": "^2.0.18", - "react-router-dom": "^7.13.0", + "react-router-dom": "^6.30.1", "recharts": "^3.7.0", "three": "^0.182.0", "yup": "^1.7.1" @@ -32,7 +32,7 @@ "@tailwindcss/forms": "^0.5.11", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react": "^5.0.0", "autoprefixer": "^10.4.24", "eslint": "^9.39.2", "eslint-plugin-react": "^7.32.0", @@ -58,13 +58,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -73,9 +73,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -83,22 +83,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -115,14 +114,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -132,14 +131,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -149,9 +148,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -159,29 +158,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -201,9 +200,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -211,9 +210,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -221,9 +220,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -231,27 +230,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -301,33 +300,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -335,14 +334,14 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1364,7 +1363,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.18.0.tgz", "integrity": "sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==", - "peer": true, "dependencies": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.26.7", @@ -1478,10 +1476,19 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/@remix-run/router": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", + "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", "dev": true, "license": "MIT" }, @@ -2056,7 +2063,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -2089,7 +2095,6 @@ "version": "0.182.0", "resolved": "https://registry.npmjs.org/@types/three/-/three-0.182.0.tgz", "integrity": "sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==", - "peer": true, "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", @@ -2128,24 +2133,24 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", + "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", + "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "react-refresh": "^0.18.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@webgpu/types": { @@ -2159,7 +2164,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2594,7 +2598,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2857,19 +2860,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -2918,8 +2908,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/d3-array": { "version": "3.2.4", @@ -3503,7 +3492,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4507,7 +4495,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -5030,7 +5017,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5733,7 +5719,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -5860,7 +5845,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6114,7 +6098,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -6138,7 +6121,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -6182,8 +6164,7 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-qr-code": { "version": "2.0.18", @@ -6226,7 +6207,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -6246,9 +6226,9 @@ } }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", "engines": { @@ -6256,41 +6236,35 @@ } }, "node_modules/react-router": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", - "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", + "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", "license": "MIT", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "@remix-run/router": "1.23.3" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", - "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", + "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", "license": "MIT", "dependencies": { - "react-router": "7.13.0" + "@remix-run/router": "1.23.3", + "react-router": "6.30.4" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-use-measure": { @@ -6377,8 +6351,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -6629,12 +6602,6 @@ "semver": "bin/semver.js" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -7041,7 +7008,6 @@ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -7121,8 +7087,7 @@ "node_modules/three": { "version": "0.182.0", "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz", - "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==", - "peer": true + "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==" }, "node_modules/three-mesh-bvh": { "version": "0.7.8", @@ -7531,7 +7496,6 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -7763,7 +7727,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx b/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx index 61861b79..07ad7d91 100644 --- a/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx +++ b/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx @@ -27,20 +27,19 @@ const Sidebar = ({ open, setOpen, collapsed, setCollapsed }) => { marketing: false, }); - // Auto-expand active parent on mount + // Auto-expand active parent when the route changes. useEffect(() => { - if (location.pathname.startsWith('/admin/store')) { - setExpandedMenus((prev) => ({ ...prev, store: true })); - } - if (location.pathname.startsWith('/admin/marketing')) { - setExpandedMenus((prev) => ({ ...prev, marketing: true })); - } - }, []); + setExpandedMenus((prev) => ({ + ...prev, + store: prev.store || location.pathname.startsWith('/admin/store'), + marketing: prev.marketing || location.pathname.startsWith('/admin/marketing'), + })); + }, [location.pathname]); // Close mobile sidebar on route change useEffect(() => { setOpen(false); - }, [location.pathname]); + }, [location.pathname, setOpen]); const toggleMenu = (menu) => { if (collapsed) { @@ -456,4 +455,4 @@ const Sidebar = ({ open, setOpen, collapsed, setCollapsed }) => { ); }; -export default Sidebar; \ No newline at end of file +export default Sidebar; diff --git a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/LiveOrders.jsx b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/LiveOrders.jsx index 1453264d..6489574e 100644 --- a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/LiveOrders.jsx +++ b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/LiveOrders.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { Clock, ChefHat, @@ -6,9 +6,15 @@ import { RefreshCw, AlertCircle } from 'lucide-react'; -import api from "@services/common/api"; import { useAdminTheme } from '@context/AdminThemeContext'; +const FALLBACK_ORDERS = [ + { id: 123, table: 4, amount: 450, status: 'cooking', items: '2x Paneer, 1x Lassi' }, + { id: 124, table: 7, amount: 320, status: 'ready', items: '1x Biryani, 2x Roti' }, + { id: 125, table: 2, amount: 780, status: 'cooking', items: '3x Thali' }, + { id: 126, table: 9, amount: 190, status: 'pending', items: '2x Lassi' }, +]; + // ============================================ // STATUS BADGE (Private to this file) // ============================================ @@ -83,30 +89,9 @@ const LiveOrders = () => { const [refreshing, setRefreshing] = useState(false); const { isDark } = useAdminTheme(); - // ------------------------------------ - // FALLBACK DATA - // ------------------------------------ - const fallbackOrders = [ - { id: 123, table: 4, amount: 450, status: 'cooking', items: '2x Paneer, 1x Lassi' }, - { id: 124, table: 7, amount: 320, status: 'ready', items: '1x Biryani, 2x Roti' }, - { id: 125, table: 2, amount: 780, status: 'cooking', items: '3x Thali' }, - { id: 126, table: 9, amount: 190, status: 'pending', items: '2x Lassi' }, - ]; - - // ------------------------------------ - // FETCH DATA - // ------------------------------------ - useEffect(() => { - fetchOrders(); - - // 🔌 UNCOMMENT: Auto-refresh every 30 seconds - // const interval = setInterval(fetchOrders, 30000); - // return () => clearInterval(interval); - }, []); - - const fetchOrders = async () => { + const fetchOrders = useCallback(async ({ initial = false } = {}) => { try { - if (!loading) setRefreshing(true); + if (!initial) setRefreshing(true); setError(null); // 🔌 UNCOMMENT WHEN API READY @@ -115,17 +100,28 @@ const LiveOrders = () => { // 🎭 MOCK await new Promise(resolve => setTimeout(resolve, 600)); - setOrders(fallbackOrders); + setOrders(FALLBACK_ORDERS); } catch (err) { console.error('Failed to fetch orders:', err); setError('Failed to load orders'); - setOrders(fallbackOrders); + setOrders(FALLBACK_ORDERS); } finally { setLoading(false); setRefreshing(false); } - }; + }, []); + + // ------------------------------------ + // FETCH DATA + // ------------------------------------ + useEffect(() => { + fetchOrders({ initial: true }); + + // 🔌 UNCOMMENT: Auto-refresh every 30 seconds + // const interval = setInterval(fetchOrders, 30000); + // return () => clearInterval(interval); + }, [fetchOrders]); // ------------------------------------ // RENDER @@ -180,4 +176,4 @@ const LiveOrders = () => { ); }; -export default LiveOrders; \ No newline at end of file +export default LiveOrders; diff --git a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/QuickActions.jsx b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/QuickActions.jsx index 61e93e22..8010f64e 100644 --- a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/QuickActions.jsx +++ b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/QuickActions.jsx @@ -7,7 +7,6 @@ import { Download, Loader2 } from 'lucide-react'; -import api from "@services/common/api"; import { useAdminTheme } from '@context/AdminThemeContext'; // import { useNavigate } from 'react-router-dom'; // if using react-router @@ -182,4 +181,4 @@ const QuickActions = () => { ); }; -export default QuickActions; \ No newline at end of file +export default QuickActions; diff --git a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/RevenueChart.jsx b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/RevenueChart.jsx index 29ff0b6e..784bed59 100644 --- a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/RevenueChart.jsx +++ b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/RevenueChart.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { RefreshCw, AlertCircle } from 'lucide-react'; import { AreaChart, @@ -9,9 +9,18 @@ import { Tooltip, ResponsiveContainer } from 'recharts'; -import api from "@services/common/api"; import { useAdminTheme } from '@context/AdminThemeContext'; +const FALLBACK_REVENUE_DATA = [ + { day: '1', revenue: 24000 }, + { day: '5', revenue: 32000 }, + { day: '10', revenue: 28000 }, + { day: '15', revenue: 45000 }, + { day: '20', revenue: 38000 }, + { day: '25', revenue: 52000 }, + { day: '30', revenue: 45230 }, +]; + // ============================================ // MAIN COMPONENT (Exported) // ============================================ @@ -21,27 +30,7 @@ const RevenueChart = () => { const [error, setError] = useState(null); const { isDark } = useAdminTheme(); - // ------------------------------------ - // FALLBACK DATA - // ------------------------------------ - const fallbackData = [ - { day: '1', revenue: 24000 }, - { day: '5', revenue: 32000 }, - { day: '10', revenue: 28000 }, - { day: '15', revenue: 45000 }, - { day: '20', revenue: 38000 }, - { day: '25', revenue: 52000 }, - { day: '30', revenue: 45230 }, - ]; - - // ------------------------------------ - // FETCH DATA - // ------------------------------------ - useEffect(() => { - fetchRevenue(); - }, []); - - const fetchRevenue = async () => { + const fetchRevenue = useCallback(async () => { try { setLoading(true); setError(null); @@ -52,16 +41,23 @@ const RevenueChart = () => { // 🎭 MOCK await new Promise(resolve => setTimeout(resolve, 1000)); - setData(fallbackData); + setData(FALLBACK_REVENUE_DATA); } catch (err) { console.error('Failed to fetch revenue:', err); setError('Failed to load chart'); - setData(fallbackData); + setData(FALLBACK_REVENUE_DATA); } finally { setLoading(false); } - }; + }, []); + + // ------------------------------------ + // FETCH DATA + // ------------------------------------ + useEffect(() => { + fetchRevenue(); + }, [fetchRevenue]); // ------------------------------------ // RENDER @@ -131,4 +127,4 @@ const RevenueChart = () => { ); }; -export default RevenueChart; \ No newline at end of file +export default RevenueChart; diff --git a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/StatsSection.jsx b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/StatsSection.jsx index 02b1f138..09dd5342 100644 --- a/RestroHub-FrontEnd/src/components/admin/dashboard/cards/StatsSection.jsx +++ b/RestroHub-FrontEnd/src/components/admin/dashboard/cards/StatsSection.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { IndianRupee, ShoppingCart, @@ -10,19 +10,66 @@ import { import api from "@services/common/api"; import { useAdminTheme } from '@context/AdminThemeContext'; -// ============================================ -// STAT CARD (Private to this file) -// ============================================ -const StatCard = ({ title, value, change, positive, subtitle, icon: Icon, color, pulse, progress }) => { +const FALLBACK_STATS = [ + { + title: "Today's Revenue", + value: 'Rs.45,230', + change: '+24%', + positive: true, + icon: IndianRupee, + color: 'green', + }, + { + title: 'Live Orders', + value: '12', + subtitle: 'active', + icon: ShoppingCart, + color: 'orange', + pulse: true, + }, + { + title: 'WhatsApp Messages', + value: '156/1000', + progress: 15.6, + icon: MessageSquare, + color: 'emerald', + }, + { + title: 'UPI Success', + value: '89%', + subtitle: '(78/89)', + icon: CreditCard, + color: 'purple', + }, +]; + +const ICON_MAP = { + revenue: IndianRupee, + orders: ShoppingCart, + messages: MessageSquare, + payments: CreditCard, +}; + +const StatCard = ({ + title, + value, + change, + positive, + subtitle, + icon: Icon, + color, + pulse, + progress, +}) => { const { isDark } = useAdminTheme(); const colorClasses = { - green: isDark ? 'bg-green-900/40 text-green-400' : 'bg-green-100 text-green-600', - orange: isDark ? 'bg-orange-900/40 text-orange-400' : 'bg-orange-100 text-orange-600', - emerald: isDark ? 'bg-emerald-900/40 text-emerald-400': 'bg-emerald-100 text-emerald-600', - purple: isDark ? 'bg-purple-900/40 text-purple-400' : 'bg-purple-100 text-purple-600', - blue: isDark ? 'bg-blue-900/40 text-blue-400' : 'bg-blue-100 text-blue-600', - red: isDark ? 'bg-red-900/40 text-red-400' : 'bg-red-100 text-red-600', + green: isDark ? 'bg-green-900/40 text-green-400' : 'bg-green-100 text-green-600', + orange: isDark ? 'bg-orange-900/40 text-orange-400' : 'bg-orange-100 text-orange-600', + emerald: isDark ? 'bg-emerald-900/40 text-emerald-400' : 'bg-emerald-100 text-emerald-600', + purple: isDark ? 'bg-purple-900/40 text-purple-400' : 'bg-purple-100 text-purple-600', + blue: isDark ? 'bg-blue-900/40 text-blue-400' : 'bg-blue-100 text-blue-600', + red: isDark ? 'bg-red-900/40 text-red-400' : 'bg-red-100 text-red-600', }; return ( @@ -65,11 +112,9 @@ const StatCard = ({ title, value, change, positive, subtitle, icon: Icon, color, ); }; -// ============================================ -// SKELETON LOADER (Private to this file) -// ============================================ const StatCardSkeleton = () => { const { isDark } = useAdminTheme(); + return (
@@ -82,106 +127,41 @@ const StatCardSkeleton = () => { ); }; -// ============================================ -// MAIN COMPONENT (Exported) -// ============================================ const StatsSection = () => { const [stats, setStats] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - // ------------------------------------ - // FALLBACK DATA (used when API fails) - // ------------------------------------ - const fallbackStats = [ - { - title: "Today's Revenue", - value: '₹45,230', - change: '+24%', - positive: true, - icon: IndianRupee, - color: 'green', - }, - { - title: 'Live Orders', - value: '12', - subtitle: 'active', - icon: ShoppingCart, - color: 'orange', - pulse: true, - }, - { - title: 'WhatsApp Messages', - value: '156/1000', - progress: 15.6, - icon: MessageSquare, - color: 'emerald', - }, - { - title: 'UPI Success', - value: '89%', - subtitle: '(78/89)', - icon: CreditCard, - color: 'purple', - }, - ]; - - // ------------------------------------ - // ICON MAPPING (API returns string, we need component) - // ------------------------------------ - const iconMap = { - revenue: IndianRupee, - orders: ShoppingCart, - messages: MessageSquare, - payments: CreditCard, - }; - - // ------------------------------------ - // FETCH DATA - // ------------------------------------ - useEffect(() => { - fetchStats(); + const fetchStats = useCallback(async () => { + try { + setLoading(true); + setError(null); + + const response = await api.get("/secure/api/v1/dashboard/statistics"); + const apiStats = response.data.map((stat) => ({ + ...stat, + icon: ICON_MAP[stat.iconKey] || IndianRupee, + })); + + setStats(apiStats); + } catch (err) { + console.error("Failed to fetch stats:", err); + setError("Failed to load stats"); + setStats(FALLBACK_STATS); + } finally { + setLoading(false); + } }, []); - const fetchStats = async () => { - try { - setLoading(true); - setError(null); - - const response = await api.get("/secure/api/v1/dashboard/statistics"); - - - const apiStats = response.data.map(stat => ({ - ...stat, - icon: iconMap[stat.iconKey] || IndianRupee, - })); - - setStats(apiStats); - - } catch (err) { - console.error("Failed to fetch stats:", err); - setError("Failed to load stats"); - setStats(fallbackStats); - } finally { - setLoading(false); - } -}; - - // ------------------------------------ - // REFRESH (can be called from parent) - // ------------------------------------ - const refresh = () => { + useEffect(() => { fetchStats(); - }; + }, [fetchStats]); - // ------------------------------------ - // RENDER - // ------------------------------------ if (loading) { return (
- {[1, 2, 3, 4].map(i => ( - + {[1, 2, 3, 4].map((item) => ( + ))}
); @@ -192,7 +172,7 @@ const StatsSection = () => {

{error}