Prakhar Singh
commited on
Commit
·
8811e47
1
Parent(s):
2636d69
DashBoard and Quize Cereated
Browse files- Frontend/package-lock.json +397 -2
- Frontend/package.json +2 -0
- Frontend/src/components/dashboard/FeedBackScore.tsx +46 -0
- Frontend/src/components/dashboard/InterviewPlayback.tsx +27 -0
- Frontend/src/components/dashboard/SkillRadarChart.tsx +28 -0
- Frontend/src/components/dashboard/WeakAreaBanner.tsx +14 -0
- Frontend/src/components/dashboard/YearlyStreak.tsx +80 -0
- Frontend/src/components/ui/card.tsx +0 -81
- Frontend/src/pages/dashboard.tsx +106 -8
- Frontend/src/pages/home.tsx +1 -1
- Frontend/src/pages/quize.tsx +100 -96
- Frontend/src/utils/generateYearlyStreakData.ts +20 -0
Frontend/package-lock.json
CHANGED
|
@@ -12,11 +12,13 @@
|
|
| 12 |
"@splinetool/runtime": "^1.11.2",
|
| 13 |
"@tailwindcss/vite": "^4.1.17",
|
| 14 |
"clsx": "^2.1.1",
|
|
|
|
| 15 |
"framer-motion": "^12.23.24",
|
| 16 |
"lucide-react": "^0.553.0",
|
| 17 |
"react": "^19.2.0",
|
| 18 |
"react-dom": "^19.2.0",
|
| 19 |
"react-router-dom": "^7.9.5",
|
|
|
|
| 20 |
"tailwind-merge": "^3.4.0",
|
| 21 |
"tailwindcss": "^4.1.17"
|
| 22 |
},
|
|
@@ -1025,6 +1027,32 @@
|
|
| 1025 |
"node": ">= 8"
|
| 1026 |
}
|
| 1027 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1028 |
"node_modules/@rolldown/pluginutils": {
|
| 1029 |
"version": "1.0.0-beta.43",
|
| 1030 |
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz",
|
|
@@ -1349,6 +1377,18 @@
|
|
| 1349 |
"semver-compare": "^1.0.0"
|
| 1350 |
}
|
| 1351 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1352 |
"node_modules/@tailwindcss/node": {
|
| 1353 |
"version": "4.1.17",
|
| 1354 |
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz",
|
|
@@ -1651,6 +1691,69 @@
|
|
| 1651 |
"@babel/types": "^7.28.2"
|
| 1652 |
}
|
| 1653 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1654 |
"node_modules/@types/estree": {
|
| 1655 |
"version": "1.0.8",
|
| 1656 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
|
@@ -1678,7 +1781,7 @@
|
|
| 1678 |
"version": "19.2.2",
|
| 1679 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
| 1680 |
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
| 1681 |
-
"
|
| 1682 |
"license": "MIT",
|
| 1683 |
"dependencies": {
|
| 1684 |
"csstype": "^3.0.2"
|
|
@@ -1694,6 +1797,12 @@
|
|
| 1694 |
"@types/react": "^19.2.0"
|
| 1695 |
}
|
| 1696 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1697 |
"node_modules/@typescript-eslint/eslint-plugin": {
|
| 1698 |
"version": "8.46.3",
|
| 1699 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.3.tgz",
|
|
@@ -2249,7 +2358,134 @@
|
|
| 2249 |
"version": "3.1.3",
|
| 2250 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
| 2251 |
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
| 2252 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2253 |
"license": "MIT"
|
| 2254 |
},
|
| 2255 |
"node_modules/debug": {
|
|
@@ -2270,6 +2506,12 @@
|
|
| 2270 |
}
|
| 2271 |
}
|
| 2272 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2273 |
"node_modules/deep-is": {
|
| 2274 |
"version": "0.1.4",
|
| 2275 |
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
|
@@ -2306,6 +2548,16 @@
|
|
| 2306 |
"node": ">=10.13.0"
|
| 2307 |
}
|
| 2308 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2309 |
"node_modules/esbuild": {
|
| 2310 |
"version": "0.25.12",
|
| 2311 |
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
|
@@ -2547,6 +2799,12 @@
|
|
| 2547 |
"node": ">=0.10.0"
|
| 2548 |
}
|
| 2549 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2550 |
"node_modules/fast-deep-equal": {
|
| 2551 |
"version": "3.1.3",
|
| 2552 |
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
@@ -2782,6 +3040,16 @@
|
|
| 2782 |
"node": ">= 4"
|
| 2783 |
}
|
| 2784 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2785 |
"node_modules/import-fresh": {
|
| 2786 |
"version": "3.3.1",
|
| 2787 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
|
@@ -2809,6 +3077,15 @@
|
|
| 2809 |
"node": ">=0.8.19"
|
| 2810 |
}
|
| 2811 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2812 |
"node_modules/is-extglob": {
|
| 2813 |
"version": "2.1.1",
|
| 2814 |
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
|
@@ -3550,6 +3827,13 @@
|
|
| 3550 |
"react": "^19.2.0"
|
| 3551 |
}
|
| 3552 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3553 |
"node_modules/react-merge-refs": {
|
| 3554 |
"version": "2.1.1",
|
| 3555 |
"resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-2.1.1.tgz",
|
|
@@ -3560,6 +3844,29 @@
|
|
| 3560 |
"url": "https://github.com/sponsors/gregberge"
|
| 3561 |
}
|
| 3562 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3563 |
"node_modules/react-refresh": {
|
| 3564 |
"version": "0.18.0",
|
| 3565 |
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
|
|
@@ -3608,6 +3915,57 @@
|
|
| 3608 |
"react-dom": ">=18"
|
| 3609 |
}
|
| 3610 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3611 |
"node_modules/resolve-from": {
|
| 3612 |
"version": "4.0.0",
|
| 3613 |
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
|
@@ -3815,6 +4173,12 @@
|
|
| 3815 |
"integrity": "sha512-kH5pKeIIBPQXAOni2AiY/Cu/NKdkFREdpH+TLdM0g6WA7RriCv0kPLgP731ady67MhTAqrVG/4mnEeibVuCJcg==",
|
| 3816 |
"license": "MIT"
|
| 3817 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3818 |
"node_modules/tinyglobby": {
|
| 3819 |
"version": "0.2.15",
|
| 3820 |
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
|
@@ -3991,6 +4355,37 @@
|
|
| 3991 |
"punycode": "^2.1.0"
|
| 3992 |
}
|
| 3993 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3994 |
"node_modules/vite": {
|
| 3995 |
"version": "7.2.2",
|
| 3996 |
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
|
|
|
|
| 12 |
"@splinetool/runtime": "^1.11.2",
|
| 13 |
"@tailwindcss/vite": "^4.1.17",
|
| 14 |
"clsx": "^2.1.1",
|
| 15 |
+
"dayjs": "^1.11.19",
|
| 16 |
"framer-motion": "^12.23.24",
|
| 17 |
"lucide-react": "^0.553.0",
|
| 18 |
"react": "^19.2.0",
|
| 19 |
"react-dom": "^19.2.0",
|
| 20 |
"react-router-dom": "^7.9.5",
|
| 21 |
+
"recharts": "^3.4.1",
|
| 22 |
"tailwind-merge": "^3.4.0",
|
| 23 |
"tailwindcss": "^4.1.17"
|
| 24 |
},
|
|
|
|
| 1027 |
"node": ">= 8"
|
| 1028 |
}
|
| 1029 |
},
|
| 1030 |
+
"node_modules/@reduxjs/toolkit": {
|
| 1031 |
+
"version": "2.10.1",
|
| 1032 |
+
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.10.1.tgz",
|
| 1033 |
+
"integrity": "sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==",
|
| 1034 |
+
"license": "MIT",
|
| 1035 |
+
"dependencies": {
|
| 1036 |
+
"@standard-schema/spec": "^1.0.0",
|
| 1037 |
+
"@standard-schema/utils": "^0.3.0",
|
| 1038 |
+
"immer": "^10.2.0",
|
| 1039 |
+
"redux": "^5.0.1",
|
| 1040 |
+
"redux-thunk": "^3.1.0",
|
| 1041 |
+
"reselect": "^5.1.0"
|
| 1042 |
+
},
|
| 1043 |
+
"peerDependencies": {
|
| 1044 |
+
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
|
| 1045 |
+
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
| 1046 |
+
},
|
| 1047 |
+
"peerDependenciesMeta": {
|
| 1048 |
+
"react": {
|
| 1049 |
+
"optional": true
|
| 1050 |
+
},
|
| 1051 |
+
"react-redux": {
|
| 1052 |
+
"optional": true
|
| 1053 |
+
}
|
| 1054 |
+
}
|
| 1055 |
+
},
|
| 1056 |
"node_modules/@rolldown/pluginutils": {
|
| 1057 |
"version": "1.0.0-beta.43",
|
| 1058 |
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz",
|
|
|
|
| 1377 |
"semver-compare": "^1.0.0"
|
| 1378 |
}
|
| 1379 |
},
|
| 1380 |
+
"node_modules/@standard-schema/spec": {
|
| 1381 |
+
"version": "1.0.0",
|
| 1382 |
+
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
| 1383 |
+
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
| 1384 |
+
"license": "MIT"
|
| 1385 |
+
},
|
| 1386 |
+
"node_modules/@standard-schema/utils": {
|
| 1387 |
+
"version": "0.3.0",
|
| 1388 |
+
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
|
| 1389 |
+
"integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
|
| 1390 |
+
"license": "MIT"
|
| 1391 |
+
},
|
| 1392 |
"node_modules/@tailwindcss/node": {
|
| 1393 |
"version": "4.1.17",
|
| 1394 |
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz",
|
|
|
|
| 1691 |
"@babel/types": "^7.28.2"
|
| 1692 |
}
|
| 1693 |
},
|
| 1694 |
+
"node_modules/@types/d3-array": {
|
| 1695 |
+
"version": "3.2.2",
|
| 1696 |
+
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
|
| 1697 |
+
"integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
|
| 1698 |
+
"license": "MIT"
|
| 1699 |
+
},
|
| 1700 |
+
"node_modules/@types/d3-color": {
|
| 1701 |
+
"version": "3.1.3",
|
| 1702 |
+
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
| 1703 |
+
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
|
| 1704 |
+
"license": "MIT"
|
| 1705 |
+
},
|
| 1706 |
+
"node_modules/@types/d3-ease": {
|
| 1707 |
+
"version": "3.0.2",
|
| 1708 |
+
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
|
| 1709 |
+
"integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
|
| 1710 |
+
"license": "MIT"
|
| 1711 |
+
},
|
| 1712 |
+
"node_modules/@types/d3-interpolate": {
|
| 1713 |
+
"version": "3.0.4",
|
| 1714 |
+
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
| 1715 |
+
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
| 1716 |
+
"license": "MIT",
|
| 1717 |
+
"dependencies": {
|
| 1718 |
+
"@types/d3-color": "*"
|
| 1719 |
+
}
|
| 1720 |
+
},
|
| 1721 |
+
"node_modules/@types/d3-path": {
|
| 1722 |
+
"version": "3.1.1",
|
| 1723 |
+
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
|
| 1724 |
+
"integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
|
| 1725 |
+
"license": "MIT"
|
| 1726 |
+
},
|
| 1727 |
+
"node_modules/@types/d3-scale": {
|
| 1728 |
+
"version": "4.0.9",
|
| 1729 |
+
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
|
| 1730 |
+
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
|
| 1731 |
+
"license": "MIT",
|
| 1732 |
+
"dependencies": {
|
| 1733 |
+
"@types/d3-time": "*"
|
| 1734 |
+
}
|
| 1735 |
+
},
|
| 1736 |
+
"node_modules/@types/d3-shape": {
|
| 1737 |
+
"version": "3.1.7",
|
| 1738 |
+
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
|
| 1739 |
+
"integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
|
| 1740 |
+
"license": "MIT",
|
| 1741 |
+
"dependencies": {
|
| 1742 |
+
"@types/d3-path": "*"
|
| 1743 |
+
}
|
| 1744 |
+
},
|
| 1745 |
+
"node_modules/@types/d3-time": {
|
| 1746 |
+
"version": "3.0.4",
|
| 1747 |
+
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
|
| 1748 |
+
"integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
|
| 1749 |
+
"license": "MIT"
|
| 1750 |
+
},
|
| 1751 |
+
"node_modules/@types/d3-timer": {
|
| 1752 |
+
"version": "3.0.2",
|
| 1753 |
+
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
|
| 1754 |
+
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
|
| 1755 |
+
"license": "MIT"
|
| 1756 |
+
},
|
| 1757 |
"node_modules/@types/estree": {
|
| 1758 |
"version": "1.0.8",
|
| 1759 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
|
|
|
| 1781 |
"version": "19.2.2",
|
| 1782 |
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
| 1783 |
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
| 1784 |
+
"devOptional": true,
|
| 1785 |
"license": "MIT",
|
| 1786 |
"dependencies": {
|
| 1787 |
"csstype": "^3.0.2"
|
|
|
|
| 1797 |
"@types/react": "^19.2.0"
|
| 1798 |
}
|
| 1799 |
},
|
| 1800 |
+
"node_modules/@types/use-sync-external-store": {
|
| 1801 |
+
"version": "0.0.6",
|
| 1802 |
+
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
| 1803 |
+
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
| 1804 |
+
"license": "MIT"
|
| 1805 |
+
},
|
| 1806 |
"node_modules/@typescript-eslint/eslint-plugin": {
|
| 1807 |
"version": "8.46.3",
|
| 1808 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.3.tgz",
|
|
|
|
| 2358 |
"version": "3.1.3",
|
| 2359 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
| 2360 |
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
| 2361 |
+
"devOptional": true,
|
| 2362 |
+
"license": "MIT"
|
| 2363 |
+
},
|
| 2364 |
+
"node_modules/d3-array": {
|
| 2365 |
+
"version": "3.2.4",
|
| 2366 |
+
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
| 2367 |
+
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
|
| 2368 |
+
"license": "ISC",
|
| 2369 |
+
"dependencies": {
|
| 2370 |
+
"internmap": "1 - 2"
|
| 2371 |
+
},
|
| 2372 |
+
"engines": {
|
| 2373 |
+
"node": ">=12"
|
| 2374 |
+
}
|
| 2375 |
+
},
|
| 2376 |
+
"node_modules/d3-color": {
|
| 2377 |
+
"version": "3.1.0",
|
| 2378 |
+
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
| 2379 |
+
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
| 2380 |
+
"license": "ISC",
|
| 2381 |
+
"engines": {
|
| 2382 |
+
"node": ">=12"
|
| 2383 |
+
}
|
| 2384 |
+
},
|
| 2385 |
+
"node_modules/d3-ease": {
|
| 2386 |
+
"version": "3.0.1",
|
| 2387 |
+
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
| 2388 |
+
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
| 2389 |
+
"license": "BSD-3-Clause",
|
| 2390 |
+
"engines": {
|
| 2391 |
+
"node": ">=12"
|
| 2392 |
+
}
|
| 2393 |
+
},
|
| 2394 |
+
"node_modules/d3-format": {
|
| 2395 |
+
"version": "3.1.0",
|
| 2396 |
+
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
|
| 2397 |
+
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
|
| 2398 |
+
"license": "ISC",
|
| 2399 |
+
"engines": {
|
| 2400 |
+
"node": ">=12"
|
| 2401 |
+
}
|
| 2402 |
+
},
|
| 2403 |
+
"node_modules/d3-interpolate": {
|
| 2404 |
+
"version": "3.0.1",
|
| 2405 |
+
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
| 2406 |
+
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
| 2407 |
+
"license": "ISC",
|
| 2408 |
+
"dependencies": {
|
| 2409 |
+
"d3-color": "1 - 3"
|
| 2410 |
+
},
|
| 2411 |
+
"engines": {
|
| 2412 |
+
"node": ">=12"
|
| 2413 |
+
}
|
| 2414 |
+
},
|
| 2415 |
+
"node_modules/d3-path": {
|
| 2416 |
+
"version": "3.1.0",
|
| 2417 |
+
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
|
| 2418 |
+
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
|
| 2419 |
+
"license": "ISC",
|
| 2420 |
+
"engines": {
|
| 2421 |
+
"node": ">=12"
|
| 2422 |
+
}
|
| 2423 |
+
},
|
| 2424 |
+
"node_modules/d3-scale": {
|
| 2425 |
+
"version": "4.0.2",
|
| 2426 |
+
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
|
| 2427 |
+
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
|
| 2428 |
+
"license": "ISC",
|
| 2429 |
+
"dependencies": {
|
| 2430 |
+
"d3-array": "2.10.0 - 3",
|
| 2431 |
+
"d3-format": "1 - 3",
|
| 2432 |
+
"d3-interpolate": "1.2.0 - 3",
|
| 2433 |
+
"d3-time": "2.1.1 - 3",
|
| 2434 |
+
"d3-time-format": "2 - 4"
|
| 2435 |
+
},
|
| 2436 |
+
"engines": {
|
| 2437 |
+
"node": ">=12"
|
| 2438 |
+
}
|
| 2439 |
+
},
|
| 2440 |
+
"node_modules/d3-shape": {
|
| 2441 |
+
"version": "3.2.0",
|
| 2442 |
+
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
|
| 2443 |
+
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
|
| 2444 |
+
"license": "ISC",
|
| 2445 |
+
"dependencies": {
|
| 2446 |
+
"d3-path": "^3.1.0"
|
| 2447 |
+
},
|
| 2448 |
+
"engines": {
|
| 2449 |
+
"node": ">=12"
|
| 2450 |
+
}
|
| 2451 |
+
},
|
| 2452 |
+
"node_modules/d3-time": {
|
| 2453 |
+
"version": "3.1.0",
|
| 2454 |
+
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
|
| 2455 |
+
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
|
| 2456 |
+
"license": "ISC",
|
| 2457 |
+
"dependencies": {
|
| 2458 |
+
"d3-array": "2 - 3"
|
| 2459 |
+
},
|
| 2460 |
+
"engines": {
|
| 2461 |
+
"node": ">=12"
|
| 2462 |
+
}
|
| 2463 |
+
},
|
| 2464 |
+
"node_modules/d3-time-format": {
|
| 2465 |
+
"version": "4.1.0",
|
| 2466 |
+
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
|
| 2467 |
+
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
|
| 2468 |
+
"license": "ISC",
|
| 2469 |
+
"dependencies": {
|
| 2470 |
+
"d3-time": "1 - 3"
|
| 2471 |
+
},
|
| 2472 |
+
"engines": {
|
| 2473 |
+
"node": ">=12"
|
| 2474 |
+
}
|
| 2475 |
+
},
|
| 2476 |
+
"node_modules/d3-timer": {
|
| 2477 |
+
"version": "3.0.1",
|
| 2478 |
+
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
| 2479 |
+
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
| 2480 |
+
"license": "ISC",
|
| 2481 |
+
"engines": {
|
| 2482 |
+
"node": ">=12"
|
| 2483 |
+
}
|
| 2484 |
+
},
|
| 2485 |
+
"node_modules/dayjs": {
|
| 2486 |
+
"version": "1.11.19",
|
| 2487 |
+
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
| 2488 |
+
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
|
| 2489 |
"license": "MIT"
|
| 2490 |
},
|
| 2491 |
"node_modules/debug": {
|
|
|
|
| 2506 |
}
|
| 2507 |
}
|
| 2508 |
},
|
| 2509 |
+
"node_modules/decimal.js-light": {
|
| 2510 |
+
"version": "2.5.1",
|
| 2511 |
+
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
| 2512 |
+
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
|
| 2513 |
+
"license": "MIT"
|
| 2514 |
+
},
|
| 2515 |
"node_modules/deep-is": {
|
| 2516 |
"version": "0.1.4",
|
| 2517 |
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
|
|
|
| 2548 |
"node": ">=10.13.0"
|
| 2549 |
}
|
| 2550 |
},
|
| 2551 |
+
"node_modules/es-toolkit": {
|
| 2552 |
+
"version": "1.41.0",
|
| 2553 |
+
"resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.41.0.tgz",
|
| 2554 |
+
"integrity": "sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==",
|
| 2555 |
+
"license": "MIT",
|
| 2556 |
+
"workspaces": [
|
| 2557 |
+
"docs",
|
| 2558 |
+
"benchmarks"
|
| 2559 |
+
]
|
| 2560 |
+
},
|
| 2561 |
"node_modules/esbuild": {
|
| 2562 |
"version": "0.25.12",
|
| 2563 |
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
|
|
|
| 2799 |
"node": ">=0.10.0"
|
| 2800 |
}
|
| 2801 |
},
|
| 2802 |
+
"node_modules/eventemitter3": {
|
| 2803 |
+
"version": "5.0.1",
|
| 2804 |
+
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
| 2805 |
+
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
| 2806 |
+
"license": "MIT"
|
| 2807 |
+
},
|
| 2808 |
"node_modules/fast-deep-equal": {
|
| 2809 |
"version": "3.1.3",
|
| 2810 |
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
|
|
| 3040 |
"node": ">= 4"
|
| 3041 |
}
|
| 3042 |
},
|
| 3043 |
+
"node_modules/immer": {
|
| 3044 |
+
"version": "10.2.0",
|
| 3045 |
+
"resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
|
| 3046 |
+
"integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
|
| 3047 |
+
"license": "MIT",
|
| 3048 |
+
"funding": {
|
| 3049 |
+
"type": "opencollective",
|
| 3050 |
+
"url": "https://opencollective.com/immer"
|
| 3051 |
+
}
|
| 3052 |
+
},
|
| 3053 |
"node_modules/import-fresh": {
|
| 3054 |
"version": "3.3.1",
|
| 3055 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
|
|
|
| 3077 |
"node": ">=0.8.19"
|
| 3078 |
}
|
| 3079 |
},
|
| 3080 |
+
"node_modules/internmap": {
|
| 3081 |
+
"version": "2.0.3",
|
| 3082 |
+
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
| 3083 |
+
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
|
| 3084 |
+
"license": "ISC",
|
| 3085 |
+
"engines": {
|
| 3086 |
+
"node": ">=12"
|
| 3087 |
+
}
|
| 3088 |
+
},
|
| 3089 |
"node_modules/is-extglob": {
|
| 3090 |
"version": "2.1.1",
|
| 3091 |
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
|
|
|
| 3827 |
"react": "^19.2.0"
|
| 3828 |
}
|
| 3829 |
},
|
| 3830 |
+
"node_modules/react-is": {
|
| 3831 |
+
"version": "19.2.0",
|
| 3832 |
+
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
|
| 3833 |
+
"integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
|
| 3834 |
+
"license": "MIT",
|
| 3835 |
+
"peer": true
|
| 3836 |
+
},
|
| 3837 |
"node_modules/react-merge-refs": {
|
| 3838 |
"version": "2.1.1",
|
| 3839 |
"resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-2.1.1.tgz",
|
|
|
|
| 3844 |
"url": "https://github.com/sponsors/gregberge"
|
| 3845 |
}
|
| 3846 |
},
|
| 3847 |
+
"node_modules/react-redux": {
|
| 3848 |
+
"version": "9.2.0",
|
| 3849 |
+
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
| 3850 |
+
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
| 3851 |
+
"license": "MIT",
|
| 3852 |
+
"dependencies": {
|
| 3853 |
+
"@types/use-sync-external-store": "^0.0.6",
|
| 3854 |
+
"use-sync-external-store": "^1.4.0"
|
| 3855 |
+
},
|
| 3856 |
+
"peerDependencies": {
|
| 3857 |
+
"@types/react": "^18.2.25 || ^19",
|
| 3858 |
+
"react": "^18.0 || ^19",
|
| 3859 |
+
"redux": "^5.0.0"
|
| 3860 |
+
},
|
| 3861 |
+
"peerDependenciesMeta": {
|
| 3862 |
+
"@types/react": {
|
| 3863 |
+
"optional": true
|
| 3864 |
+
},
|
| 3865 |
+
"redux": {
|
| 3866 |
+
"optional": true
|
| 3867 |
+
}
|
| 3868 |
+
}
|
| 3869 |
+
},
|
| 3870 |
"node_modules/react-refresh": {
|
| 3871 |
"version": "0.18.0",
|
| 3872 |
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
|
|
|
|
| 3915 |
"react-dom": ">=18"
|
| 3916 |
}
|
| 3917 |
},
|
| 3918 |
+
"node_modules/recharts": {
|
| 3919 |
+
"version": "3.4.1",
|
| 3920 |
+
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.4.1.tgz",
|
| 3921 |
+
"integrity": "sha512-35kYg6JoOgwq8sE4rhYkVWwa6aAIgOtT+Ob0gitnShjwUwZmhrmy7Jco/5kJNF4PnLXgt9Hwq+geEMS+WrjU1g==",
|
| 3922 |
+
"license": "MIT",
|
| 3923 |
+
"workspaces": [
|
| 3924 |
+
"www"
|
| 3925 |
+
],
|
| 3926 |
+
"dependencies": {
|
| 3927 |
+
"@reduxjs/toolkit": "1.x.x || 2.x.x",
|
| 3928 |
+
"clsx": "^2.1.1",
|
| 3929 |
+
"decimal.js-light": "^2.5.1",
|
| 3930 |
+
"es-toolkit": "^1.39.3",
|
| 3931 |
+
"eventemitter3": "^5.0.1",
|
| 3932 |
+
"immer": "^10.1.1",
|
| 3933 |
+
"react-redux": "8.x.x || 9.x.x",
|
| 3934 |
+
"reselect": "5.1.1",
|
| 3935 |
+
"tiny-invariant": "^1.3.3",
|
| 3936 |
+
"use-sync-external-store": "^1.2.2",
|
| 3937 |
+
"victory-vendor": "^37.0.2"
|
| 3938 |
+
},
|
| 3939 |
+
"engines": {
|
| 3940 |
+
"node": ">=18"
|
| 3941 |
+
},
|
| 3942 |
+
"peerDependencies": {
|
| 3943 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3944 |
+
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3945 |
+
"react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 3946 |
+
}
|
| 3947 |
+
},
|
| 3948 |
+
"node_modules/redux": {
|
| 3949 |
+
"version": "5.0.1",
|
| 3950 |
+
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
| 3951 |
+
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
| 3952 |
+
"license": "MIT"
|
| 3953 |
+
},
|
| 3954 |
+
"node_modules/redux-thunk": {
|
| 3955 |
+
"version": "3.1.0",
|
| 3956 |
+
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
| 3957 |
+
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
| 3958 |
+
"license": "MIT",
|
| 3959 |
+
"peerDependencies": {
|
| 3960 |
+
"redux": "^5.0.0"
|
| 3961 |
+
}
|
| 3962 |
+
},
|
| 3963 |
+
"node_modules/reselect": {
|
| 3964 |
+
"version": "5.1.1",
|
| 3965 |
+
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
| 3966 |
+
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
| 3967 |
+
"license": "MIT"
|
| 3968 |
+
},
|
| 3969 |
"node_modules/resolve-from": {
|
| 3970 |
"version": "4.0.0",
|
| 3971 |
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
|
|
|
| 4173 |
"integrity": "sha512-kH5pKeIIBPQXAOni2AiY/Cu/NKdkFREdpH+TLdM0g6WA7RriCv0kPLgP731ady67MhTAqrVG/4mnEeibVuCJcg==",
|
| 4174 |
"license": "MIT"
|
| 4175 |
},
|
| 4176 |
+
"node_modules/tiny-invariant": {
|
| 4177 |
+
"version": "1.3.3",
|
| 4178 |
+
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
| 4179 |
+
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
|
| 4180 |
+
"license": "MIT"
|
| 4181 |
+
},
|
| 4182 |
"node_modules/tinyglobby": {
|
| 4183 |
"version": "0.2.15",
|
| 4184 |
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
|
|
|
| 4355 |
"punycode": "^2.1.0"
|
| 4356 |
}
|
| 4357 |
},
|
| 4358 |
+
"node_modules/use-sync-external-store": {
|
| 4359 |
+
"version": "1.6.0",
|
| 4360 |
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
| 4361 |
+
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
| 4362 |
+
"license": "MIT",
|
| 4363 |
+
"peerDependencies": {
|
| 4364 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 4365 |
+
}
|
| 4366 |
+
},
|
| 4367 |
+
"node_modules/victory-vendor": {
|
| 4368 |
+
"version": "37.3.6",
|
| 4369 |
+
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
|
| 4370 |
+
"integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
|
| 4371 |
+
"license": "MIT AND ISC",
|
| 4372 |
+
"dependencies": {
|
| 4373 |
+
"@types/d3-array": "^3.0.3",
|
| 4374 |
+
"@types/d3-ease": "^3.0.0",
|
| 4375 |
+
"@types/d3-interpolate": "^3.0.1",
|
| 4376 |
+
"@types/d3-scale": "^4.0.2",
|
| 4377 |
+
"@types/d3-shape": "^3.1.0",
|
| 4378 |
+
"@types/d3-time": "^3.0.0",
|
| 4379 |
+
"@types/d3-timer": "^3.0.0",
|
| 4380 |
+
"d3-array": "^3.1.6",
|
| 4381 |
+
"d3-ease": "^3.0.1",
|
| 4382 |
+
"d3-interpolate": "^3.0.1",
|
| 4383 |
+
"d3-scale": "^4.0.2",
|
| 4384 |
+
"d3-shape": "^3.1.0",
|
| 4385 |
+
"d3-time": "^3.0.0",
|
| 4386 |
+
"d3-timer": "^3.0.1"
|
| 4387 |
+
}
|
| 4388 |
+
},
|
| 4389 |
"node_modules/vite": {
|
| 4390 |
"version": "7.2.2",
|
| 4391 |
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
|
Frontend/package.json
CHANGED
|
@@ -14,11 +14,13 @@
|
|
| 14 |
"@splinetool/runtime": "^1.11.2",
|
| 15 |
"@tailwindcss/vite": "^4.1.17",
|
| 16 |
"clsx": "^2.1.1",
|
|
|
|
| 17 |
"framer-motion": "^12.23.24",
|
| 18 |
"lucide-react": "^0.553.0",
|
| 19 |
"react": "^19.2.0",
|
| 20 |
"react-dom": "^19.2.0",
|
| 21 |
"react-router-dom": "^7.9.5",
|
|
|
|
| 22 |
"tailwind-merge": "^3.4.0",
|
| 23 |
"tailwindcss": "^4.1.17"
|
| 24 |
},
|
|
|
|
| 14 |
"@splinetool/runtime": "^1.11.2",
|
| 15 |
"@tailwindcss/vite": "^4.1.17",
|
| 16 |
"clsx": "^2.1.1",
|
| 17 |
+
"dayjs": "^1.11.19",
|
| 18 |
"framer-motion": "^12.23.24",
|
| 19 |
"lucide-react": "^0.553.0",
|
| 20 |
"react": "^19.2.0",
|
| 21 |
"react-dom": "^19.2.0",
|
| 22 |
"react-router-dom": "^7.9.5",
|
| 23 |
+
"recharts": "^3.4.1",
|
| 24 |
"tailwind-merge": "^3.4.0",
|
| 25 |
"tailwindcss": "^4.1.17"
|
| 26 |
},
|
Frontend/src/components/dashboard/FeedBackScore.tsx
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from "react";
|
| 2 |
+
|
| 3 |
+
interface Props {
|
| 4 |
+
confidence: number;
|
| 5 |
+
clarity: number;
|
| 6 |
+
accuracy: number;
|
| 7 |
+
speed: number;
|
| 8 |
+
improvements: string[];
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
const ScoreCard = ({ label, value }: any) => (
|
| 12 |
+
<div className="p-4 text-center bg-gray-100 rounded-xl">
|
| 13 |
+
<p className="text-3xl font-bold text-black">{value}%</p>
|
| 14 |
+
<p className="text-gray-600">{label}</p>
|
| 15 |
+
</div>
|
| 16 |
+
);
|
| 17 |
+
|
| 18 |
+
const FeedbackScore: React.FC<Props> = ({
|
| 19 |
+
confidence,
|
| 20 |
+
clarity,
|
| 21 |
+
accuracy,
|
| 22 |
+
speed,
|
| 23 |
+
improvements,
|
| 24 |
+
}) => {
|
| 25 |
+
return (
|
| 26 |
+
<div className="bg-white p-5 shadow rounded-xl">
|
| 27 |
+
<h3 className="text-xl font-bold mb-3 text-black">AI Feedback Summary</h3>
|
| 28 |
+
|
| 29 |
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
| 30 |
+
<ScoreCard label="Confidence" value={confidence} />
|
| 31 |
+
<ScoreCard label="Clarity" value={clarity} />
|
| 32 |
+
<ScoreCard label="Technical Accuracy" value={accuracy} />
|
| 33 |
+
<ScoreCard label="Speed" value={speed} />
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
<h4 className="text-lg font-semibold mt-5 text-black">Suggested Improvements</h4>
|
| 37 |
+
<ul className="list-disc pl-5 text-blue-600">
|
| 38 |
+
{improvements.map((item, i) => (
|
| 39 |
+
<li key={i}>{item}</li>
|
| 40 |
+
))}
|
| 41 |
+
</ul>
|
| 42 |
+
</div>
|
| 43 |
+
);
|
| 44 |
+
};
|
| 45 |
+
|
| 46 |
+
export default FeedbackScore;
|
Frontend/src/components/dashboard/InterviewPlayback.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const InterviewPlayback = ({
|
| 2 |
+
audioUrl,
|
| 3 |
+
transcript,
|
| 4 |
+
highlights,
|
| 5 |
+
}: any) => (
|
| 6 |
+
<div className="bg-white p-5 shadow rounded-xl">
|
| 7 |
+
<h3 className="text-xl font-bold mb-4 text-black"> Interview Playback</h3>
|
| 8 |
+
|
| 9 |
+
{audioUrl && (
|
| 10 |
+
<audio controls className="w-full mb-4">
|
| 11 |
+
<source src={audioUrl} type="audio/mp3" />
|
| 12 |
+
</audio>
|
| 13 |
+
)}
|
| 14 |
+
|
| 15 |
+
<h4 className="font-semibold mb-2 text-black"> Transcript</h4>
|
| 16 |
+
<p className="text-gray-700 whitespace-pre-wrap">{transcript}</p>
|
| 17 |
+
|
| 18 |
+
<h4 className="font-semibold mt-4 text-black"> AI Highlights</h4>
|
| 19 |
+
<ul className="list-disc pl-5 text-blue-600">
|
| 20 |
+
{highlights.map((h: string, i: number) => (
|
| 21 |
+
<li key={i}>{h}</li>
|
| 22 |
+
))}
|
| 23 |
+
</ul>
|
| 24 |
+
</div>
|
| 25 |
+
);
|
| 26 |
+
|
| 27 |
+
export default InterviewPlayback;
|
Frontend/src/components/dashboard/SkillRadarChart.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import {
|
| 2 |
+
Radar, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, ResponsiveContainer
|
| 3 |
+
} from "recharts";
|
| 4 |
+
|
| 5 |
+
const SkillRadarChart = ({ data }: { data: any[] }) => (
|
| 6 |
+
<div className="bg-white p-5 shadow rounded-xl">
|
| 7 |
+
<h3 className="text-xl font-bold mb-3 text-black">Skill Strength Chart</h3>
|
| 8 |
+
|
| 9 |
+
<div className="w-full h-80">
|
| 10 |
+
<ResponsiveContainer>
|
| 11 |
+
<RadarChart cx="50%" cy="50%" outerRadius="70%" data={data}>
|
| 12 |
+
<PolarGrid />
|
| 13 |
+
<PolarAngleAxis dataKey="skill" />
|
| 14 |
+
<PolarRadiusAxis angle={30} domain={[0, 100]} />
|
| 15 |
+
<Radar
|
| 16 |
+
name="Skill Level"
|
| 17 |
+
dataKey="value"
|
| 18 |
+
stroke="#1170d6"
|
| 19 |
+
fill="#1170d6"
|
| 20 |
+
fillOpacity={0.4}
|
| 21 |
+
/>
|
| 22 |
+
</RadarChart>
|
| 23 |
+
</ResponsiveContainer>
|
| 24 |
+
</div>
|
| 25 |
+
</div>
|
| 26 |
+
);
|
| 27 |
+
|
| 28 |
+
export default SkillRadarChart;
|
Frontend/src/components/dashboard/WeakAreaBanner.tsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const WeakAreaBanner = ({ topic }: { topic: string | null }) => {
|
| 2 |
+
if (!topic) return null;
|
| 3 |
+
|
| 4 |
+
return (
|
| 5 |
+
<div className="bg-red-100 p-4 rounded-xl border border-red-300 mt-4">
|
| 6 |
+
<p className="text-red-700 font-semibold">
|
| 7 |
+
⚠️ You are weak in <strong>{topic}</strong>.
|
| 8 |
+
</p>
|
| 9 |
+
<p className="text-red-600">Start targeted practice today.</p>
|
| 10 |
+
</div>
|
| 11 |
+
);
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
export default WeakAreaBanner;
|
Frontend/src/components/dashboard/YearlyStreak.tsx
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
interface StreakData {
|
| 2 |
+
date: string;
|
| 3 |
+
count: number;
|
| 4 |
+
weekday: number;
|
| 5 |
+
week: number;
|
| 6 |
+
month: string;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
const getColor = (count: number) => {
|
| 10 |
+
if (count === 0) return "#2e2e2e";
|
| 11 |
+
if (count === 1) return "#9be9f8";
|
| 12 |
+
if (count === 2) return "#40c4f3";
|
| 13 |
+
if (count === 3) return "#30a1c4";
|
| 14 |
+
return "#216e9c";
|
| 15 |
+
};
|
| 16 |
+
const YearlyStreak = ({ data }: { data: StreakData[] }) => {
|
| 17 |
+
const totalSubmissions = data.reduce((a, b) => a + b.count, 0);
|
| 18 |
+
const activeDays = data.filter((d) => d.count > 0).length;
|
| 19 |
+
|
| 20 |
+
let streak = 0;
|
| 21 |
+
let maxStreak = 0;
|
| 22 |
+
data.forEach((d) => {
|
| 23 |
+
if (d.count > 0) {
|
| 24 |
+
streak++;
|
| 25 |
+
maxStreak = Math.max(maxStreak, streak);
|
| 26 |
+
} else {
|
| 27 |
+
streak = 0;
|
| 28 |
+
}
|
| 29 |
+
});
|
| 30 |
+
|
| 31 |
+
const weeks = data.reduce((acc: any, day) => {
|
| 32 |
+
acc[day.week] = acc[day.week] || [];
|
| 33 |
+
acc[day.week].push(day);
|
| 34 |
+
return acc;
|
| 35 |
+
}, {});
|
| 36 |
+
|
| 37 |
+
return (
|
| 38 |
+
<div className="bg-gray-900 p-6 rounded-xl text-white shadow-xl">
|
| 39 |
+
<div className="flex justify-between mb-4">
|
| 40 |
+
<h3 className="text-xl font-semibold">
|
| 41 |
+
{totalSubmissions} Hour Platform Activities This Year
|
| 42 |
+
</h3>
|
| 43 |
+
|
| 44 |
+
<div className="flex gap-6 text-gray-300">
|
| 45 |
+
<p>Total active days: <span className="text-white">{activeDays}</span></p>
|
| 46 |
+
<p>Max streak: <span className="text-white">{maxStreak}</span></p>
|
| 47 |
+
</div>
|
| 48 |
+
</div>
|
| 49 |
+
|
| 50 |
+
<div className="flex">
|
| 51 |
+
{Object.keys(weeks).map((weekIndex) => (
|
| 52 |
+
<div key={weekIndex} className="flex flex-col mr-1">
|
| 53 |
+
{weeks[weekIndex].map((day: StreakData) => (
|
| 54 |
+
<div
|
| 55 |
+
key={day.date}
|
| 56 |
+
title={`${day.date} — ${day.count} tasks`}
|
| 57 |
+
className="w-4 h-4 rounded-sm mb-1"
|
| 58 |
+
style={{ backgroundColor: getColor(day.count) }}
|
| 59 |
+
/>
|
| 60 |
+
))}
|
| 61 |
+
</div>
|
| 62 |
+
))}
|
| 63 |
+
</div>
|
| 64 |
+
|
| 65 |
+
<div className="flex mt-3 text-gray-400 text-xs">
|
| 66 |
+
{Object.keys(weeks).map((weekIndex) => {
|
| 67 |
+
const firstDay = weeks[weekIndex][0];
|
| 68 |
+
const showLabel = firstDay.date.endsWith("01");
|
| 69 |
+
return (
|
| 70 |
+
<div key={weekIndex} className="w-4 mx-[2px]">
|
| 71 |
+
{showLabel && <span>{firstDay.month}</span>}
|
| 72 |
+
</div>
|
| 73 |
+
);
|
| 74 |
+
})}
|
| 75 |
+
</div>
|
| 76 |
+
</div>
|
| 77 |
+
);
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
export default YearlyStreak;
|
Frontend/src/components/ui/card.tsx
DELETED
|
@@ -1,81 +0,0 @@
|
|
| 1 |
-
import * as React from "react"
|
| 2 |
-
import { cn } from "../../lib/utils"
|
| 3 |
-
|
| 4 |
-
// 1. Corrected forwardRef syntax: <RefType, PropsType>(...)
|
| 5 |
-
// 2. Used modern typing: React.ElementRef<"tag"> and React.ComponentPropsWithoutRef<"tag">
|
| 6 |
-
|
| 7 |
-
const Card = React.forwardRef<
|
| 8 |
-
React.ElementRef<"div">,
|
| 9 |
-
React.ComponentPropsWithoutRef<"div">
|
| 10 |
-
>(({ className, ...props }, ref) => (
|
| 11 |
-
<div
|
| 12 |
-
ref={ref}
|
| 13 |
-
className={cn(
|
| 14 |
-
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
| 15 |
-
className,
|
| 16 |
-
)}
|
| 17 |
-
{...props}
|
| 18 |
-
/>
|
| 19 |
-
))
|
| 20 |
-
Card.displayName = "Card"
|
| 21 |
-
|
| 22 |
-
const CardHeader = React.forwardRef<
|
| 23 |
-
React.ElementRef<"div">,
|
| 24 |
-
React.ComponentPropsWithoutRef<"div">
|
| 25 |
-
>(({ className, ...props }, ref) => (
|
| 26 |
-
<div
|
| 27 |
-
ref={ref}
|
| 28 |
-
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
| 29 |
-
{...props}
|
| 30 |
-
/>
|
| 31 |
-
))
|
| 32 |
-
CardHeader.displayName = "CardHeader"
|
| 33 |
-
|
| 34 |
-
const CardTitle = React.forwardRef<
|
| 35 |
-
React.ElementRef<"h3">, // Corrected to h3 to match the element type
|
| 36 |
-
React.ComponentPropsWithoutRef<"h3">
|
| 37 |
-
>(({ className, ...props }, ref) => (
|
| 38 |
-
<h3
|
| 39 |
-
ref={ref}
|
| 40 |
-
className={cn(
|
| 41 |
-
"text-2xl font-semibold leading-none tracking-tight",
|
| 42 |
-
className,
|
| 43 |
-
)}
|
| 44 |
-
{...props}
|
| 45 |
-
/>
|
| 46 |
-
))
|
| 47 |
-
CardTitle.displayName = "CardTitle"
|
| 48 |
-
|
| 49 |
-
const CardDescription = React.forwardRef<
|
| 50 |
-
React.ElementRef<"p">,
|
| 51 |
-
React.ComponentPropsWithoutRef<"p">
|
| 52 |
-
>(({ className, ...props }, ref) => (
|
| 53 |
-
<p
|
| 54 |
-
ref={ref}
|
| 55 |
-
className={cn("text-sm text-muted-foreground", className)}
|
| 56 |
-
{...props}
|
| 57 |
-
/>
|
| 58 |
-
))
|
| 59 |
-
CardDescription.displayName = "CardDescription"
|
| 60 |
-
|
| 61 |
-
const CardContent = React.forwardRef<
|
| 62 |
-
React.ElementRef<"div">,
|
| 63 |
-
React.ComponentPropsWithoutRef<"div">
|
| 64 |
-
>(({ className, ...props }, ref) => (
|
| 65 |
-
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
| 66 |
-
))
|
| 67 |
-
CardContent.displayName = "CardContent"
|
| 68 |
-
|
| 69 |
-
const CardFooter = React.forwardRef<
|
| 70 |
-
React.ElementRef<"div">,
|
| 71 |
-
React.ComponentPropsWithoutRef<"div">
|
| 72 |
-
>(({ className, ...props }, ref) => (
|
| 73 |
-
<div
|
| 74 |
-
ref={ref}
|
| 75 |
-
className={cn("flex items-center p-6 pt-0", className)}
|
| 76 |
-
{...props}
|
| 77 |
-
/>
|
| 78 |
-
))
|
| 79 |
-
CardFooter.displayName = "CardFooter"
|
| 80 |
-
|
| 81 |
-
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Frontend/src/pages/dashboard.tsx
CHANGED
|
@@ -1,14 +1,112 @@
|
|
| 1 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
const Dashboard: React.FC = () => {
|
| 4 |
return (
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
</div>
|
| 11 |
);
|
| 12 |
};
|
| 13 |
|
| 14 |
-
export default Dashboard;
|
|
|
|
| 1 |
+
import YearlyStreak from "../components/dashboard/YearlyStreak";
|
| 2 |
+
import FeedbackScore from "../components/dashboard/FeedBackScore";
|
| 3 |
+
import SkillRadarChart from "../components/dashboard/SkillRadarChart";
|
| 4 |
+
import WeakAreaBanner from "../components/dashboard/WeakAreaBanner";
|
| 5 |
+
import InterviewPlayback from "../components/dashboard/InterviewPlayback";
|
| 6 |
+
import { generateYearlyStreakData } from "../utils/generateYearlyStreakData";
|
| 7 |
+
|
| 8 |
+
const Dashboard = () => {
|
| 9 |
+
const streakData = generateYearlyStreakData();
|
| 10 |
+
|
| 11 |
+
const radarData = [
|
| 12 |
+
{ skill: "DSA", value: 70 },
|
| 13 |
+
{ skill: "System Design", value: 60 },
|
| 14 |
+
{ skill: "Communication", value: 85 },
|
| 15 |
+
{ skill: "Problem Solving", value: 75 },
|
| 16 |
+
{ skill: "Accuracy", value: 68 },
|
| 17 |
+
{ skill: "Time Mgmt", value: 80 },
|
| 18 |
+
];
|
| 19 |
+
|
| 20 |
+
const weakTopic = "Dynamic Programming";
|
| 21 |
|
|
|
|
| 22 |
return (
|
| 23 |
+
// PRIMARY CHANGE: Background Gradient inspired by landing page
|
| 24 |
+
// Using a custom CSS class for a more complex gradient if needed, or approximating with Tailwind.
|
| 25 |
+
// For now, let's use a subtle linear gradient that implies the dark blue-black.
|
| 26 |
+
<div className="px-6 py-8 space-y-10 min-h-screen text-gray-100 bg-linear-to-br from-[#0a0e1b] via-[#100d27] to-[#0a0e1b] font-sans">
|
| 27 |
+
{/* Font sans is a good default for modern look */}
|
| 28 |
+
|
| 29 |
+
{/* ----------- HEADER SECTION (Updated for new theme) ----------- */}
|
| 30 |
+
<div className="flex flex-col md:flex-row md:items-center justify-between mb-4">
|
| 31 |
+
<h1 className="text-3xl lg:text-4xl font-extrabold text-gray-50 tracking-tight">
|
| 32 |
+
👋 Welcome back, <span className="text-blue-400">Prakhar</span>
|
| 33 |
+
</h1>
|
| 34 |
+
|
| 35 |
+
<div className="flex items-center space-x-3 mt-4 md:mt-0">
|
| 36 |
+
{/* PRIMARY BUTTON: Vibrant Purple Theme Color, matching "Start Free Trial" */}
|
| 37 |
+
<button className="px-6 py-2 bg-gradient-to-r from-blue-600 to-blue-800 text-white rounded-lg shadow-lg shadow-purple-500/30 hover:from-blue-500 hover:to-blue-700 transition-all duration-300 ease-in-out font-semibold">
|
| 38 |
+
Start Interview
|
| 39 |
+
</button>
|
| 40 |
+
</div>
|
| 41 |
+
</div>
|
| 42 |
+
|
| 43 |
+
{/* ----------- GRID MAIN LAYOUT (2 COLUMNS for top content) ----------- */}
|
| 44 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
| 45 |
+
|
| 46 |
+
{/* LEFT PANEL (Feedback Score) */}
|
| 47 |
+
<div className="space-y-6 col-span-1">
|
| 48 |
+
{/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
|
| 49 |
+
<div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 h-full">
|
| 50 |
+
<h2 className="text-xl font-bold mb-4 text-gray-50">AI Feedback Score</h2>
|
| 51 |
+
<FeedbackScore
|
| 52 |
+
confidence={78}
|
| 53 |
+
clarity={82}
|
| 54 |
+
accuracy={70}
|
| 55 |
+
speed={65}
|
| 56 |
+
improvements={[
|
| 57 |
+
"Improve explanation clarity",
|
| 58 |
+
"Practice more DP problems",
|
| 59 |
+
"Reduce filler words in answers",
|
| 60 |
+
]}
|
| 61 |
+
/>
|
| 62 |
+
</div>
|
| 63 |
+
</div>
|
| 64 |
+
|
| 65 |
+
{/* RIGHT PANEL (Skill Chart) */}
|
| 66 |
+
<div className="space-y-6 col-span-1">
|
| 67 |
+
{/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
|
| 68 |
+
<div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 h-full">
|
| 69 |
+
<h2 className="text-xl font-bold mb-4 text-gray-50">Skill Strength Chart</h2>
|
| 70 |
+
<SkillRadarChart data={radarData} />
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
</div>
|
| 74 |
+
|
| 75 |
+
{/* ----------- MIDDLE ROW: INTERVIEW PLAYBACK (LEFT) AND WEAK AREA (RIGHT) ----------- */}
|
| 76 |
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 77 |
+
|
| 78 |
+
{/* INTERVIEW PLAYBACK (2/3 width on large screens, LEFT) */}
|
| 79 |
+
{/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
|
| 80 |
+
<div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 lg:col-span-2">
|
| 81 |
+
<h2 className="text-xl font-bold mb-4 text-gray-50">Interview Playback AI Feedback</h2>
|
| 82 |
+
<InterviewPlayback
|
| 83 |
+
audioUrl="https://example.com/audio.mp3"
|
| 84 |
+
transcript={`Interviewer: Explain polymorphism.\nYou: Polymorphism means...`}
|
| 85 |
+
highlights={[
|
| 86 |
+
"Answer lacked real-world example",
|
| 87 |
+
"Need more clarity in describing LLD concepts",
|
| 88 |
+
"Example Interview Playback",
|
| 89 |
+
]}
|
| 90 |
+
/>
|
| 91 |
+
</div>
|
| 92 |
+
|
| 93 |
+
{/* WEAK AREA (1/3 width on large screens, RIGHT) */}
|
| 94 |
+
{/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
|
| 95 |
+
<div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-5 border border-gray-700/50 col-span-1 flex-col items-center justify-center">
|
| 96 |
+
{/* WeakAreaBanner will need internal styling adjustments for its alert nature */}
|
| 97 |
+
<h2 className="text-xl font-bold mb-4 text-gray-50">WeakAreaBanner</h2>
|
| 98 |
+
<WeakAreaBanner topic={weakTopic} />
|
| 99 |
+
</div>
|
| 100 |
+
</div>
|
| 101 |
+
|
| 102 |
+
{/* ----------- BOTTOM ROW: YEARLY STREAK (FULL WIDTH) ----------- */}
|
| 103 |
+
{/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
|
| 104 |
+
<div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50">
|
| 105 |
+
<h2 className="text-xl font-bold mb-3 text-gray-50">Yearly Streak</h2>
|
| 106 |
+
<YearlyStreak data={streakData} />
|
| 107 |
+
</div>
|
| 108 |
</div>
|
| 109 |
);
|
| 110 |
};
|
| 111 |
|
| 112 |
+
export default Dashboard;
|
Frontend/src/pages/home.tsx
CHANGED
|
@@ -200,7 +200,7 @@ const AIInterviewPlatform: React.FC<AIInterviewPlatformProps> = ({ onLogin }) =>
|
|
| 200 |
</AuthModal>
|
| 201 |
|
| 202 |
{/* Hero Section */}
|
| 203 |
-
<section ref={heroRef} id="home" className="min-h-[calc(100vh-68px)] flex items-center pt- pb-20 px-4 sm:px-6 lg:px-8 relative overflow-hidden bg-black">
|
| 204 |
{/* Spotlight applied directly to the container as per the demo structure */}
|
| 205 |
<Spotlight parentRef={heroRef} color="#4b9fff" className="mix-blend-screen" />
|
| 206 |
<div className="max-w-7xl mx-auto w-full relative z-10">
|
|
|
|
| 200 |
</AuthModal>
|
| 201 |
|
| 202 |
{/* Hero Section */}
|
| 203 |
+
<section ref={heroRef} id="home" className="min-h-[calc(100vh-68px)] flex items-center pt-20 pb-20 px-4 sm:px-6 lg:px-8 relative overflow-hidden bg-black">
|
| 204 |
{/* Spotlight applied directly to the container as per the demo structure */}
|
| 205 |
<Spotlight parentRef={heroRef} color="#4b9fff" className="mix-blend-screen" />
|
| 206 |
<div className="max-w-7xl mx-auto w-full relative z-10">
|
Frontend/src/pages/quize.tsx
CHANGED
|
@@ -1,121 +1,125 @@
|
|
| 1 |
import React from "react";
|
| 2 |
-
import { FileText,
|
| 3 |
|
|
|
|
| 4 |
const ResumeGeneratedQuize: React.FC = () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
return (
|
| 6 |
<div className="min-h-screen bg-black text-white py-20 px-6 lg:px-12">
|
| 7 |
|
| 8 |
{/* Page Title */}
|
| 9 |
-
<h1 className="text-4xl font-bold mb-
|
| 10 |
Smart AI-Powered Quiz Generator
|
| 11 |
</h1>
|
| 12 |
|
| 13 |
-
{/* =====
|
| 14 |
-
<div className="grid grid-cols-1
|
| 15 |
-
|
| 16 |
-
{/*
|
| 17 |
-
<div
|
| 18 |
-
<
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
</div>
|
| 22 |
-
<p className="text-gray-300">
|
| 23 |
-
Create intelligent quizzes using AI-generated questions tailored to your learning needs.
|
| 24 |
-
</p>
|
| 25 |
</div>
|
| 26 |
|
| 27 |
-
{/* Resume Based Quiz */}
|
| 28 |
-
<div className="p-6 bg-slate-900/60 rounded-2xl shadow-xl border border-slate-800 hover:bg-slate-800/70 transition">
|
| 29 |
-
<div className="flex items-center gap-3 mb-4">
|
| 30 |
-
<FileSpreadsheet className="w-8 h-8 text-blue-400" />
|
| 31 |
-
<h2 className="text-2xl font-bold">Resume-Based Quiz</h2>
|
| 32 |
-
</div>
|
| 33 |
-
<p className="text-gray-300">
|
| 34 |
-
Upload your resume and get customized quizzes based on your skills & experiences.
|
| 35 |
-
</p>
|
| 36 |
-
</div>
|
| 37 |
|
| 38 |
-
{/*
|
| 39 |
-
<div className="
|
| 40 |
-
<
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
</div>
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
</p>
|
| 47 |
</div>
|
| 48 |
|
| 49 |
</div>
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
{/*
|
| 57 |
-
<
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
<QuizTypeCard
|
| 79 |
-
icon={<Edit3 className="w-10 h-10 text-blue-300" />}
|
| 80 |
-
title="Writing Quiz"
|
| 81 |
-
desc="Subjective, long-form answers graded by AI."
|
| 82 |
-
/>
|
| 83 |
|
| 84 |
</div>
|
| 85 |
</div>
|
| 86 |
);
|
| 87 |
};
|
| 88 |
|
| 89 |
-
export default ResumeGeneratedQuize;
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
/* ===== Reusable Quiz Card Component ===== */
|
| 93 |
-
|
| 94 |
-
const QuizTypeCard = ({
|
| 95 |
-
icon,
|
| 96 |
-
title,
|
| 97 |
-
desc,
|
| 98 |
-
}: {
|
| 99 |
-
icon: React.ReactNode;
|
| 100 |
-
title: string;
|
| 101 |
-
desc: string;
|
| 102 |
-
}) => {
|
| 103 |
-
return (
|
| 104 |
-
<div className="p-6 bg-slate-900/60 rounded-2xl shadow-xl border border-slate-800 hover:bg-slate-800/70 transition flex flex-col items-start gap-3">
|
| 105 |
-
{icon}
|
| 106 |
-
<h3 className="text-xl font-semibold">{title}</h3>
|
| 107 |
-
<p className="text-gray-400">{desc}</p>
|
| 108 |
-
|
| 109 |
-
<button
|
| 110 |
-
className="
|
| 111 |
-
mt-4 px-4 py-2 rounded-lg
|
| 112 |
-
bg-gradient-to-r from-blue-600 to-purple-600
|
| 113 |
-
hover:from-blue-700 hover:to-purple-700
|
| 114 |
-
font-medium transition shadow-lg
|
| 115 |
-
"
|
| 116 |
-
>
|
| 117 |
-
Start Quiz
|
| 118 |
-
</button>
|
| 119 |
-
</div>
|
| 120 |
-
);
|
| 121 |
-
};
|
|
|
|
| 1 |
import React from "react";
|
| 2 |
+
import { FileText, FileSpreadsheet, Code2, ListChecks, UploadCloud, Type } from "lucide-react";
|
| 3 |
|
| 4 |
+
// The structure of this component is heavily modified to meet the new layout requirements.
|
| 5 |
const ResumeGeneratedQuize: React.FC = () => {
|
| 6 |
+
|
| 7 |
+
// Consistent purple button style
|
| 8 |
+
const buttonClass = "w-full py-3 rounded-lg bg-gradient-to-r from-purple-500 to-purple-700 hover:from-purple-400 hover:to-purple-600 font-medium transition shadow-lg shadow-purple-500/30 text-white mt-4";
|
| 9 |
+
|
| 10 |
+
const OutputTypeOption = ({ icon, title, desc }: { icon: React.ReactNode; title: string; desc: string }) => (
|
| 11 |
+
// These cards inherently take full width of their parent container (which is now the right column)
|
| 12 |
+
<div className="p-4 bg-slate-900/50 rounded-xl border border-slate-700 hover:bg-slate-800/60 transition cursor-pointer">
|
| 13 |
+
<div className="flex items-center gap-3 mb-2">
|
| 14 |
+
{icon}
|
| 15 |
+
<h4 className="text-xl font-semibold text-gray-50">{title}</h4>
|
| 16 |
+
</div>
|
| 17 |
+
<p className="text-gray-400 text-sm">{desc}</p>
|
| 18 |
+
</div>
|
| 19 |
+
);
|
| 20 |
+
|
| 21 |
+
const SourceCard = ({ icon, title, desc, actionText }: { icon: React.ReactNode; title: string; desc: string; actionText: string }) => (
|
| 22 |
+
<div className="p-6 bg-slate-900/60 rounded-2xl shadow-xl border border-slate-700 hover:bg-slate-800/70 transition flex flex-col h-full">
|
| 23 |
+
<div className="flex items-start gap-4 mb-4">
|
| 24 |
+
{icon}
|
| 25 |
+
<div>
|
| 26 |
+
<h2 className="text-2xl font-bold">{title}</h2>
|
| 27 |
+
<p className="text-gray-400 mt-1 text-sm">{desc}</p>
|
| 28 |
+
</div>
|
| 29 |
+
</div>
|
| 30 |
+
{/* The SourceCard button width is intentionally set to w-fit px-6 to be narrower */}
|
| 31 |
+
<button className={buttonClass.replace('w-full', 'w-fit px-6')} >
|
| 32 |
+
{actionText}
|
| 33 |
+
</button>
|
| 34 |
+
</div>
|
| 35 |
+
);
|
| 36 |
+
|
| 37 |
return (
|
| 38 |
<div className="min-h-screen bg-black text-white py-20 px-6 lg:px-12">
|
| 39 |
|
| 40 |
{/* Page Title */}
|
| 41 |
+
<h1 className="text-4xl font-bold mb-16 text-center">
|
| 42 |
Smart AI-Powered Quiz Generator
|
| 43 |
</h1>
|
| 44 |
|
| 45 |
+
{/* ===== MAIN TWO-COLUMN LAYOUT (Source Selection vs. Configuration) ===== */}
|
| 46 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
|
| 47 |
+
|
| 48 |
+
{/* --- LEFT SIDE: INPUT SOURCE SELECTION --- */}
|
| 49 |
+
<div>
|
| 50 |
+
<h3 className="text-3xl font-bold mb-6 text-gray-100 border-b border-purple-700 pb-2">
|
| 51 |
+
1. Select Quiz Source
|
| 52 |
+
</h3>
|
| 53 |
+
<div className="space-y-8">
|
| 54 |
+
{/* Consolidated Resume/Note PDF Upload Card */}
|
| 55 |
+
<SourceCard
|
| 56 |
+
icon={<FileSpreadsheet className="w-8 h-8 text-cyan-400" />}
|
| 57 |
+
title="Resume/Note PDF Upload"
|
| 58 |
+
desc="Generate quizzes based on skills and experience listed in your resume file."
|
| 59 |
+
actionText="Upload"
|
| 60 |
+
/>
|
| 61 |
</div>
|
|
|
|
|
|
|
|
|
|
| 62 |
</div>
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
+
{/* --- RIGHT SIDE: PROMPT & OUTPUT CONFIGURATION (The full width section) --- */}
|
| 66 |
+
<div className="lg:sticky lg:top-8 self-start">
|
| 67 |
+
<h3 className="text-3xl font-bold mb-6 text-gray-100 border-b border-purple-700 pb-2">
|
| 68 |
+
2. Configure & Generate
|
| 69 |
+
</h3>
|
| 70 |
+
|
| 71 |
+
{/* Prompt/Text Area Section */}
|
| 72 |
+
<div className="bg-slate-900/60 rounded-2xl shadow-2xl p-6 border border-slate-800 mb-8">
|
| 73 |
+
<label htmlFor="prompt-area" className="text-lg font-semibold block mb-3 text-gray-200">
|
| 74 |
+
Custom Prompt/Instructions (Optional)
|
| 75 |
+
</label>
|
| 76 |
+
<textarea
|
| 77 |
+
id="prompt-area"
|
| 78 |
+
rows={4}
|
| 79 |
+
placeholder="e.g., 'Focus only on Python and OOP concepts' or 'Generate a quiz on the content uploaded in step 1'"
|
| 80 |
+
className="w-full p-3 rounded-lg bg-black/40 border border-slate-700 text-gray-100 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 transition"
|
| 81 |
+
></textarea>
|
| 82 |
+
<p className="text-gray-500 text-sm mt-2">
|
| 83 |
+
This prompt refines the quiz generation based on the selected source.
|
| 84 |
+
</p>
|
| 85 |
</div>
|
| 86 |
+
|
| 87 |
+
{/* Output Type Section - NOW CORRECTLY PLACED INSIDE THE RIGHT COLUMN */}
|
|
|
|
| 88 |
</div>
|
| 89 |
|
| 90 |
</div>
|
| 91 |
|
| 92 |
+
<div className="lg:sticky lg:top-8 self-start">
|
| 93 |
+
<h4 className="text-2xl font-semibold mb-4 text-gray-200">
|
| 94 |
+
Choose Output Type:
|
| 95 |
+
</h4>
|
| 96 |
+
|
| 97 |
+
{/* NEW: Use grid-cols-2 and gap-4 to place the options side-by-side */}
|
| 98 |
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
| 99 |
+
|
| 100 |
+
{/* MCQ Quiz Option - takes full width of its column */}
|
| 101 |
+
<OutputTypeOption
|
| 102 |
+
icon={<ListChecks className="w-6 h-6 text-purple-400" />}
|
| 103 |
+
title="Multiple Choice Quiz (MCQ)"
|
| 104 |
+
desc="Ideal for quick assessment of knowledge and comprehension."
|
| 105 |
+
/>
|
| 106 |
+
|
| 107 |
+
{/* Coding Quiz Option - takes full width of its column */}
|
| 108 |
+
<OutputTypeOption
|
| 109 |
+
icon={<Code2 className="w-6 h-6 text-green-400" />}
|
| 110 |
+
title="Coding Challenge Quiz"
|
| 111 |
+
desc="Generates problems requiring code snippets or full functions for evaluation."
|
| 112 |
+
/>
|
| 113 |
+
</div>
|
| 114 |
+
|
| 115 |
+
{/* Main Generation Button - Full width (w-full is in buttonClass) */}
|
| 116 |
+
<button className={buttonClass + ' text-xl mt-8'}>
|
| 117 |
+
Generate Quiz Now
|
| 118 |
+
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
|
| 120 |
</div>
|
| 121 |
</div>
|
| 122 |
);
|
| 123 |
};
|
| 124 |
|
| 125 |
+
export default ResumeGeneratedQuize;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Frontend/src/utils/generateYearlyStreakData.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import dayjs from "dayjs";
|
| 2 |
+
|
| 3 |
+
export const generateYearlyStreakData = () => {
|
| 4 |
+
const today = dayjs();
|
| 5 |
+
const days = [];
|
| 6 |
+
|
| 7 |
+
for (let i = 0; i < 365; i++) {
|
| 8 |
+
const date = today.subtract(i, "day");
|
| 9 |
+
|
| 10 |
+
days.push({
|
| 11 |
+
date: date.format("YYYY-MM-DD"),
|
| 12 |
+
count: Math.floor(Math.random() * 4), // 0–3 activity
|
| 13 |
+
weekday: date.day(),
|
| 14 |
+
week: Math.floor(i / 7),
|
| 15 |
+
month: date.format("MMM"),
|
| 16 |
+
});
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
return days.reverse();
|
| 20 |
+
};
|