From 28639516d576877f74fb8bb9dd093a5914b07f62 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Tue, 30 Dec 2025 19:29:42 +0700 Subject: [PATCH] feat(FE-390): slicing UI and API integration for production dashboard --- package-lock.json | 395 +++- package.json | 3 +- src/app/dashboard/page.tsx | 8 +- .../pages/dashboard/DashboardProduction.tsx | 399 ++++ .../dashboard/chart/EggWeightBarChart.tsx | 89 + .../pages/dashboard/chart/FCRBarChart.tsx | 97 + .../dashboard/chart/ProductionLineChart.tsx | 357 ++++ .../pages/dashboard/chart/ProductionStat.tsx | 107 + .../dashboard/chart/StandardLineChart.tsx | 691 +++++++ .../DashboardProductionFilter.schema.ts | 16 + src/config/constant.ts | 2 +- .../dashboard/dashboard.production.dummy.json | 1801 +++++++++++++++++ .../dashboard/dashboard.production.dummy.ts | 27 + src/services/api/dashboard.ts | 34 + .../api/dashboard/dashboard-production.d.ts | 52 + 15 files changed, 4059 insertions(+), 19 deletions(-) create mode 100644 src/components/pages/dashboard/DashboardProduction.tsx create mode 100644 src/components/pages/dashboard/chart/EggWeightBarChart.tsx create mode 100644 src/components/pages/dashboard/chart/FCRBarChart.tsx create mode 100644 src/components/pages/dashboard/chart/ProductionLineChart.tsx create mode 100644 src/components/pages/dashboard/chart/ProductionStat.tsx create mode 100644 src/components/pages/dashboard/chart/StandardLineChart.tsx create mode 100644 src/components/pages/dashboard/filter/DashboardProductionFilter.schema.ts create mode 100644 src/dummy/dashboard/dashboard.production.dummy.json create mode 100644 src/dummy/dashboard/dashboard.production.dummy.ts create mode 100644 src/services/api/dashboard.ts create mode 100644 src/types/api/dashboard/dashboard-production.d.ts diff --git a/package-lock.json b/package-lock.json index c29a16a6..d7ffd3eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "react-hot-toast": "^2.6.0", "react-number-format": "^5.4.4", "react-select": "^5.10.2", + "recharts": "^3.6.0", "swr": "^2.3.6", "tailwind-merge": "^3.3.1", "use-debounce": "^10.0.6", @@ -1450,6 +1451,42 @@ "@react-pdf/stylesheet": "^6.1.1" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.3.tgz", + "integrity": "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1464,6 +1501,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -1804,6 +1853,69 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1871,7 +1983,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1902,6 +2013,12 @@ "license": "MIT", "optional": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.46.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", @@ -1948,7 +2065,6 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -2472,7 +2588,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3138,8 +3253,128 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT", - "peer": true + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, "node_modules/daisyui": { "version": "5.5.8", @@ -3245,6 +3480,12 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3587,6 +3828,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.43.0.tgz", + "integrity": "sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3605,7 +3856,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3779,7 +4029,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -4026,6 +4275,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -4651,6 +4906,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -4698,6 +4963,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/iobuffer": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", @@ -5244,7 +5518,6 @@ "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.4.tgz", "integrity": "sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "fast-png": "^6.2.0", @@ -6345,7 +6618,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -6376,7 +6648,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -6440,6 +6711,29 @@ "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-select": { "version": "5.10.2", "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", @@ -6477,6 +6771,51 @@ "react-dom": ">=16.6.0" } }, + "node_modules/recharts": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.6.0.tgz", + "integrity": "sha512-L5bjxvQRAe26RlToBAziKUB7whaGKEwD3znoM6fz3DrTowCIC/FnJYnuq1GEzB8Zv2kdTfaxQfi5GoH0tBinyg==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -6543,6 +6882,12 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -7263,6 +7608,12 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -7310,7 +7661,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -7478,7 +7828,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7635,6 +7984,28 @@ "base64-arraybuffer": "^1.0.2" } }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vite-compatible-readable-stream": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz", diff --git a/package.json b/package.json index 61cc5776..e331cf3b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react-hot-toast": "^2.6.0", "react-number-format": "^5.4.4", "react-select": "^5.10.2", + "recharts": "^3.6.0", "swr": "^2.3.6", "tailwind-merge": "^3.3.1", "use-debounce": "^10.0.6", @@ -50,4 +51,4 @@ "tailwindcss": "^4", "typescript": "^5" } -} +} \ No newline at end of file diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 4f2c344e..426cf6b9 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,9 +1,7 @@ +import DashboardProduction from '@/components/pages/dashboard/DashboardProduction'; + const Dashboard = () => { - return ( -
-

Dashboard

-
- ); + return ; }; export default Dashboard; diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx new file mode 100644 index 00000000..fb8190aa --- /dev/null +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -0,0 +1,399 @@ +'use client'; + +import Button from '@/components/Button'; +import Card from '@/components/Card'; +import { Icon } from '@iconify/react'; +import ProductionLineChart from '@/components/pages/dashboard/chart/ProductionLineChart'; +import StandardLineChart from '@/components/pages/dashboard/chart/StandardLineChart'; +import EggWeightBarChart from '@/components/pages/dashboard/chart/EggWeightBarChart'; +import FCRBarChart from '@/components/pages/dashboard/chart/FCRBarChart'; +import ProductionStat from '@/components/pages/dashboard/chart/ProductionStat'; +import Modal, { useModal } from '@/components/Modal'; +import DateInput from '@/components/input/DateInput'; +import SelectInput, { + OptionType, + useSelect, +} from '@/components/input/SelectInput'; +import { RadioGroup } from '@/components/input/RadioInput'; +import { useState } from 'react'; +import useSWR from 'swr'; +import { DashboardApi } from '@/services/api/dashboard'; +import { useFormik } from 'formik'; +import dashboardProductionFilterSchema from '@/components/pages/dashboard/filter/DashboardProductionFilter.schema'; +import { ProjectFlockApi } from '@/services/api/production'; +import { ProductionStandardApi } from '@/services/api/master-data'; + +const DashboardProduction = () => { + const filterModal = useModal(); + const [selectedPeriod, setSelectedPeriod] = useState('daily'); + const [selectedStandards, setSelectedStandards] = useState([ + 'hen_day', + 'hen_house', + ]); + const [endpointUrl, setEndpointUrl] = useState('/dashboard'); + + // ===== FETCH DATA ===== + const { + data: dashboardProductionResponse, + isLoading: isLoadingDashboardProductionData, + error: dashboardProductionError, + } = useSWR(endpointUrl, () => + DashboardApi.getDashboardProductionFetcher(endpointUrl) + ); + + const dashboardProductionData = + dashboardProductionResponse?.status === 'success' + ? dashboardProductionResponse.data + : undefined; + + // ===== SELECT ===== + const { options: flockOptions, isLoadingOptions: isLoadingFlockOptions } = + useSelect(ProjectFlockApi.basePath, 'id', 'flock_name', '', { + limit: 'limit', + category: 'LAYING', + }); + const { + options: standardProductionOptions, + isLoadingOptions: isLoadingStandardProductionOptions, + } = useSelect(ProductionStandardApi.basePath, 'id', 'name', '', { + limit: 'limit', + }); + + // ===== FORMIK ===== + const formik = useFormik({ + initialValues: { + startDate: '', + endDate: '', + flock: [] as OptionType[], + standard_production_id: [] as OptionType[], + standard_productions: [] as OptionType[], + period: selectedPeriod, + }, + validationSchema: dashboardProductionFilterSchema, + onSubmit: (values) => { + console.log(values); + // Build URL with query parameters + const params = new URLSearchParams(); + + if (values.startDate) params.set('startDate', values.startDate); + if (values.endDate) params.set('endDate', values.endDate); + + if (values.flock && values.flock.length > 0) { + const flockIds = values.flock + .map((f: OptionType) => f.value || f) + .join(','); + params.set('flock', flockIds); + } + + if ( + values.standard_production_id && + values.standard_production_id.length > 0 + ) { + const standardIds = values.standard_production_id + .map((s: OptionType) => s.value || s) + .join(','); + params.set('standard_production_id', standardIds); + } + + if (selectedStandards.length > 0) { + params.set('standards', selectedStandards.join(',')); + } + + params.set('period', selectedPeriod); + + const newUrl = `/dashboard?${params.toString()}`; + setEndpointUrl(newUrl); + + // Close modal after applying filter + filterModal.closeModal(); + }, + }); + + const handleResetFilter = () => { + formik.resetForm(); + setSelectedPeriod('daily'); + setSelectedStandards(['hen_day', 'hen_house']); + setEndpointUrl('/dashboard'); + }; + + if (isLoadingDashboardProductionData) { + return ( +
+ +
+ ); + } + return ( + <> +
+
+

Dashboard

+
+ + +
+
+ + {/* Dashboard Statistics */} + + + {/* Charts Grid */} +
+ {/* Production Line Chart */} + + + + + {/* Standard Line Chart */} + + + + + {/* Bar Charts Grid - 2 columns */} +
+ {/* FCR Bar Chart */} + + + + + {/* Egg Weight Bar Chart */} + + + +
+
+
+ +
+ {/* Modal Header */} +
+
+ +

Filter Data

+
+ +
+ +
+ {/* Rentang Waktu */} +
+ +
+ + + +
+
+ + {/* Flock */} +
+ formik.setFieldValue('flock', selected)} + errorMessage={formik.errors.flock as string} + options={flockOptions} + isLoading={isLoadingFlockOptions} + isMulti + isError={ + Boolean(formik.errors.flock) && Boolean(formik.touched.flock) + } + /> +
+ + {/* Production */} +
+ + formik.setFieldValue('standard_production_id', selected) + } + errorMessage={formik.errors.standard_production_id as string} + options={standardProductionOptions} + isLoading={isLoadingStandardProductionOptions} + isMulti + isError={ + Boolean(formik.errors.standard_production_id) && + Boolean(formik.touched.standard_production_id) + } + /> +
+ + {/* Standard */} +
+ ({ + value: s, + label: + s === 'hen_day' + ? 'Hen Day' + : s === 'hen_house' + ? 'Hen House' + : s === 'uniformity' + ? 'Uniformity' + : s === 'egg_weight' + ? 'Egg Weight' + : 'Egg Mass', + }))} + options={[ + { value: 'hen_day', label: 'Hen Day' }, + { value: 'hen_house', label: 'Hen House' }, + { value: 'uniformity', label: 'Uniformity' }, + { value: 'egg_weight', label: 'Egg Weight' }, + { value: 'egg_mass', label: 'Egg Mass' }, + ]} + isMulti + onChange={(selected: OptionType | OptionType[] | null) => { + const values = Array.isArray(selected) + ? selected.map((item) => String(item.value)) + : []; + setSelectedStandards( + values.length > 0 ? values : ['hen_day'] + ); + }} + isError={ + Boolean(formik.errors.standard_productions) && + Boolean(formik.touched.standard_productions) + } + /> +
+ + {/* Periode Perbandingan */} +
+ +
+ + + + +
+
+ + {/* Action Buttons */} +
+ + +
+
+
+
+ + ); +}; + +export default DashboardProduction; diff --git a/src/components/pages/dashboard/chart/EggWeightBarChart.tsx b/src/components/pages/dashboard/chart/EggWeightBarChart.tsx new file mode 100644 index 00000000..7a9a02c6 --- /dev/null +++ b/src/components/pages/dashboard/chart/EggWeightBarChart.tsx @@ -0,0 +1,89 @@ +'use client'; + +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + Cell, +} from 'recharts'; +import { DashboardProductionEggWeights } from '@/types/api/dashboard/dashboard-production'; + +interface EggWeightBarChartProps { + data?: DashboardProductionEggWeights[]; +} + +const EggWeightBarChart = ({ data }: EggWeightBarChartProps) => { + // Show loading state if no data + if (!data || data.length === 0) { + return ( +
+

+ Rata-rata Berat Telur (EW) +

+
+

Memuat data...

+
+
+ ); + } + + return ( +
+

Rata-rata Berat Telur (EW)

+ + + + + + + value !== undefined ? [`${value} gram`, ''] : ['', ''] + } + cursor={{ fill: 'rgba(59, 130, 246, 0.1)' }} + /> + + {data.map((entry, index) => ( + + ))} + + + +
+ ); +}; + +export default EggWeightBarChart; diff --git a/src/components/pages/dashboard/chart/FCRBarChart.tsx b/src/components/pages/dashboard/chart/FCRBarChart.tsx new file mode 100644 index 00000000..2647c7f7 --- /dev/null +++ b/src/components/pages/dashboard/chart/FCRBarChart.tsx @@ -0,0 +1,97 @@ +'use client'; + +import { + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + Cell, +} from 'recharts'; +import { DashboardProductionFcrData } from '@/types/api/dashboard/dashboard-production'; + +interface FCRBarChartProps { + data?: DashboardProductionFcrData[]; +} + +// Alternating colors: green and red +const colors = ['#10b981', '#ef4444']; + +const FCRBarChart = ({ data }: FCRBarChartProps) => { + // Show loading state if no data + if (!data || data.length === 0) { + return ( +
+

+ Feed Conversion Ratio (FCR) +

+
+

Memuat data...

+
+
+ ); + } + + return ( +
+

+ Feed Conversion Ratio (FCR) +

+ + + + + + + value !== undefined ? [value.toFixed(2), 'FCR'] : ['', ''] + } + cursor={{ fill: 'rgba(16, 185, 129, 0.1)' }} + /> + + {data.map((entry, index) => ( + + ))} + + + +
+ ); +}; + +export default FCRBarChart; diff --git a/src/components/pages/dashboard/chart/ProductionLineChart.tsx b/src/components/pages/dashboard/chart/ProductionLineChart.tsx new file mode 100644 index 00000000..470e09c9 --- /dev/null +++ b/src/components/pages/dashboard/chart/ProductionLineChart.tsx @@ -0,0 +1,357 @@ +'use client'; + +import { useState } from 'react'; +import { + LineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from 'recharts'; + +// Sample data in API format +const sampleApiData: ProductionChartItem[] = [ + { + date: '2025-12-01T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 88 }, + { id: 2, name: 'Flock A-001', data: 92 }, + { id: 3, name: 'Flock B-001', data: 90 }, + { id: 4, name: 'Flock B-002', data: 85 }, + ], + }, + { + date: '2025-12-03T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 85 }, + { id: 2, name: 'Flock A-001', data: 95 }, + { id: 3, name: 'Flock B-001', data: 93 }, + { id: 4, name: 'Flock B-002', data: 87 }, + ], + }, + { + date: '2025-12-05T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 82 }, + { id: 2, name: 'Flock A-001', data: 98 }, + { id: 3, name: 'Flock B-001', data: 91 }, + { id: 4, name: 'Flock B-002', data: 84 }, + ], + }, + { + date: '2025-12-07T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 80 }, + { id: 2, name: 'Flock A-001', data: 89 }, + { id: 3, name: 'Flock B-001', data: 88 }, + { id: 4, name: 'Flock B-002', data: 82 }, + ], + }, + { + date: '2025-12-08T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 83 }, + { id: 2, name: 'Flock A-001', data: 92 }, + { id: 3, name: 'Flock B-001', data: 95 }, + { id: 4, name: 'Flock B-002', data: 85 }, + ], + }, + { + date: '2025-12-11T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 81 }, + { id: 2, name: 'Flock A-001', data: 88 }, + { id: 3, name: 'Flock B-001', data: 92 }, + { id: 4, name: 'Flock B-002', data: 83 }, + ], + }, + { + date: '2025-12-13T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 84 }, + { id: 2, name: 'Flock A-001', data: 90 }, + { id: 3, name: 'Flock B-001', data: 89 }, + { id: 4, name: 'Flock B-002', data: 86 }, + ], + }, + { + date: '2025-12-15T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 82 }, + { id: 2, name: 'Flock A-001', data: 94 }, + { id: 3, name: 'Flock B-001', data: 96 }, + { id: 4, name: 'Flock B-002', data: 84 }, + ], + }, + { + date: '2025-12-17T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 80 }, + { id: 2, name: 'Flock A-001', data: 91 }, + { id: 3, name: 'Flock B-001', data: 93 }, + { id: 4, name: 'Flock B-002', data: 82 }, + ], + }, + { + date: '2025-12-19T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 79 }, + { id: 2, name: 'Flock A-001', data: 88 }, + { id: 3, name: 'Flock B-001', data: 90 }, + { id: 4, name: 'Flock B-002', data: 81 }, + ], + }, + { + date: '2025-12-21T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 81 }, + { id: 2, name: 'Flock A-001', data: 97 }, + { id: 3, name: 'Flock B-001', data: 92 }, + { id: 4, name: 'Flock B-002', data: 83 }, + ], + }, + { + date: '2025-12-23T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 83 }, + { id: 2, name: 'Flock A-001', data: 95 }, + { id: 3, name: 'Flock B-001', data: 98 }, + { id: 4, name: 'Flock B-002', data: 85 }, + ], + }, + { + date: '2025-12-25T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 80 }, + { id: 2, name: 'Flock A-001', data: 89 }, + { id: 3, name: 'Flock B-001', data: 94 }, + { id: 4, name: 'Flock B-002', data: 82 }, + ], + }, + { + date: '2025-12-27T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 82 }, + { id: 2, name: 'Flock A-001', data: 93 }, + { id: 3, name: 'Flock B-001', data: 96 }, + { id: 4, name: 'Flock B-002', data: 84 }, + ], + }, + { + date: '2025-12-28T00:00:00Z', + flocks: [ + { id: 1, name: 'Flock A-002', data: 85 }, + { id: 2, name: 'Flock A-001', data: 96 }, + { id: 3, name: 'Flock B-001', data: 95 }, + { id: 4, name: 'Flock B-002', data: 87 }, + ], + }, +]; + +// Helper function to format date based on period +const formatDateByPeriod = ( + dateString: string, + period: 'daily' | 'weekly' | 'monthly' | 'yearly' +): string => { + const date = new Date(dateString); + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'Mei', + 'Jun', + 'Jul', + 'Agu', + 'Sep', + 'Okt', + 'Nov', + 'Des', + ]; + + switch (period) { + case 'daily': + // Format: "1 Des" + return `${date.getDate()} ${monthNames[date.getMonth()]}`; + + case 'weekly': + // Format: "Week 1 Des" + const weekNumber = Math.ceil(date.getDate() / 7); + return `Week ${weekNumber} ${monthNames[date.getMonth()]}`; + + case 'monthly': + // Format: "Des" + return monthNames[date.getMonth()]; + + case 'yearly': + // Format: "2025" + return date.getFullYear().toString(); + + default: + return dateString; + } +}; + +// Type definitions for API data +interface FlockData { + id: number; + name: string; + data: number; +} + +interface ProductionChartItem { + date: string; + flocks: FlockData[]; +} + +interface ProductionChartsData { + production_charts: ProductionChartItem[]; +} + +// Transform API data to Recharts format +const transformProductionData = (apiData: ProductionChartItem[]) => { + return apiData.map((item) => { + const transformed: Record = { + date: item.date.split('T')[0], // Extract YYYY-MM-DD from ISO string + }; + + // Add each flock's data as a property + item.flocks.forEach((flock) => { + transformed[flock.name] = flock.data; + }); + + return transformed; + }); +}; + +interface ProductionLineChartProps { + period?: 'daily' | 'weekly' | 'monthly' | 'yearly'; + data?: ProductionChartItem[]; // Optional API data +} + +const ProductionLineChart = ({ + period = 'daily', + data: apiData, +}: ProductionLineChartProps) => { + // State to track which lines are hidden + const [hiddenLines, setHiddenLines] = useState([]); + + // Use API data if provided, otherwise use sample data + const chartData = apiData + ? transformProductionData(apiData) + : transformProductionData(sampleApiData); + + // Handle legend click to show/hide lines + const handleLegendClick = (dataKey: string) => { + setHiddenLines((prev) => + prev.includes(dataKey) + ? prev.filter((key) => key !== dataKey) + : [...prev, dataKey] + ); + }; + + return ( +
+

+ Performa Produksi per Flock +

+ + + + formatDateByPeriod(value, period)} + /> + + + formatDateByPeriod(value as string, period) + } + /> + { + if (e.dataKey) handleLegendClick(e.dataKey as string); + }} + style={{ cursor: 'pointer' }} + /> + + + + + + +
+ ); +}; + +export default ProductionLineChart; + +// Export types for external use +export type { FlockData, ProductionChartItem, ProductionChartsData }; diff --git a/src/components/pages/dashboard/chart/ProductionStat.tsx b/src/components/pages/dashboard/chart/ProductionStat.tsx new file mode 100644 index 00000000..7e299223 --- /dev/null +++ b/src/components/pages/dashboard/chart/ProductionStat.tsx @@ -0,0 +1,107 @@ +import Card from '@/components/Card'; +import { Icon } from '@iconify/react'; +import { DashboardProductionStatisticsData } from '@/types/api/dashboard/dashboard-production'; +import { formatCurrency } from '@/lib/helper'; + +interface ProductionStatProps { + data?: DashboardProductionStatisticsData[]; +} + +const ProductionStat = ({ data }: ProductionStatProps) => { + // Helper function to get icon based on title + const getIcon = (title: string) => { + if (title.toLowerCase().includes('keuangan')) + return 'heroicons:currency-dollar'; + if (title.toLowerCase().includes('penjualan')) + return 'heroicons:arrow-trending-up'; + if (title.toLowerCase().includes('pembelian')) + return 'heroicons:shopping-cart'; + if (title.toLowerCase().includes('overhead')) return 'heroicons:calculator'; + return 'heroicons:chart-bar'; + }; + + // Helper function to get icon background color + const getIconBgColor = (title: string) => { + if (title.toLowerCase().includes('keuangan')) return 'bg-blue-500'; + if (title.toLowerCase().includes('penjualan')) return 'bg-green-500'; + if (title.toLowerCase().includes('pembelian')) return 'bg-orange-500'; + if (title.toLowerCase().includes('overhead')) return 'bg-purple-500'; + return 'bg-gray-500'; + }; + + // Show loading state if no data + if (!data || data.length === 0) { + return ( +
+ {[1, 2, 3, 4].map((i) => ( + +
+
+
+
+
+
+ ))} +
+ ); + } + + return ( +
+ {data.map((stat, index) => ( + +
+
+

{stat.title}

+

+ {formatCurrency(stat.value)} +

+

+ + {stat.change > 0 ? '+' : ''} + {stat.change}% vs{' '} + {stat.period === 'monthly' ? 'bulan lalu' : 'periode lalu'} +

+
+
+
+ +
+
+
+
+ ))} +
+ ); +}; + +export default ProductionStat; diff --git a/src/components/pages/dashboard/chart/StandardLineChart.tsx b/src/components/pages/dashboard/chart/StandardLineChart.tsx new file mode 100644 index 00000000..18bcabf6 --- /dev/null +++ b/src/components/pages/dashboard/chart/StandardLineChart.tsx @@ -0,0 +1,691 @@ +'use client'; + +import { useState } from 'react'; +import { + LineChart, + Line, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, +} from 'recharts'; + +// Type definitions for API data +interface FlockData { + id: number; + name: string; + data: number; +} + +interface StandardData { + name: string; + value: number; +} + +interface StandardChartItem { + week: number; + standards: StandardData[]; + flocks: FlockData[]; +} + +// Sample data in API format +const sampleApiData: StandardChartItem[] = [ + { + week: 18, + standards: [ + { name: 'hen_day', value: 40 }, + { name: 'hen_house', value: 38 }, + { name: 'uniformity', value: 85 }, + { name: 'egg_weight', value: 52 }, + { name: 'egg_mass', value: 20 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 38 }, + { id: 2, name: 'Flock A-002', data: 37 }, + { id: 3, name: 'Flock B-001', data: 39 }, + { id: 4, name: 'Flock B-002', data: 36 }, + ], + }, + { + week: 20, + standards: [ + { name: 'hen_day', value: 45 }, + { name: 'hen_house', value: 43 }, + { name: 'uniformity', value: 86 }, + { name: 'egg_weight', value: 54 }, + { name: 'egg_mass', value: 24 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 43 }, + { id: 2, name: 'Flock A-002', data: 42 }, + { id: 3, name: 'Flock B-001', data: 44 }, + { id: 4, name: 'Flock B-002', data: 41 }, + ], + }, + { + week: 22, + standards: [ + { name: 'hen_day', value: 48 }, + { name: 'hen_house', value: 46 }, + { name: 'uniformity', value: 87 }, + { name: 'egg_weight', value: 55 }, + { name: 'egg_mass', value: 26 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 47 }, + { id: 2, name: 'Flock A-002', data: 46 }, + { id: 3, name: 'Flock B-001', data: 48 }, + { id: 4, name: 'Flock B-002', data: 45 }, + ], + }, + { + week: 24, + standards: [ + { name: 'hen_day', value: 50 }, + { name: 'hen_house', value: 48 }, + { name: 'uniformity', value: 88 }, + { name: 'egg_weight', value: 56 }, + { name: 'egg_mass', value: 28 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 49 }, + { id: 2, name: 'Flock A-002', data: 48 }, + { id: 3, name: 'Flock B-001', data: 50 }, + { id: 4, name: 'Flock B-002', data: 47 }, + ], + }, + { + week: 26, + standards: [ + { name: 'hen_day', value: 52 }, + { name: 'hen_house', value: 50 }, + { name: 'uniformity', value: 89 }, + { name: 'egg_weight', value: 57 }, + { name: 'egg_mass', value: 30 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 50 }, + { id: 2, name: 'Flock A-002', data: 49 }, + { id: 3, name: 'Flock B-001', data: 51 }, + { id: 4, name: 'Flock B-002', data: 48 }, + ], + }, + { + week: 28, + standards: [ + { name: 'hen_day', value: 55 }, + { name: 'hen_house', value: 53 }, + { name: 'uniformity', value: 90 }, + { name: 'egg_weight', value: 58 }, + { name: 'egg_mass', value: 32 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 53 }, + { id: 2, name: 'Flock A-002', data: 52 }, + { id: 3, name: 'Flock B-001', data: 54 }, + { id: 4, name: 'Flock B-002', data: 51 }, + ], + }, + { + week: 30, + standards: [ + { name: 'hen_day', value: 58 }, + { name: 'hen_house', value: 56 }, + { name: 'uniformity', value: 91 }, + { name: 'egg_weight', value: 59 }, + { name: 'egg_mass', value: 34 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 55 }, + { id: 2, name: 'Flock A-002', data: 54 }, + { id: 3, name: 'Flock B-001', data: 56 }, + { id: 4, name: 'Flock B-002', data: 53 }, + ], + }, + { + week: 32, + standards: [ + { name: 'hen_day', value: 60 }, + { name: 'hen_house', value: 58 }, + { name: 'uniformity', value: 92 }, + { name: 'egg_weight', value: 60 }, + { name: 'egg_mass', value: 36 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 58 }, + { id: 2, name: 'Flock A-002', data: 57 }, + { id: 3, name: 'Flock B-001', data: 59 }, + { id: 4, name: 'Flock B-002', data: 56 }, + ], + }, + { + week: 34, + standards: [ + { name: 'hen_day', value: 62 }, + { name: 'hen_house', value: 60 }, + { name: 'uniformity', value: 92 }, + { name: 'egg_weight', value: 61 }, + { name: 'egg_mass', value: 38 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 60 }, + { id: 2, name: 'Flock A-002', data: 59 }, + { id: 3, name: 'Flock B-001', data: 61 }, + { id: 4, name: 'Flock B-002', data: 58 }, + ], + }, + { + week: 36, + standards: [ + { name: 'hen_day', value: 64 }, + { name: 'hen_house', value: 62 }, + { name: 'uniformity', value: 93 }, + { name: 'egg_weight', value: 62 }, + { name: 'egg_mass', value: 40 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 62 }, + { id: 2, name: 'Flock A-002', data: 61 }, + { id: 3, name: 'Flock B-001', data: 63 }, + { id: 4, name: 'Flock B-002', data: 60 }, + ], + }, + { + week: 38, + standards: [ + { name: 'hen_day', value: 66 }, + { name: 'hen_house', value: 64 }, + { name: 'uniformity', value: 93 }, + { name: 'egg_weight', value: 63 }, + { name: 'egg_mass', value: 42 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 64 }, + { id: 2, name: 'Flock A-002', data: 63 }, + { id: 3, name: 'Flock B-001', data: 65 }, + { id: 4, name: 'Flock B-002', data: 62 }, + ], + }, + { + week: 40, + standards: [ + { name: 'hen_day', value: 68 }, + { name: 'hen_house', value: 66 }, + { name: 'uniformity', value: 94 }, + { name: 'egg_weight', value: 64 }, + { name: 'egg_mass', value: 44 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 66 }, + { id: 2, name: 'Flock A-002', data: 65 }, + { id: 3, name: 'Flock B-001', data: 67 }, + { id: 4, name: 'Flock B-002', data: 64 }, + ], + }, + { + week: 42, + standards: [ + { name: 'hen_day', value: 70 }, + { name: 'hen_house', value: 68 }, + { name: 'uniformity', value: 94 }, + { name: 'egg_weight', value: 65 }, + { name: 'egg_mass', value: 46 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 68 }, + { id: 2, name: 'Flock A-002', data: 67 }, + { id: 3, name: 'Flock B-001', data: 69 }, + { id: 4, name: 'Flock B-002', data: 66 }, + ], + }, + { + week: 44, + standards: [ + { name: 'hen_day', value: 72 }, + { name: 'hen_house', value: 70 }, + { name: 'uniformity', value: 95 }, + { name: 'egg_weight', value: 66 }, + { name: 'egg_mass', value: 48 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 70 }, + { id: 2, name: 'Flock A-002', data: 69 }, + { id: 3, name: 'Flock B-001', data: 71 }, + { id: 4, name: 'Flock B-002', data: 68 }, + ], + }, + { + week: 46, + standards: [ + { name: 'hen_day', value: 74 }, + { name: 'hen_house', value: 72 }, + { name: 'uniformity', value: 95 }, + { name: 'egg_weight', value: 67 }, + { name: 'egg_mass', value: 50 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 72 }, + { id: 2, name: 'Flock A-002', data: 71 }, + { id: 3, name: 'Flock B-001', data: 73 }, + { id: 4, name: 'Flock B-002', data: 70 }, + ], + }, + { + week: 48, + standards: [ + { name: 'hen_day', value: 76 }, + { name: 'hen_house', value: 74 }, + { name: 'uniformity', value: 95 }, + { name: 'egg_weight', value: 68 }, + { name: 'egg_mass', value: 52 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 74 }, + { id: 2, name: 'Flock A-002', data: 73 }, + { id: 3, name: 'Flock B-001', data: 75 }, + { id: 4, name: 'Flock B-002', data: 72 }, + ], + }, + { + week: 50, + standards: [ + { name: 'hen_day', value: 78 }, + { name: 'hen_house', value: 76 }, + { name: 'uniformity', value: 96 }, + { name: 'egg_weight', value: 69 }, + { name: 'egg_mass', value: 54 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 76 }, + { id: 2, name: 'Flock A-002', data: 75 }, + { id: 3, name: 'Flock B-001', data: 77 }, + { id: 4, name: 'Flock B-002', data: 74 }, + ], + }, + { + week: 52, + standards: [ + { name: 'hen_day', value: 80 }, + { name: 'hen_house', value: 78 }, + { name: 'uniformity', value: 96 }, + { name: 'egg_weight', value: 70 }, + { name: 'egg_mass', value: 56 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 78 }, + { id: 2, name: 'Flock A-002', data: 77 }, + { id: 3, name: 'Flock B-001', data: 79 }, + { id: 4, name: 'Flock B-002', data: 76 }, + ], + }, + { + week: 54, + standards: [ + { name: 'hen_day', value: 82 }, + { name: 'hen_house', value: 80 }, + { name: 'uniformity', value: 96 }, + { name: 'egg_weight', value: 71 }, + { name: 'egg_mass', value: 58 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 80 }, + { id: 2, name: 'Flock A-002', data: 79 }, + { id: 3, name: 'Flock B-001', data: 81 }, + { id: 4, name: 'Flock B-002', data: 78 }, + ], + }, + { + week: 56, + standards: [ + { name: 'hen_day', value: 84 }, + { name: 'hen_house', value: 82 }, + { name: 'uniformity', value: 97 }, + { name: 'egg_weight', value: 72 }, + { name: 'egg_mass', value: 60 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 82 }, + { id: 2, name: 'Flock A-002', data: 81 }, + { id: 3, name: 'Flock B-001', data: 83 }, + { id: 4, name: 'Flock B-002', data: 80 }, + ], + }, + { + week: 58, + standards: [ + { name: 'hen_day', value: 86 }, + { name: 'hen_house', value: 84 }, + { name: 'uniformity', value: 97 }, + { name: 'egg_weight', value: 73 }, + { name: 'egg_mass', value: 62 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 84 }, + { id: 2, name: 'Flock A-002', data: 83 }, + { id: 3, name: 'Flock B-001', data: 85 }, + { id: 4, name: 'Flock B-002', data: 82 }, + ], + }, + { + week: 60, + standards: [ + { name: 'hen_day', value: 88 }, + { name: 'hen_house', value: 86 }, + { name: 'uniformity', value: 97 }, + { name: 'egg_weight', value: 74 }, + { name: 'egg_mass', value: 64 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 86 }, + { id: 2, name: 'Flock A-002', data: 85 }, + { id: 3, name: 'Flock B-001', data: 87 }, + { id: 4, name: 'Flock B-002', data: 84 }, + ], + }, + { + week: 62, + standards: [ + { name: 'hen_day', value: 90 }, + { name: 'hen_house', value: 88 }, + { name: 'uniformity', value: 98 }, + { name: 'egg_weight', value: 75 }, + { name: 'egg_mass', value: 66 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 88 }, + { id: 2, name: 'Flock A-002', data: 87 }, + { id: 3, name: 'Flock B-001', data: 89 }, + { id: 4, name: 'Flock B-002', data: 86 }, + ], + }, + { + week: 64, + standards: [ + { name: 'hen_day', value: 92 }, + { name: 'hen_house', value: 90 }, + { name: 'uniformity', value: 98 }, + { name: 'egg_weight', value: 76 }, + { name: 'egg_mass', value: 68 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 90 }, + { id: 2, name: 'Flock A-002', data: 89 }, + { id: 3, name: 'Flock B-001', data: 91 }, + { id: 4, name: 'Flock B-002', data: 88 }, + ], + }, + { + week: 66, + standards: [ + { name: 'hen_day', value: 94 }, + { name: 'hen_house', value: 92 }, + { name: 'uniformity', value: 98 }, + { name: 'egg_weight', value: 77 }, + { name: 'egg_mass', value: 70 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 92 }, + { id: 2, name: 'Flock A-002', data: 91 }, + { id: 3, name: 'Flock B-001', data: 93 }, + { id: 4, name: 'Flock B-002', data: 90 }, + ], + }, + { + week: 68, + standards: [ + { name: 'hen_day', value: 95 }, + { name: 'hen_house', value: 93 }, + { name: 'uniformity', value: 98 }, + { name: 'egg_weight', value: 78 }, + { name: 'egg_mass', value: 72 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 93 }, + { id: 2, name: 'Flock A-002', data: 92 }, + { id: 3, name: 'Flock B-001', data: 94 }, + { id: 4, name: 'Flock B-002', data: 91 }, + ], + }, + { + week: 70, + standards: [ + { name: 'hen_day', value: 96 }, + { name: 'hen_house', value: 94 }, + { name: 'uniformity', value: 99 }, + { name: 'egg_weight', value: 79 }, + { name: 'egg_mass', value: 74 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 94 }, + { id: 2, name: 'Flock A-002', data: 93 }, + { id: 3, name: 'Flock B-001', data: 95 }, + { id: 4, name: 'Flock B-002', data: 92 }, + ], + }, + { + week: 72, + standards: [ + { name: 'hen_day', value: 97 }, + { name: 'hen_house', value: 95 }, + { name: 'uniformity', value: 99 }, + { name: 'egg_weight', value: 80 }, + { name: 'egg_mass', value: 76 }, + ], + flocks: [ + { id: 1, name: 'Flock A-001', data: 95 }, + { id: 2, name: 'Flock A-002', data: 94 }, + { id: 3, name: 'Flock B-001', data: 96 }, + { id: 4, name: 'Flock B-002', data: 93 }, + ], + }, +]; + +// Transform API data to Recharts format +const transformStandardData = ( + apiData: StandardChartItem[], + selectedStandards: string[] = [ + 'hen_day', + 'hen_house', + 'uniformity', + 'egg_weight', + 'egg_mass', + ] +) => { + return apiData.map((item) => { + const transformed: Record = { + week: item.week, + }; + + // Add selected standards as properties + selectedStandards.forEach((standardName) => { + const standardData = item.standards.find((s) => s.name === standardName); + if (standardData) { + transformed[standardName] = standardData.value; + } + }); + + // Add each flock's data as a property + item.flocks.forEach((flock) => { + transformed[flock.name] = flock.data; + }); + + return transformed; + }); +}; + +interface StandardLineChartProps { + data?: StandardChartItem[]; + selectedStandards?: string[]; +} + +const StandardLineChart = ({ + data: apiData, + selectedStandards = [ + 'hen_day', + 'hen_house', + 'uniformity', + 'egg_weight', + 'egg_mass', + ], +}: StandardLineChartProps) => { + // State to track which lines are hidden + const [hiddenLines, setHiddenLines] = useState([]); + + // Use API data if provided, otherwise use sample data + const chartData = apiData + ? transformStandardData(apiData, selectedStandards) + : transformStandardData(sampleApiData, selectedStandards); + + // Handle legend click to show/hide lines + const handleLegendClick = (dataKey: string) => { + setHiddenLines((prev) => + prev.includes(dataKey) + ? prev.filter((key) => key !== dataKey) + : [...prev, dataKey] + ); + }; + + // Standard line colors mapping + const standardColors: Record = { + hen_day: '#94a3b8', + hen_house: '#64748b', + uniformity: '#475569', + egg_weight: '#334155', + egg_mass: '#1e293b', + }; + + // Standard names mapping for display + const standardLabels: Record = { + hen_day: 'Hen Day', + hen_house: 'Hen House', + uniformity: 'Uniformity', + egg_weight: 'Egg Weight', + egg_mass: 'Egg Mass', + }; + + return ( +
+

+ Perbandingan Henday per Umur +

+ + + + + + + value !== undefined ? [`${value}%`, ''] : ['', ''] + } + labelFormatter={(label) => `Minggu ${label}`} + /> + { + if (e.dataKey) handleLegendClick(e.dataKey as string); + }} + style={{ cursor: 'pointer' }} + /> + {/* Dynamic Standard Lines */} + {selectedStandards.map((standardName) => ( + + ))} + {/* Flock Lines */} + + + + + + +
+ ); +}; + +export default StandardLineChart; + +// Export types for external use +export type { FlockData, StandardData, StandardChartItem }; diff --git a/src/components/pages/dashboard/filter/DashboardProductionFilter.schema.ts b/src/components/pages/dashboard/filter/DashboardProductionFilter.schema.ts new file mode 100644 index 00000000..4ed86a48 --- /dev/null +++ b/src/components/pages/dashboard/filter/DashboardProductionFilter.schema.ts @@ -0,0 +1,16 @@ +import * as yup from 'yup'; + +const dashboardProductionFilterSchema = yup.object({ + startDate: yup.string().optional(), + endDate: yup.string().optional(), + flock: yup.array().optional(), + standard_production_id: yup.array().optional(), + standard_productions: yup.array().optional(), + period: yup.string().optional(), +}); + +export type DashboardProductionFilterValues = yup.InferType< + typeof dashboardProductionFilterSchema +>; + +export default dashboardProductionFilterSchema; diff --git a/src/config/constant.ts b/src/config/constant.ts index 69669141..48e5a435 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -308,7 +308,7 @@ export const FINANCE_INITIAL_BALANCE_TYPE_OPTIONS = [ { label: 'Saldo Awal Negatif', value: 'NEGATIVE' }, ]; -export const FINANCE_TRANSACTION_STATUS = ['PENJUALAN', 'PEMBELIAN']; +export const FINANCE_TRANSACTION_STATUS = ['PENJUALAN', 'PEMBELIAN', 'BIAYA']; export const FINANCE_INITIAL_BALANCE_STATUS = ['SALDO_AWAL']; diff --git a/src/dummy/dashboard/dashboard.production.dummy.json b/src/dummy/dashboard/dashboard.production.dummy.json new file mode 100644 index 00000000..4b2fbd1a --- /dev/null +++ b/src/dummy/dashboard/dashboard.production.dummy.json @@ -0,0 +1,1801 @@ +{ + "statistics_data": [ + { + "title": "Total Keuangan", + "value": 2850000000, + "change": 12.5, + "period": "monthly", + "changeType": "increase" + }, + { + "title": "Penjualan", + "value": 3200000, + "change": 8.3, + "period": "monthly", + "changeType": "increase" + }, + { + "title": "Pembelian", + "value": 1850000000, + "change": -3.2, + "period": "monthly", + "changeType": "decrease" + }, + { + "title": "Biaya Overhead", + "value": 160000000, + "change": -1.5, + "period": "monthly", + "changeType": "decrease" + } + ], + "production_charts": [ + { + "date": "2025-12-01T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 88 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 92 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 90 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 85 + } + ] + }, + { + "date": "2025-12-03T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 85 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 95 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 93 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 87 + } + ] + }, + { + "date": "2025-12-05T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 82 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 98 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 91 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 84 + } + ] + }, + { + "date": "2025-12-07T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 80 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 89 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 88 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 82 + } + ] + }, + { + "date": "2025-12-08T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 83 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 92 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 95 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 85 + } + ] + }, + { + "date": "2025-12-11T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 81 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 88 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 92 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 83 + } + ] + }, + { + "date": "2025-12-13T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 84 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 90 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 89 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 86 + } + ] + }, + { + "date": "2025-12-15T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 82 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 94 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 96 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 84 + } + ] + }, + { + "date": "2025-12-17T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 80 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 91 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 93 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 82 + } + ] + }, + { + "date": "2025-12-19T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 79 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 88 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 90 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 81 + } + ] + }, + { + "date": "2025-12-21T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 81 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 97 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 92 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 83 + } + ] + }, + { + "date": "2025-12-23T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 83 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 95 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 98 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 85 + } + ] + }, + { + "date": "2025-12-25T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 80 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 89 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 94 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 82 + } + ] + }, + { + "date": "2025-12-27T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 82 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 93 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 96 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 84 + } + ] + }, + { + "date": "2025-12-28T00:00:00Z", + "flocks": [ + { + "id": 1, + "name": "Flock A-002", + "data": 85 + }, + { + "id": 2, + "name": "Flock A-001", + "data": 96 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 95 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 87 + } + ] + } + ], + "standard_productions": [ + { + "week": 18, + "standards": [ + { + "name": "hen_day", + "value": 40 + }, + { + "name": "hen_house", + "value": 38 + }, + { + "name": "uniformity", + "value": 85 + }, + { + "name": "egg_weight", + "value": 52 + }, + { + "name": "egg_mass", + "value": 20 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 38 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 37 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 39 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 36 + } + ] + }, + { + "week": 20, + "standards": [ + { + "name": "hen_day", + "value": 45 + }, + { + "name": "hen_house", + "value": 43 + }, + { + "name": "uniformity", + "value": 86 + }, + { + "name": "egg_weight", + "value": 54 + }, + { + "name": "egg_mass", + "value": 24 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 43 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 42 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 44 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 41 + } + ] + }, + { + "week": 22, + "standards": [ + { + "name": "hen_day", + "value": 48 + }, + { + "name": "hen_house", + "value": 46 + }, + { + "name": "uniformity", + "value": 87 + }, + { + "name": "egg_weight", + "value": 55 + }, + { + "name": "egg_mass", + "value": 26 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 47 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 46 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 48 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 45 + } + ] + }, + { + "week": 24, + "standards": [ + { + "name": "hen_day", + "value": 50 + }, + { + "name": "hen_house", + "value": 48 + }, + { + "name": "uniformity", + "value": 88 + }, + { + "name": "egg_weight", + "value": 56 + }, + { + "name": "egg_mass", + "value": 28 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 49 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 48 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 50 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 47 + } + ] + }, + { + "week": 26, + "standards": [ + { + "name": "hen_day", + "value": 52 + }, + { + "name": "hen_house", + "value": 50 + }, + { + "name": "uniformity", + "value": 89 + }, + { + "name": "egg_weight", + "value": 57 + }, + { + "name": "egg_mass", + "value": 30 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 50 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 49 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 51 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 48 + } + ] + }, + { + "week": 28, + "standards": [ + { + "name": "hen_day", + "value": 55 + }, + { + "name": "hen_house", + "value": 53 + }, + { + "name": "uniformity", + "value": 90 + }, + { + "name": "egg_weight", + "value": 58 + }, + { + "name": "egg_mass", + "value": 32 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 53 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 52 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 54 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 51 + } + ] + }, + { + "week": 30, + "standards": [ + { + "name": "hen_day", + "value": 58 + }, + { + "name": "hen_house", + "value": 56 + }, + { + "name": "uniformity", + "value": 91 + }, + { + "name": "egg_weight", + "value": 59 + }, + { + "name": "egg_mass", + "value": 34 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 55 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 54 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 56 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 53 + } + ] + }, + { + "week": 32, + "standards": [ + { + "name": "hen_day", + "value": 60 + }, + { + "name": "hen_house", + "value": 58 + }, + { + "name": "uniformity", + "value": 92 + }, + { + "name": "egg_weight", + "value": 60 + }, + { + "name": "egg_mass", + "value": 36 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 58 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 57 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 59 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 56 + } + ] + }, + { + "week": 34, + "standards": [ + { + "name": "hen_day", + "value": 62 + }, + { + "name": "hen_house", + "value": 60 + }, + { + "name": "uniformity", + "value": 92 + }, + { + "name": "egg_weight", + "value": 61 + }, + { + "name": "egg_mass", + "value": 38 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 60 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 59 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 61 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 58 + } + ] + }, + { + "week": 36, + "standards": [ + { + "name": "hen_day", + "value": 64 + }, + { + "name": "hen_house", + "value": 62 + }, + { + "name": "uniformity", + "value": 93 + }, + { + "name": "egg_weight", + "value": 62 + }, + { + "name": "egg_mass", + "value": 40 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 62 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 61 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 63 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 60 + } + ] + }, + { + "week": 38, + "standards": [ + { + "name": "hen_day", + "value": 66 + }, + { + "name": "hen_house", + "value": 64 + }, + { + "name": "uniformity", + "value": 93 + }, + { + "name": "egg_weight", + "value": 63 + }, + { + "name": "egg_mass", + "value": 42 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 64 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 63 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 65 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 62 + } + ] + }, + { + "week": 40, + "standards": [ + { + "name": "hen_day", + "value": 68 + }, + { + "name": "hen_house", + "value": 66 + }, + { + "name": "uniformity", + "value": 94 + }, + { + "name": "egg_weight", + "value": 64 + }, + { + "name": "egg_mass", + "value": 44 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 66 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 65 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 67 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 64 + } + ] + }, + { + "week": 42, + "standards": [ + { + "name": "hen_day", + "value": 70 + }, + { + "name": "hen_house", + "value": 68 + }, + { + "name": "uniformity", + "value": 94 + }, + { + "name": "egg_weight", + "value": 65 + }, + { + "name": "egg_mass", + "value": 46 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 68 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 67 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 69 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 66 + } + ] + }, + { + "week": 44, + "standards": [ + { + "name": "hen_day", + "value": 72 + }, + { + "name": "hen_house", + "value": 70 + }, + { + "name": "uniformity", + "value": 95 + }, + { + "name": "egg_weight", + "value": 66 + }, + { + "name": "egg_mass", + "value": 48 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 70 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 69 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 71 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 68 + } + ] + }, + { + "week": 46, + "standards": [ + { + "name": "hen_day", + "value": 74 + }, + { + "name": "hen_house", + "value": 72 + }, + { + "name": "uniformity", + "value": 95 + }, + { + "name": "egg_weight", + "value": 67 + }, + { + "name": "egg_mass", + "value": 50 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 72 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 71 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 73 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 70 + } + ] + }, + { + "week": 48, + "standards": [ + { + "name": "hen_day", + "value": 76 + }, + { + "name": "hen_house", + "value": 74 + }, + { + "name": "uniformity", + "value": 95 + }, + { + "name": "egg_weight", + "value": 68 + }, + { + "name": "egg_mass", + "value": 52 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 74 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 73 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 75 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 72 + } + ] + }, + { + "week": 50, + "standards": [ + { + "name": "hen_day", + "value": 78 + }, + { + "name": "hen_house", + "value": 76 + }, + { + "name": "uniformity", + "value": 96 + }, + { + "name": "egg_weight", + "value": 69 + }, + { + "name": "egg_mass", + "value": 54 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 76 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 75 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 77 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 74 + } + ] + }, + { + "week": 52, + "standards": [ + { + "name": "hen_day", + "value": 80 + }, + { + "name": "hen_house", + "value": 78 + }, + { + "name": "uniformity", + "value": 96 + }, + { + "name": "egg_weight", + "value": 70 + }, + { + "name": "egg_mass", + "value": 56 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 78 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 77 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 79 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 76 + } + ] + }, + { + "week": 54, + "standards": [ + { + "name": "hen_day", + "value": 82 + }, + { + "name": "hen_house", + "value": 80 + }, + { + "name": "uniformity", + "value": 96 + }, + { + "name": "egg_weight", + "value": 71 + }, + { + "name": "egg_mass", + "value": 58 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 80 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 79 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 81 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 78 + } + ] + }, + { + "week": 56, + "standards": [ + { + "name": "hen_day", + "value": 84 + }, + { + "name": "hen_house", + "value": 82 + }, + { + "name": "uniformity", + "value": 97 + }, + { + "name": "egg_weight", + "value": 72 + }, + { + "name": "egg_mass", + "value": 60 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 82 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 81 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 83 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 80 + } + ] + }, + { + "week": 58, + "standards": [ + { + "name": "hen_day", + "value": 86 + }, + { + "name": "hen_house", + "value": 84 + }, + { + "name": "uniformity", + "value": 97 + }, + { + "name": "egg_weight", + "value": 73 + }, + { + "name": "egg_mass", + "value": 62 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 84 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 83 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 85 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 82 + } + ] + }, + { + "week": 60, + "standards": [ + { + "name": "hen_day", + "value": 88 + }, + { + "name": "hen_house", + "value": 86 + }, + { + "name": "uniformity", + "value": 97 + }, + { + "name": "egg_weight", + "value": 74 + }, + { + "name": "egg_mass", + "value": 64 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 86 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 85 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 87 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 84 + } + ] + }, + { + "week": 62, + "standards": [ + { + "name": "hen_day", + "value": 90 + }, + { + "name": "hen_house", + "value": 88 + }, + { + "name": "uniformity", + "value": 98 + }, + { + "name": "egg_weight", + "value": 75 + }, + { + "name": "egg_mass", + "value": 66 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 88 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 87 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 89 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 86 + } + ] + }, + { + "week": 64, + "standards": [ + { + "name": "hen_day", + "value": 92 + }, + { + "name": "hen_house", + "value": 90 + }, + { + "name": "uniformity", + "value": 98 + }, + { + "name": "egg_weight", + "value": 76 + }, + { + "name": "egg_mass", + "value": 68 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 90 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 89 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 91 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 88 + } + ] + }, + { + "week": 66, + "standards": [ + { + "name": "hen_day", + "value": 94 + }, + { + "name": "hen_house", + "value": 92 + }, + { + "name": "uniformity", + "value": 98 + }, + { + "name": "egg_weight", + "value": 77 + }, + { + "name": "egg_mass", + "value": 70 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 92 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 91 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 93 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 90 + } + ] + }, + { + "week": 68, + "standards": [ + { + "name": "hen_day", + "value": 95 + }, + { + "name": "hen_house", + "value": 93 + }, + { + "name": "uniformity", + "value": 98 + }, + { + "name": "egg_weight", + "value": 78 + }, + { + "name": "egg_mass", + "value": 72 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 93 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 92 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 94 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 91 + } + ] + }, + { + "week": 70, + "standards": [ + { + "name": "hen_day", + "value": 96 + }, + { + "name": "hen_house", + "value": 94 + }, + { + "name": "uniformity", + "value": 99 + }, + { + "name": "egg_weight", + "value": 79 + }, + { + "name": "egg_mass", + "value": 74 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 94 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 93 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 95 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 92 + } + ] + }, + { + "week": 72, + "standards": [ + { + "name": "hen_day", + "value": 97 + }, + { + "name": "hen_house", + "value": 95 + }, + { + "name": "uniformity", + "value": 99 + }, + { + "name": "egg_weight", + "value": 80 + }, + { + "name": "egg_mass", + "value": 76 + } + ], + "flocks": [ + { + "id": 1, + "name": "Flock A-001", + "data": 95 + }, + { + "id": 2, + "name": "Flock A-002", + "data": 94 + }, + { + "id": 3, + "name": "Flock B-001", + "data": 96 + }, + { + "id": 4, + "name": "Flock B-002", + "data": 93 + } + ] + } + ], + "egg_weights": [ + { + "flock": { + "id": 1, + "name": "Flock A-001" + }, + "weight": 62 + }, + { + "flock": { + "id": 2, + "name": "Flock A-002" + }, + "weight": 61 + }, + { + "flock": { + "id": 3, + "name": "Flock B-001" + }, + "weight": 63 + }, + { + "flock": { + "id": 4, + "name": "Flock B-002" + }, + "weight": 60 + }, + { + "flock": { + "id": 5, + "name": "Flock C-001" + }, + "weight": 62 + } + ], + "fcr_data": [ + { + "flock": { + "id": 1, + "name": "Flock A-001" + }, + "fcr": 2.1 + }, + { + "flock": { + "id": 2, + "name": "Flock A-002" + }, + "fcr": 2.3 + }, + { + "flock": { + "id": 3, + "name": "Flock B-001" + }, + "fcr": 2 + }, + { + "flock": { + "id": 4, + "name": "Flock B-002" + }, + "fcr": 2.4 + }, + { + "flock": { + "id": 5, + "name": "Flock C-001" + }, + "fcr": 2.2 + } + ] +} \ No newline at end of file diff --git a/src/dummy/dashboard/dashboard.production.dummy.ts b/src/dummy/dashboard/dashboard.production.dummy.ts new file mode 100644 index 00000000..b1e2911b --- /dev/null +++ b/src/dummy/dashboard/dashboard.production.dummy.ts @@ -0,0 +1,27 @@ +/** + * Dummy data for DashboardProduction + * Generated from: dashboard.production.dummy.json + * + * This file is auto-generated. Do not edit manually. + */ + +import { DashboardProductionStatisticsData, DashboardProductionProductionChartsFlocks, DashboardProductionProductionCharts, DashboardProductionStandardProductionsStandards, DashboardProductionStandardProductions, DashboardProductionFcrDataFlock, DashboardProductionEggWeights, DashboardProductionFcrData, DashboardProduction } from '../../types/api/dashboard/dashboard-production'; +import { BaseApiResponse } from '@/types/api/api-general'; +import dummyData from './dashboard.production.dummy.json'; + +/** + * Get dummy DashboardProduction data + * @returns Promise with BaseApiResponse containing DashboardProduction + */ +export async function getDummySingle(): Promise> { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + code: 200, + status: 'success', + message: 'Data retrieved successfully', + data: dummyData as unknown as DashboardProduction, + }); + }, 500); + }); +} diff --git a/src/services/api/dashboard.ts b/src/services/api/dashboard.ts new file mode 100644 index 00000000..d45ebbde --- /dev/null +++ b/src/services/api/dashboard.ts @@ -0,0 +1,34 @@ +import { BaseApiService } from '@/services/api/base'; +import { BaseApiResponse } from '@/types/api/api-general'; +import { DashboardProduction } from '@/types/api/dashboard/dashboard-production'; +import { getDummySingle } from '@/dummy/dashboard/dashboard.production.dummy'; + +class DashboardService extends BaseApiService< + DashboardProduction, + unknown, + unknown +> { + constructor(basePath: string) { + super(basePath); + } + + /** + * Fetch dashboard production data + * @param endpoint - The endpoint URL with query parameters + * @returns Promise with BaseApiResponse containing DashboardProduction + * + * Note: Currently using dummy data. When real API is ready, + * uncomment the line below and remove getDummySingle() call: + * return await this.customRequest>(endpoint); + */ + async getDashboardProductionFetcher( + endpoint: string + ): Promise> { + // For now, we're using dummy data regardless of the endpoint + // The endpoint parameter is kept for future API integration + console.log('Fetching dashboard data with endpoint:', endpoint); + return await getDummySingle(); + } +} + +export const DashboardApi = new DashboardService('/dashboard'); diff --git a/src/types/api/dashboard/dashboard-production.d.ts b/src/types/api/dashboard/dashboard-production.d.ts new file mode 100644 index 00000000..05acddd3 --- /dev/null +++ b/src/types/api/dashboard/dashboard-production.d.ts @@ -0,0 +1,52 @@ +export interface DashboardProduction { + statistics_data: DashboardProductionStatisticsData[]; + production_charts: DashboardProductionProductionCharts[]; + standard_productions: DashboardProductionStandardProductions[]; + egg_weights: DashboardProductionEggWeights[]; + fcr_data: DashboardProductionFcrData[]; +} + +export interface DashboardProductionFcrData { + flock: DashboardProductionFcrDataFlock; + fcr: number; +} + +export interface DashboardProductionEggWeights { + flock: DashboardProductionFcrDataFlock; + weight: number; +} + +export interface DashboardProductionStandardProductions { + week: number; + standards: DashboardProductionStandardProductionsStandards[]; + flocks: DashboardProductionProductionChartsFlocks[]; +} + +export interface DashboardProductionProductionCharts { + date: string; + flocks: DashboardProductionProductionChartsFlocks[]; +} + +export interface DashboardProductionStatisticsData { + title: string; + value: number; + change: number; + period: string; + changeType: string; +} + +export interface DashboardProductionFcrDataFlock { + id: number; + name: string; +} + +export interface DashboardProductionStandardProductionsStandards { + name: string; + value: number; +} + +export interface DashboardProductionProductionChartsFlocks { + id: number; + name: string; + data: number; +} \ No newline at end of file