From ba37f19b459fd66e47bb3871c6ae8baba5d18896 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Thu, 26 Mar 2026 04:28:08 -0600 Subject: [PATCH] feat(stats): add user analytics charts and stabilize ECharts theme --- client/package.json | 20 +- client/src/App.vue | 22 +- .../features/statistics/api/statistics.api.ts | 28 ++ .../statistics/components/StatisticsGrid.vue | 54 ++-- .../statistics/components/StatisticsPage.vue | 64 ++++- .../{ => library}/BooksAddedOverTimeChart.vue | 10 +- .../{ => library}/FormatDistributionChart.vue | 8 +- .../FormatShareOverTimeChart.vue | 6 +- .../library/GenreCooccurrenceChart.vue | 56 ++++ .../{ => library}/GenreDistributionChart.vue | 8 +- .../{ => library}/GenreRankOverTimeChart.vue | 9 +- .../LanguageDistributionChart.vue | 8 +- ...ibraryMetadataCompletenessHeatmapChart.vue | 9 +- .../MetadataCompletenessChart.vue | 8 +- .../MetadataScoreDistributionChart.vue | 7 +- .../PageCountDistributionChart.vue | 7 +- .../{ => library}/PublicationDecadeChart.vue | 8 +- .../{ => library}/StorageByFormatChart.vue | 8 +- .../{ => library}/TopAuthorsChart.vue | 8 +- .../components/user/BooksCompletedChart.vue | 80 ++++++ .../{ => user}/CompletionLatencyChart.vue | 8 +- .../{ => user}/CompletionTimelineChart.vue | 8 +- .../{ => user}/FavoriteReadingDaysChart.vue | 8 +- .../user/GenreReadingTimeTreemapChart.vue | 75 ++++++ .../{ => user}/GoalTrajectoryChart.vue | 10 +- .../{ => user}/PeakReadingHoursChart.vue | 8 +- .../{ => user}/ProgressFunnelChart.vue | 12 +- .../components/user/ReadingClockChart.vue | 107 ++++++++ .../{ => user}/ReadingHeatmapChart.vue | 9 +- .../user/ReadingPaceScatterChart.vue | 68 +++++ .../user/SessionArchetypesChart.vue | 88 +++++++ .../composables/useGenreCooccurrence.ts | 13 + .../composables/useStatisticsConfig.ts | 41 ++- .../composables/useUserBooksCompleted.ts | 13 + .../composables/useUserGenreReadingTime.ts | 13 + .../composables/useUserReadingPace.ts | 13 + .../composables/useUserSessionArchetypes.ts | 13 + .../statistics/statistics-chart-meta.ts | 73 +++++- client/src/lib/echarts.ts | 134 ++++++++-- packages/types/src/statistics.ts | 50 +++- packages/types/src/user-statistics.ts | 51 ++++ scripts/seed/reading-sessions.sh | 140 ++++++++++ .../statistics/statistics.controller.ts | 5 + .../statistics/statistics.repository.ts | 48 +++- .../modules/statistics/statistics.service.ts | 5 + .../user-statistics-aggregation.job.ts | 4 +- .../user-statistics.controller.ts | 30 +++ .../user-statistics.repository.ts | 241 +++++++++++++++++- .../user-statistics.service.ts | 85 ++++++ 49 files changed, 1574 insertions(+), 227 deletions(-) rename client/src/features/statistics/components/{ => library}/BooksAddedOverTimeChart.vue (92%) rename client/src/features/statistics/components/{ => library}/FormatDistributionChart.vue (82%) rename client/src/features/statistics/components/{ => library}/FormatShareOverTimeChart.vue (95%) create mode 100644 client/src/features/statistics/components/library/GenreCooccurrenceChart.vue rename client/src/features/statistics/components/{ => library}/GenreDistributionChart.vue (86%) rename client/src/features/statistics/components/{ => library}/GenreRankOverTimeChart.vue (93%) rename client/src/features/statistics/components/{ => library}/LanguageDistributionChart.vue (82%) rename client/src/features/statistics/components/{ => library}/LibraryMetadataCompletenessHeatmapChart.vue (93%) rename client/src/features/statistics/components/{ => library}/MetadataCompletenessChart.vue (87%) rename client/src/features/statistics/components/{ => library}/MetadataScoreDistributionChart.vue (91%) rename client/src/features/statistics/components/{ => library}/PageCountDistributionChart.vue (88%) rename client/src/features/statistics/components/{ => library}/PublicationDecadeChart.vue (86%) rename client/src/features/statistics/components/{ => library}/StorageByFormatChart.vue (88%) rename client/src/features/statistics/components/{ => library}/TopAuthorsChart.vue (86%) create mode 100644 client/src/features/statistics/components/user/BooksCompletedChart.vue rename client/src/features/statistics/components/{ => user}/CompletionLatencyChart.vue (92%) rename client/src/features/statistics/components/{ => user}/CompletionTimelineChart.vue (90%) rename client/src/features/statistics/components/{ => user}/FavoriteReadingDaysChart.vue (93%) create mode 100644 client/src/features/statistics/components/user/GenreReadingTimeTreemapChart.vue rename client/src/features/statistics/components/{ => user}/GoalTrajectoryChart.vue (91%) rename client/src/features/statistics/components/{ => user}/PeakReadingHoursChart.vue (90%) rename client/src/features/statistics/components/{ => user}/ProgressFunnelChart.vue (96%) create mode 100644 client/src/features/statistics/components/user/ReadingClockChart.vue rename client/src/features/statistics/components/{ => user}/ReadingHeatmapChart.vue (95%) create mode 100644 client/src/features/statistics/components/user/ReadingPaceScatterChart.vue create mode 100644 client/src/features/statistics/components/user/SessionArchetypesChart.vue create mode 100644 client/src/features/statistics/composables/useGenreCooccurrence.ts create mode 100644 client/src/features/statistics/composables/useUserBooksCompleted.ts create mode 100644 client/src/features/statistics/composables/useUserGenreReadingTime.ts create mode 100644 client/src/features/statistics/composables/useUserReadingPace.ts create mode 100644 client/src/features/statistics/composables/useUserSessionArchetypes.ts create mode 100755 scripts/seed/reading-sessions.sh diff --git a/client/package.json b/client/package.json index f7c43364e..3483a0b85 100644 --- a/client/package.json +++ b/client/package.json @@ -33,16 +33,16 @@ "clsx": "^2.1.1", "echarts": "^6.0.0", "howler": "^2.2.4", - "lucide-vue-next": "^0.577.0", + "lucide-vue-next": "^1.0.0", "pdfjs-dist": "^5.5.207", "pinia": "^3.0.4", "reka-ui": "^2.9.2", "socket.io-client": "^4.8.3", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.2.2", - "vue": "^3.5.30", + "vue": "^3.5.31", "vue-draggable-plus": "^0.6.1", - "vue-echarts": "^8.0.1", + "vue-echarts": "8.1.0-beta.2", "vue-router": "^5.0.4", "vue-sonner": "^2.0.9", "vue-virtual-scroller": "^1.1.2" @@ -52,25 +52,25 @@ "@types/jsdom": "^28.0.1", "@types/node": "^25.5.0", "@vitejs/plugin-vue": "^6.0.5", - "@vitest/coverage-v8": "^4.1.0", + "@vitest/coverage-v8": "^4.1.1", "@vitest/eslint-plugin": "^1.6.13", "@vue/eslint-config-typescript": "^14.7.0", "@vue/test-utils": "^2.4.6", - "@vue/tsconfig": "^0.9.0", + "@vue/tsconfig": "^0.9.1", "eslint": "^10.1.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-oxlint": "~1.56.0", + "eslint-plugin-oxlint": "~1.57.0", "eslint-plugin-vue": "~10.8.0", "jiti": "^2.6.1", "jsdom": "^29.0.1", "npm-run-all2": "^8.0.4", - "oxlint": "~1.56.0", + "oxlint": "~1.57.0", "prettier": "3.8.1", "tw-animate-css": "^1.4.0", "typescript": "~5.9.3", - "vite": "^8.0.1", - "vite-plugin-vue-devtools": "^8.1.0", - "vitest": "^4.1.0", + "vite": "^8.0.2", + "vite-plugin-vue-devtools": "^8.1.1", + "vitest": "^4.1.1", "vue-tsc": "^3.2.6" }, "engines": { diff --git a/client/src/App.vue b/client/src/App.vue index 413768c88..5933b9b4d 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -1,33 +1,23 @@