chore: update Stripe dependencies and remove unused chart components
- Updated @stripe/react-stripe-js from ^5.4.1 to ^5.6.0 - Updated @stripe/stripe-js from ^8.6.1 to ^8.8.0 - Updated stripe from ^20.2.0 to ^20.4.0 - Removed dynamic imports for TimeserieBarChart and TimeserieBarChartStacked in AdminDashboard - Deleted TimeserieBarChart and TimeserieBarChartStacked components - Deleted Chart component and related utilities
This commit is contained in:
parent
e415f46104
commit
068f4b0c01
6 changed files with 23 additions and 1039 deletions
330
apps/infoalloggi/package-lock.json
generated
330
apps/infoalloggi/package-lock.json
generated
|
|
@ -22,8 +22,8 @@
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@react-email/components": "^1.0.8",
|
"@react-email/components": "^1.0.8",
|
||||||
"@react-email/render": "^2.0.4",
|
"@react-email/render": "^2.0.4",
|
||||||
"@stripe/react-stripe-js": "^5.4.1",
|
"@stripe/react-stripe-js": "^5.6.0",
|
||||||
"@stripe/stripe-js": "^8.6.1",
|
"@stripe/stripe-js": "^8.8.0",
|
||||||
"@t3-oss/env-nextjs": "^0.13.10",
|
"@t3-oss/env-nextjs": "^0.13.10",
|
||||||
"@tailwindcss/forms": "^0.5.11",
|
"@tailwindcss/forms": "^0.5.11",
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
|
|
@ -82,9 +82,8 @@
|
||||||
"react-select": "^5.10.2",
|
"react-select": "^5.10.2",
|
||||||
"react-to-print": "^3.2.0",
|
"react-to-print": "^3.2.0",
|
||||||
"react-use": "^17.6.0",
|
"react-use": "^17.6.0",
|
||||||
"recharts": "^2.15.4",
|
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"stripe": "^20.2.0",
|
"stripe": "^20.4.0",
|
||||||
"superjson": "^2.2.6",
|
"superjson": "^2.2.6",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.2",
|
||||||
|
|
@ -6221,9 +6220,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@stripe/react-stripe-js": {
|
"node_modules/@stripe/react-stripe-js": {
|
||||||
"version": "5.4.1",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-5.6.0.tgz",
|
||||||
"integrity": "sha512-ipeYcAHa4EPmjwfv0lFE+YDVkOQ0TMKkFWamW+BqmnSkEln/hO8rmxGPPWcd9WjqABx6Ro8Xg4pAS7evCcR9cw==",
|
"integrity": "sha512-tucu/vTGc+5NXbo2pUiaVjA4ENdRBET8qGS00BM4BAU8J4Pi3eY6BHollsP2+VSuzzlvXwMg0it3ZLhbCj2fPg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prop-types": "^15.7.2"
|
"prop-types": "^15.7.2"
|
||||||
|
|
@ -6235,9 +6234,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@stripe/stripe-js": {
|
"node_modules/@stripe/stripe-js": {
|
||||||
"version": "8.6.1",
|
"version": "8.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-8.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-8.8.0.tgz",
|
||||||
"integrity": "sha512-UJ05U2062XDgydbUcETH1AoRQLNhigQ2KmDn1BG8sC3xfzu6JKg95Qt6YozdzFpxl1Npii/02m2LEWFt1RYjVA==",
|
"integrity": "sha512-NNYuyW8qmLjyHnpyFgs/23wUrjB8k0xN9YIZFOMLewCa/pIkIji9e9aY/EgdNryEDDRptc6TcPIHRvG1R0ClFw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -7217,69 +7216,6 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz",
|
|
||||||
"integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==",
|
|
||||||
"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/geojson": {
|
"node_modules/@types/geojson": {
|
||||||
"version": "7946.0.16",
|
"version": "7946.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
||||||
|
|
@ -7906,6 +7842,7 @@
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.2",
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
|
@ -8412,127 +8349,6 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"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.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-ryitBnaRbXQtgZ/gU50GSn6jQRwinSCQclpakXymvLd8ytTgE5bmSfgYcUxD7XYL34qHhFDyVk71qqKsfSyvmA==",
|
|
||||||
"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/data-uri-to-buffer": {
|
"node_modules/data-uri-to-buffer": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
|
||||||
|
|
@ -8656,12 +8472,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": {
|
"node_modules/deep-is": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||||
|
|
@ -9286,12 +9096,6 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eventemitter3": {
|
|
||||||
"version": "4.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
|
||||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/events-universal": {
|
"node_modules/events-universal": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
||||||
|
|
@ -10209,15 +10013,6 @@
|
||||||
"node": ">= 0.4"
|
"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/interpret": {
|
"node_modules/interpret": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
||||||
|
|
@ -11360,6 +11155,7 @@
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash.defaults": {
|
"node_modules/lodash.defaults": {
|
||||||
|
|
@ -12229,6 +12025,7 @@
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -13136,21 +12933,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
|
||||||
"version": "6.14.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
|
||||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
|
@ -13803,21 +13585,6 @@
|
||||||
"react-dom": "^16.8.0 || ^17 || ^18 || ^19"
|
"react-dom": "^16.8.0 || ^17 || ^18 || ^19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-smooth": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fast-equals": "^5.0.1",
|
|
||||||
"prop-types": "^15.8.1",
|
|
||||||
"react-transition-group": "^4.4.5"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-style-singleton": {
|
"node_modules/react-style-singleton": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
|
|
@ -13953,44 +13720,6 @@
|
||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/recharts": {
|
|
||||||
"version": "2.15.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
|
|
||||||
"integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"clsx": "^2.0.0",
|
|
||||||
"eventemitter3": "^4.0.1",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"react-is": "^18.3.1",
|
|
||||||
"react-smooth": "^4.0.4",
|
|
||||||
"recharts-scale": "^0.4.4",
|
|
||||||
"tiny-invariant": "^1.3.1",
|
|
||||||
"victory-vendor": "^36.6.8"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
||||||
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/recharts-scale": {
|
|
||||||
"version": "0.4.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
|
|
||||||
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"decimal.js-light": "^2.4.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/recharts/node_modules/react-is": {
|
|
||||||
"version": "18.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
|
||||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/rechoir": {
|
"node_modules/rechoir": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
|
||||||
|
|
@ -14463,6 +14192,7 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
@ -14482,6 +14212,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
@ -14498,6 +14229,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bound": "^1.0.2",
|
"call-bound": "^1.0.2",
|
||||||
|
|
@ -14516,6 +14248,7 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bound": "^1.0.2",
|
"call-bound": "^1.0.2",
|
||||||
|
|
@ -14961,13 +14694,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stripe": {
|
"node_modules/stripe": {
|
||||||
"version": "20.2.0",
|
"version": "20.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-20.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-20.4.0.tgz",
|
||||||
"integrity": "sha512-m8niTfdm3nPP/yQswRWMwQxqEUcTtB3RTJQ9oo6NINDzgi7aPOadsH/fPXIIfL1Sc5+lqQFKSk7WiO6CXmvaeA==",
|
"integrity": "sha512-F/aN1IQ9vHmlyLNi3DkiIbyzQb6gyBG0uYFd/VrEVQSc9BLtlgknPUx0EvzZdBMRLFuRaPFIFd7Mxwtg7Pbwzw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
|
||||||
"qs": "^6.14.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
},
|
},
|
||||||
|
|
@ -15604,28 +15334,6 @@
|
||||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc"
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/victory-vendor": {
|
|
||||||
"version": "36.9.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
|
||||||
"integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==",
|
|
||||||
"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/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@react-email/components": "^1.0.8",
|
"@react-email/components": "^1.0.8",
|
||||||
"@react-email/render": "^2.0.4",
|
"@react-email/render": "^2.0.4",
|
||||||
"@stripe/react-stripe-js": "^5.4.1",
|
"@stripe/react-stripe-js": "^5.6.0",
|
||||||
"@stripe/stripe-js": "^8.6.1",
|
"@stripe/stripe-js": "^8.8.0",
|
||||||
"@t3-oss/env-nextjs": "^0.13.10",
|
"@t3-oss/env-nextjs": "^0.13.10",
|
||||||
"@tailwindcss/forms": "^0.5.11",
|
"@tailwindcss/forms": "^0.5.11",
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
|
|
@ -94,9 +94,8 @@
|
||||||
"react-select": "^5.10.2",
|
"react-select": "^5.10.2",
|
||||||
"react-to-print": "^3.2.0",
|
"react-to-print": "^3.2.0",
|
||||||
"react-use": "^17.6.0",
|
"react-use": "^17.6.0",
|
||||||
"recharts": "^2.15.4",
|
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"stripe": "^20.2.0",
|
"stripe": "^20.4.0",
|
||||||
"superjson": "^2.2.6",
|
"superjson": "^2.2.6",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.2",
|
||||||
|
|
@ -133,4 +132,4 @@
|
||||||
"ct3aMetadata": {
|
"ct3aMetadata": {
|
||||||
"initVersion": "7.9.0"
|
"initVersion": "7.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { CircleHelp } from "lucide-react";
|
import { CircleHelp } from "lucide-react";
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
import { AccordionComp } from "~/components/accordionComp";
|
import { AccordionComp } from "~/components/accordionComp";
|
||||||
import { LoadingPage } from "~/components/loading";
|
import { LoadingPage } from "~/components/loading";
|
||||||
import {
|
import {
|
||||||
|
|
@ -24,23 +23,6 @@ import {
|
||||||
import { ServizioList } from "../servizio/servizio";
|
import { ServizioList } from "../servizio/servizio";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
const TimeserieBarChart = dynamic(
|
|
||||||
() => import("~/components/timeserieBarChart").then((mod) => mod.default),
|
|
||||||
{
|
|
||||||
ssr: false,
|
|
||||||
loading: () => <div className="h-117 animate-pulse bg-gray-100" />,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const TimeserieBarChartStacked = dynamic(
|
|
||||||
() =>
|
|
||||||
import("~/components/timeserieBarChartStacked").then((mod) => mod.default),
|
|
||||||
{
|
|
||||||
ssr: false,
|
|
||||||
loading: () => <div className="h-117 animate-pulse bg-gray-100" />,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const AdminDashboard = () => {
|
export const AdminDashboard = () => {
|
||||||
const { data: stats, isLoading } = api.stats.adminDashStats.useQuery();
|
const { data: stats, isLoading } = api.stats.adminDashStats.useQuery();
|
||||||
|
|
||||||
|
|
@ -69,22 +51,6 @@ export const AdminDashboard = () => {
|
||||||
{stats.userCount}
|
{stats.userCount}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<TimeserieBarChart
|
|
||||||
timeserie={stats.userTimeserie}
|
|
||||||
title="Utenti registrati"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TimeserieBarChartStacked
|
|
||||||
timeserie={stats.serviziTimeserie.data}
|
|
||||||
title="Servizi creati"
|
|
||||||
valueALabel={stats.serviziTimeserie.valueALabel}
|
|
||||||
valueBLabel={stats.serviziTimeserie.valueBLabel}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TimeserieBarChart
|
|
||||||
timeserie={stats.contattiTimeserie}
|
|
||||||
title="Contatti generati"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
"use client";
|
|
||||||
import { enUS, it } from "date-fns/locale";
|
|
||||||
import { CalendarIcon } from "lucide-react";
|
|
||||||
import * as React from "react";
|
|
||||||
import type { DateRange } from "react-day-picker";
|
|
||||||
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
|
|
||||||
import { Button } from "~/components/ui/button";
|
|
||||||
import { Calendar } from "~/components/ui/calendar";
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardAction,
|
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
|
||||||
CardFooter,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
} from "~/components/ui/card";
|
|
||||||
import {
|
|
||||||
type ChartConfig,
|
|
||||||
ChartContainer,
|
|
||||||
ChartTooltip,
|
|
||||||
ChartTooltipContent,
|
|
||||||
} from "~/components/ui/chart";
|
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from "~/components/ui/popover";
|
|
||||||
import { cn } from "~/lib/utils";
|
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
|
||||||
|
|
||||||
const chartConfig = {
|
|
||||||
value: {
|
|
||||||
color: "var(--chart-2)",
|
|
||||||
label: "Valore",
|
|
||||||
},
|
|
||||||
} satisfies ChartConfig;
|
|
||||||
|
|
||||||
type TimeserieBarChartProps = {
|
|
||||||
title: string;
|
|
||||||
description?: string;
|
|
||||||
timeserie: { date: Date; value: number }[];
|
|
||||||
};
|
|
||||||
export default function TimeserieBarChart({
|
|
||||||
timeserie,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
}: TimeserieBarChartProps) {
|
|
||||||
const { locale } = useTranslation();
|
|
||||||
|
|
||||||
const startDate = timeserie[0]
|
|
||||||
? new Date(timeserie[0].date)
|
|
||||||
: new Date(2025, 1, 1);
|
|
||||||
const endDate = timeserie[timeserie.length - 1]
|
|
||||||
? // biome-ignore lint/style/noNonNullAssertion: <exists>
|
|
||||||
new Date(timeserie[timeserie.length - 1]!.date)
|
|
||||||
: new Date();
|
|
||||||
|
|
||||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
|
||||||
from: startDate,
|
|
||||||
to: endDate,
|
|
||||||
});
|
|
||||||
const filteredData = React.useMemo(() => {
|
|
||||||
if (!range?.from && !range?.to) {
|
|
||||||
return timeserie;
|
|
||||||
}
|
|
||||||
|
|
||||||
return timeserie.filter((item) => {
|
|
||||||
// biome-ignore lint/style/noNonNullAssertion: <exists>
|
|
||||||
return item.date >= range.from! && item.date <= range.to!;
|
|
||||||
});
|
|
||||||
}, [range]);
|
|
||||||
|
|
||||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className="@container/card w-full pb-4">
|
|
||||||
<CardHeader className="flex @md/card:grid flex-col border-b">
|
|
||||||
<CardTitle>{title}</CardTitle>
|
|
||||||
<CardDescription className={cn(!description && "sr-only")}>
|
|
||||||
{description || "Analytics for the selected period."}
|
|
||||||
</CardDescription>
|
|
||||||
<CardAction className="@md/card:mt-0 mt-2">
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button variant="outline">
|
|
||||||
<CalendarIcon />
|
|
||||||
{range?.from && range?.to
|
|
||||||
? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`
|
|
||||||
: "Seleziona un intervallo di date"}
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent align="end" className="w-auto overflow-hidden p-0">
|
|
||||||
<Calendar
|
|
||||||
className="w-full"
|
|
||||||
defaultMonth={range?.from}
|
|
||||||
fixedWeeks
|
|
||||||
locale={DatePickerLocale}
|
|
||||||
mode="range"
|
|
||||||
onSelect={setRange}
|
|
||||||
selected={range}
|
|
||||||
showOutsideDays
|
|
||||||
/>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
</CardAction>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="px-4">
|
|
||||||
<ChartContainer
|
|
||||||
className="aspect-auto h-62.5 w-full"
|
|
||||||
config={chartConfig}
|
|
||||||
>
|
|
||||||
{filteredData.length === 0 ? (
|
|
||||||
<div className="flex h-full items-center justify-center text-base text-muted-foreground">
|
|
||||||
Nessun dato disponibile per il periodo selezionato.
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<BarChart
|
|
||||||
accessibilityLayer
|
|
||||||
data={filteredData}
|
|
||||||
margin={{
|
|
||||||
left: 12,
|
|
||||||
right: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CartesianGrid vertical={false} />
|
|
||||||
<XAxis
|
|
||||||
axisLine={false}
|
|
||||||
dataKey="date"
|
|
||||||
minTickGap={20}
|
|
||||||
tickFormatter={(value) => {
|
|
||||||
const date = new Date(String(value));
|
|
||||||
return date.toLocaleDateString("it-IT", {
|
|
||||||
day: "numeric",
|
|
||||||
month: "short",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
tickLine={false}
|
|
||||||
tickMargin={8}
|
|
||||||
/>
|
|
||||||
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
|
|
||||||
<Bar dataKey="value" fill={`var(--color-value)`} radius={4} />
|
|
||||||
</BarChart>
|
|
||||||
)}
|
|
||||||
</ChartContainer>
|
|
||||||
</CardContent>
|
|
||||||
<CardFooter className="flex justify-end border-t pt-4!">
|
|
||||||
<span className="text-muted-foreground text-sm">
|
|
||||||
Totale:{" "}
|
|
||||||
<strong>
|
|
||||||
{filteredData.reduce((acc, item) => acc + item.value, 0)}
|
|
||||||
</strong>
|
|
||||||
</span>
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
"use client";
|
|
||||||
import { enUS, it } from "date-fns/locale";
|
|
||||||
import { CalendarIcon } from "lucide-react";
|
|
||||||
import * as React from "react";
|
|
||||||
import type { DateRange } from "react-day-picker";
|
|
||||||
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
|
|
||||||
import { Button } from "~/components/ui/button";
|
|
||||||
import { Calendar } from "~/components/ui/calendar";
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardAction,
|
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
|
||||||
CardFooter,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
} from "~/components/ui/card";
|
|
||||||
import {
|
|
||||||
type ChartConfig,
|
|
||||||
ChartContainer,
|
|
||||||
ChartTooltip,
|
|
||||||
ChartTooltipContent,
|
|
||||||
} from "~/components/ui/chart";
|
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from "~/components/ui/popover";
|
|
||||||
import { cn } from "~/lib/utils";
|
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
|
||||||
|
|
||||||
const chartConfig = {
|
|
||||||
valueA: {
|
|
||||||
color: "var(--chart-2)",
|
|
||||||
label: "valueA",
|
|
||||||
},
|
|
||||||
valueB: {
|
|
||||||
color: "var(--chart-3)",
|
|
||||||
label: "valueB",
|
|
||||||
},
|
|
||||||
} satisfies ChartConfig;
|
|
||||||
|
|
||||||
export type StackedTimeserie = { date: Date; valueA: number; valueB: number };
|
|
||||||
|
|
||||||
type AnalyticsChartProps = {
|
|
||||||
title: string;
|
|
||||||
description?: string;
|
|
||||||
valueALabel: string;
|
|
||||||
valueBLabel: string;
|
|
||||||
timeserie: StackedTimeserie[];
|
|
||||||
};
|
|
||||||
export default function TimeserieBarChartStacked({
|
|
||||||
timeserie,
|
|
||||||
title,
|
|
||||||
valueALabel,
|
|
||||||
valueBLabel,
|
|
||||||
description,
|
|
||||||
}: AnalyticsChartProps) {
|
|
||||||
const { locale } = useTranslation();
|
|
||||||
|
|
||||||
const configs = chartConfig;
|
|
||||||
configs.valueA.label = valueALabel;
|
|
||||||
configs.valueB.label = valueBLabel;
|
|
||||||
|
|
||||||
const startDate = timeserie[0]
|
|
||||||
? new Date(timeserie[0].date)
|
|
||||||
: new Date(2025, 1, 1);
|
|
||||||
const endDate = timeserie[timeserie.length - 1]
|
|
||||||
? // biome-ignore lint/style/noNonNullAssertion: <exists>
|
|
||||||
new Date(timeserie[timeserie.length - 1]!.date)
|
|
||||||
: new Date();
|
|
||||||
|
|
||||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
|
||||||
from: startDate,
|
|
||||||
to: endDate,
|
|
||||||
});
|
|
||||||
const filteredData = React.useMemo(() => {
|
|
||||||
if (!range?.from && !range?.to) {
|
|
||||||
return timeserie;
|
|
||||||
}
|
|
||||||
|
|
||||||
return timeserie.filter((item) => {
|
|
||||||
// biome-ignore lint/style/noNonNullAssertion: <exists>
|
|
||||||
return item.date >= range.from! && item.date <= range.to!;
|
|
||||||
});
|
|
||||||
}, [range]);
|
|
||||||
|
|
||||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className="@container/card w-full pb-4">
|
|
||||||
<CardHeader className="flex @md/card:grid flex-col border-b">
|
|
||||||
<CardTitle>{title}</CardTitle>
|
|
||||||
<CardDescription className={cn(!description && "sr-only")}>
|
|
||||||
{description || "Analytics for the selected period."}
|
|
||||||
</CardDescription>
|
|
||||||
<CardAction className="@md/card:mt-0 mt-2">
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button variant="outline">
|
|
||||||
<CalendarIcon />
|
|
||||||
{range?.from && range?.to
|
|
||||||
? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`
|
|
||||||
: "Seleziona un intervallo di date"}
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent align="end" className="w-auto overflow-hidden p-0">
|
|
||||||
<Calendar
|
|
||||||
className="w-full"
|
|
||||||
defaultMonth={range?.from}
|
|
||||||
fixedWeeks
|
|
||||||
locale={DatePickerLocale}
|
|
||||||
mode="range"
|
|
||||||
onSelect={setRange}
|
|
||||||
selected={range}
|
|
||||||
showOutsideDays
|
|
||||||
/>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
</CardAction>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="px-4">
|
|
||||||
<ChartContainer
|
|
||||||
className="aspect-auto h-62.5 w-full"
|
|
||||||
config={chartConfig}
|
|
||||||
>
|
|
||||||
{filteredData.length === 0 ? (
|
|
||||||
<div className="flex h-full items-center justify-center text-base text-muted-foreground">
|
|
||||||
Nessun dato disponibile per il periodo selezionato.
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<BarChart
|
|
||||||
accessibilityLayer
|
|
||||||
data={filteredData}
|
|
||||||
margin={{
|
|
||||||
left: 12,
|
|
||||||
right: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CartesianGrid vertical={false} />
|
|
||||||
<XAxis
|
|
||||||
axisLine={false}
|
|
||||||
dataKey="date"
|
|
||||||
minTickGap={20}
|
|
||||||
tickFormatter={(value) => {
|
|
||||||
const date = new Date(String(value));
|
|
||||||
return date.toLocaleDateString("it-IT", {
|
|
||||||
day: "numeric",
|
|
||||||
month: "short",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
tickLine={false}
|
|
||||||
tickMargin={8}
|
|
||||||
/>
|
|
||||||
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
|
|
||||||
<Bar
|
|
||||||
dataKey="valueA"
|
|
||||||
fill={`var(--color-valueA)`}
|
|
||||||
radius={[0, 0, 4, 4]}
|
|
||||||
stackId="a"
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="valueB"
|
|
||||||
fill={`var(--color-valueB)`}
|
|
||||||
radius={[4, 4, 0, 0]}
|
|
||||||
stackId="a"
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
)}
|
|
||||||
</ChartContainer>
|
|
||||||
</CardContent>
|
|
||||||
<CardFooter className="flex justify-end border-t pt-4!">
|
|
||||||
<span className="text-muted-foreground text-sm">
|
|
||||||
Totale: <strong>{filteredData.reduce((acc) => acc + 1, 0)}</strong>
|
|
||||||
</span>
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,353 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import * as RechartsPrimitive from "recharts";
|
|
||||||
|
|
||||||
import { cn } from "~/lib/utils";
|
|
||||||
|
|
||||||
// Format: { THEME_NAME: CSS_SELECTOR }
|
|
||||||
const THEMES = { dark: ".dark", light: "" } as const;
|
|
||||||
|
|
||||||
export type ChartConfig = {
|
|
||||||
[k in string]: {
|
|
||||||
label?: React.ReactNode;
|
|
||||||
icon?: React.ComponentType;
|
|
||||||
} & (
|
|
||||||
| { color?: string; theme?: never }
|
|
||||||
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type ChartContextProps = {
|
|
||||||
config: ChartConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ChartContext = React.createContext<ChartContextProps | null>(null);
|
|
||||||
|
|
||||||
function useChart() {
|
|
||||||
const context = React.useContext(ChartContext);
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
throw new Error("useChart must be used within a <ChartContainer />");
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChartContainer({
|
|
||||||
id,
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
config,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<"div"> & {
|
|
||||||
config: ChartConfig;
|
|
||||||
children: React.ComponentProps<
|
|
||||||
typeof RechartsPrimitive.ResponsiveContainer
|
|
||||||
>["children"];
|
|
||||||
}) {
|
|
||||||
const uniqueId = React.useId();
|
|
||||||
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ChartContext.Provider value={{ config }}>
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-hidden [&_.recharts-surface]:outline-hidden",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
data-chart={chartId}
|
|
||||||
data-slot="chart"
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<ChartStyle config={config} id={chartId} />
|
|
||||||
<RechartsPrimitive.ResponsiveContainer>
|
|
||||||
{children}
|
|
||||||
</RechartsPrimitive.ResponsiveContainer>
|
|
||||||
</div>
|
|
||||||
</ChartContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
|
||||||
const colorConfig = Object.entries(config).filter(
|
|
||||||
([, config]) => config.theme || config.color,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!colorConfig.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<style
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: Object.entries(THEMES)
|
|
||||||
.map(
|
|
||||||
([theme, prefix]) => `
|
|
||||||
${prefix} [data-chart=${id}] {
|
|
||||||
${colorConfig
|
|
||||||
.map(([key, itemConfig]) => {
|
|
||||||
const color =
|
|
||||||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
|
||||||
itemConfig.color;
|
|
||||||
return color ? ` --color-${key}: ${color};` : null;
|
|
||||||
})
|
|
||||||
.join("\n")}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
)
|
|
||||||
.join("\n"),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ChartTooltip = RechartsPrimitive.Tooltip;
|
|
||||||
|
|
||||||
function ChartTooltipContent({
|
|
||||||
active,
|
|
||||||
payload,
|
|
||||||
className,
|
|
||||||
indicator = "dot",
|
|
||||||
hideLabel = false,
|
|
||||||
hideIndicator = false,
|
|
||||||
label,
|
|
||||||
labelFormatter,
|
|
||||||
labelClassName,
|
|
||||||
formatter,
|
|
||||||
color,
|
|
||||||
nameKey,
|
|
||||||
labelKey,
|
|
||||||
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
|
||||||
React.ComponentProps<"div"> & {
|
|
||||||
hideLabel?: boolean;
|
|
||||||
hideIndicator?: boolean;
|
|
||||||
indicator?: "line" | "dot" | "dashed";
|
|
||||||
nameKey?: string;
|
|
||||||
labelKey?: string;
|
|
||||||
}) {
|
|
||||||
const { config } = useChart();
|
|
||||||
|
|
||||||
const tooltipLabel = React.useMemo(() => {
|
|
||||||
if (hideLabel || !payload?.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [item] = payload;
|
|
||||||
const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
|
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
|
||||||
const value =
|
|
||||||
!labelKey && typeof label === "string"
|
|
||||||
? config[label as keyof typeof config]?.label || label
|
|
||||||
: itemConfig?.label;
|
|
||||||
|
|
||||||
if (labelFormatter) {
|
|
||||||
return (
|
|
||||||
<div className={cn("font-medium", labelClassName)}>
|
|
||||||
{labelFormatter(value, payload)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div className={cn("font-medium", labelClassName)}>{value}</div>;
|
|
||||||
}, [
|
|
||||||
label,
|
|
||||||
labelFormatter,
|
|
||||||
payload,
|
|
||||||
hideLabel,
|
|
||||||
labelClassName,
|
|
||||||
config,
|
|
||||||
labelKey,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!active || !payload?.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nestLabel = payload.length === 1 && indicator !== "dot";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{!nestLabel ? tooltipLabel : null}
|
|
||||||
<div className="grid gap-1.5">
|
|
||||||
{payload.map((item, index) => {
|
|
||||||
const key = `${nameKey || item.name || item.dataKey || "value"}`;
|
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
|
||||||
const indicatorColor = color || item.payload.fill || item.color;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
|
||||||
indicator === "dot" && "items-center",
|
|
||||||
)}
|
|
||||||
key={item.dataKey}
|
|
||||||
>
|
|
||||||
{formatter && item?.value !== undefined && item.name ? (
|
|
||||||
formatter(item.value, item.name, item, index, item.payload)
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{itemConfig?.icon ? (
|
|
||||||
<itemConfig.icon />
|
|
||||||
) : (
|
|
||||||
!hideIndicator && (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
|
|
||||||
{
|
|
||||||
"h-2.5 w-2.5": indicator === "dot",
|
|
||||||
"my-0.5": nestLabel && indicator === "dashed",
|
|
||||||
"w-0 border-[1.5px] border-dashed bg-transparent":
|
|
||||||
indicator === "dashed",
|
|
||||||
"w-1": indicator === "line",
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
style={
|
|
||||||
{
|
|
||||||
"--color-bg": indicatorColor,
|
|
||||||
"--color-border": indicatorColor,
|
|
||||||
} as React.CSSProperties
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex flex-1 justify-between leading-none",
|
|
||||||
nestLabel ? "items-end" : "items-center",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="grid gap-1.5">
|
|
||||||
{nestLabel ? tooltipLabel : null}
|
|
||||||
<span className="text-muted-foreground">
|
|
||||||
{itemConfig?.label || item.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{item.value && (
|
|
||||||
<span className="font-medium font-mono text-foreground tabular-nums">
|
|
||||||
{item.value.toLocaleString("it-IT")}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ChartLegend = RechartsPrimitive.Legend;
|
|
||||||
|
|
||||||
function ChartLegendContent({
|
|
||||||
className,
|
|
||||||
hideIcon = false,
|
|
||||||
payload,
|
|
||||||
verticalAlign = "bottom",
|
|
||||||
nameKey,
|
|
||||||
}: React.ComponentProps<"div"> &
|
|
||||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
|
||||||
hideIcon?: boolean;
|
|
||||||
nameKey?: string;
|
|
||||||
}) {
|
|
||||||
const { config } = useChart();
|
|
||||||
|
|
||||||
if (!payload?.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex items-center justify-center gap-4",
|
|
||||||
verticalAlign === "top" ? "pb-3" : "pt-3",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{payload.map((item) => {
|
|
||||||
const key = `${nameKey || item.dataKey || "value"}`;
|
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
|
|
||||||
)}
|
|
||||||
key={item.value}
|
|
||||||
>
|
|
||||||
{itemConfig?.icon && !hideIcon ? (
|
|
||||||
<itemConfig.icon />
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
className="h-2 w-2 shrink-0 rounded-[2px]"
|
|
||||||
style={{
|
|
||||||
backgroundColor: item.color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{itemConfig?.label}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to extract item config from a payload.
|
|
||||||
function getPayloadConfigFromPayload(
|
|
||||||
config: ChartConfig,
|
|
||||||
payload: unknown,
|
|
||||||
key: string,
|
|
||||||
) {
|
|
||||||
if (typeof payload !== "object" || payload === null) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const payloadPayload =
|
|
||||||
"payload" in payload &&
|
|
||||||
typeof payload.payload === "object" &&
|
|
||||||
payload.payload !== null
|
|
||||||
? payload.payload
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
let configLabelKey: string = key;
|
|
||||||
|
|
||||||
if (
|
|
||||||
key in payload &&
|
|
||||||
typeof payload[key as keyof typeof payload] === "string"
|
|
||||||
) {
|
|
||||||
configLabelKey = payload[key as keyof typeof payload] as string;
|
|
||||||
} else if (
|
|
||||||
payloadPayload &&
|
|
||||||
key in payloadPayload &&
|
|
||||||
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
|
||||||
) {
|
|
||||||
configLabelKey = payloadPayload[
|
|
||||||
key as keyof typeof payloadPayload
|
|
||||||
] as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
return configLabelKey in config
|
|
||||||
? config[configLabelKey]
|
|
||||||
: config[key as keyof typeof config];
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
ChartContainer,
|
|
||||||
ChartTooltip,
|
|
||||||
ChartTooltipContent,
|
|
||||||
ChartLegend,
|
|
||||||
ChartLegendContent,
|
|
||||||
ChartStyle,
|
|
||||||
};
|
|
||||||
Loading…
Add table
Reference in a new issue