Skip to content

Commit 8b7368b

Browse files
committed
feat: add stats
1 parent 7e157b3 commit 8b7368b

File tree

13 files changed

+378
-2
lines changed

13 files changed

+378
-2
lines changed

src/jelu-ui/package-lock.json

+27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/jelu-ui/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
"@vueuse/core": "8.2.6",
2121
"@vueuse/router": "8.2.6",
2222
"axios": "0.26.1",
23+
"chart.js": "^3.7.1",
2324
"daisyui": "2.14.3",
2425
"dayjs": "1.11.0",
2526
"floating-vue": "^2.0.0-beta.15",
2627
"sweetalert2": "11.4.8",
2728
"theme-change": "^2.0.2",
2829
"vue": "3.2.33",
2930
"vue-avatar-sdh": "^1.0.3",
31+
"vue-chartjs": "^4.1.0",
3032
"vue-i18n": "^9.1.9",
3133
"vue-router": "4.0.14",
3234
"vuejs-sidebar-menu": "^1.0.0",

src/jelu-ui/src/components/AdminBase.vue

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const items = ref([{ name:t('settings.profile'), tooltip:t('settings.my_profile'
1919
{ name:t('settings.authors'), icon:"bxs-user-account", href:"/profile/admin/authors", tooltip: t('settings.author_management') },
2020
{ name:t('settings.imports'), icon:"bxs-file-plus", href:"/profile/imports", tooltip: t('settings.csv_import') },
2121
{ name:t('settings.messages'), icon:"bxs-message-alt-detail", href:"/profile/messages" },
22+
{ name:t('settings.stats'), icon:"bxs-chart", href:"/profile/stats", tooltip: t('settings.stats') },
2223
])
2324
2425
if (store.getters.isAdmin) {
+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<script setup lang="ts">
2+
import { useTitle } from '@vueuse/core';
3+
import { BarElement, CategoryScale, Chart as ChartJS, ChartData, Legend, LinearScale, Title, Tooltip } from 'chart.js';
4+
import dayjs from "dayjs";
5+
import { Ref, ref, watch } from "vue";
6+
import { Bar } from 'vue-chartjs';
7+
import { useI18n } from 'vue-i18n';
8+
import dataService from "../services/DataService";
9+
10+
const { t } = useI18n({
11+
inheritLocale: true,
12+
useScope: 'global'
13+
})
14+
15+
useTitle('Jelu | Stats')
16+
console.log(dayjs('2020-1-1').format('MMMM'))
17+
console.log(dayjs('2020-3-1').format('MMMM'))
18+
19+
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
20+
21+
const getYears = () => {
22+
dataService.yearsWithStats()
23+
.then(res => {
24+
years.value = res
25+
})
26+
.catch(e => {
27+
console.log(e)
28+
})
29+
30+
}
31+
32+
const getAllStats = () => {
33+
dataService.yearStats()
34+
.then(res => {
35+
let labels = res.map(r => r.year)
36+
37+
const updatedChartData = {
38+
labels: labels,
39+
datasets: [
40+
{
41+
label: 'finished',
42+
backgroundColor: '#bbbbbb',
43+
data: res.map(r => r.finished)
44+
},
45+
{
46+
label: 'dropped',
47+
backgroundColor: '#f87979',
48+
data: res.map(r => r.dropped)
49+
}
50+
]
51+
}
52+
chartData.value = { ...updatedChartData }
53+
})
54+
.catch(e => {
55+
console.log(e)
56+
})
57+
}
58+
59+
const getYearStats = () => {
60+
if (currentYear.value != null) {
61+
dataService.monthStatsForYear(currentYear.value)
62+
.then(res => {
63+
let labels = res.map(r => r.month).map(m => dayjs(`2020-${m}-1`).format('MMMM'))
64+
65+
const updatedChartData = {
66+
labels: labels,
67+
datasets: [
68+
{
69+
label: 'finished',
70+
backgroundColor: '#bbbbbb',
71+
data: res.map(r => r.finished)
72+
},
73+
{
74+
label: 'dropped',
75+
backgroundColor: '#f87979',
76+
data: res.map(r => r.dropped)
77+
}
78+
]
79+
}
80+
yearChartData.value = { ...updatedChartData }
81+
})
82+
.catch(e => {
83+
console.log(e)
84+
})
85+
}
86+
}
87+
88+
const loaded = ref(false)
89+
const chartData = ref<ChartData<'bar'>>({
90+
datasets: []
91+
})
92+
const yearChartData = ref<ChartData<'bar'>>({
93+
datasets: []
94+
})
95+
96+
const years: Ref<Array<number>> = ref([])
97+
const currentYear: Ref<number|null> = ref(null)
98+
99+
watch(currentYear, (newVal, oldVal) => {
100+
console.log("year " + newVal + " " + oldVal)
101+
getYearStats()
102+
103+
})
104+
105+
getAllStats()
106+
getYears()
107+
108+
</script>
109+
110+
<template>
111+
<div class="grid grid-cols-1 justify-center justify-items-center justify-self-center">
112+
<h1 class="text-2xl typewriter w-11/12 sm:w-8/12 pb-4 capitalize">
113+
{{ t('stats.all_time') }}
114+
</h1>
115+
<div class="">
116+
<Bar
117+
:chart-data="chartData"
118+
/>
119+
</div>
120+
<h1 class="text-2xl typewriter w-11/12 sm:w-8/12 py-4 capitalize">
121+
{{ t('stats.yearly_stats') }}
122+
</h1>
123+
<div v-if="years != null && years !== undefined && years.length > 0" class="">
124+
<select
125+
v-model="currentYear"
126+
class="select select-bordered select-accent pt-2 mb-4"
127+
>
128+
<option
129+
disabled
130+
selected
131+
>
132+
{{ t('stats.choose_year') }}
133+
</option>
134+
<option
135+
v-for="year in years"
136+
:key="year"
137+
:value="year"
138+
>
139+
{{ year }}
140+
</option>
141+
</select>
142+
<Bar
143+
:chart-data="yearChartData"
144+
/>
145+
</div>
146+
</div>
147+
</template>
148+
149+
<style scoped>
150+
151+
152+
</style>

src/jelu-ui/src/locales/en.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
"users_management" : "Users management",
103103
"shortcuts" : "Shortcuts",
104104
"shortcuts_tooltip" : "Keyboard shortcuts",
105-
"messages" : "Messages"
105+
"messages" : "Messages",
106+
"stats" : "Stats"
106107
},
107108
"user" : {
108109
"log_first" : "Please log in first"
@@ -244,5 +245,10 @@
244245
"user-messages" : {
245246
"link" : "link",
246247
"mark_read": "mark as read"
248+
},
249+
"stats" : {
250+
"all_time" : "All time stats",
251+
"yearly_stats" : "Yearly stats",
252+
"choose_year" : "Choose a year"
247253
}
248254
}

src/jelu-ui/src/locales/fr.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@
103103
"users_management" : "gestion des utilisateurs",
104104
"shortcuts" : "Raccourcis",
105105
"shortcuts_tooltip" : "Raccourcis claviers",
106-
"messages" : "Messages"
106+
"messages" : "Messages",
107+
"stats" : "Statistiques"
107108
},
108109
"user" : {
109110
"log_first" : "Veuillez vous identifier"
@@ -245,5 +246,10 @@
245246
"user-messages" : {
246247
"link" : "lien",
247248
"mark_read": "marquer comme lu"
249+
},
250+
"stats" : {
251+
"all_time" : "Données globales",
252+
"yearly_stats" : "Statistiques annuelles",
253+
"choose_year" : "Choisir une année"
248254
}
249255
}

src/jelu-ui/src/model/YearStats.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface YearStats {
2+
dropped: number,
3+
finished: number,
4+
year: number
5+
}
6+
7+
export interface MonthStats {
8+
dropped: number,
9+
finished: number,
10+
year: number,
11+
month: number
12+
}

src/jelu-ui/src/router.ts

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const router = createRouter({
9191
{ path: 'imports', component: () => import(/* webpackChunkName: "recommend" */ './components/Imports.vue')},
9292
{ path: 'settings', component: () => import(/* webpackChunkName: "recommend" */ './components/UserSettings.vue')},
9393
{ path: 'messages', component: () => import(/* webpackChunkName: "recommend" */ './components/UserMessages.vue')},
94+
{ path: 'stats', component: () => import(/* webpackChunkName: "recommend" */ './components/UserStats.vue')},
9495
]
9596
},
9697
],

src/jelu-ui/src/services/DataService.ts

+51
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { LibraryFilter } from "../model/LibraryFilter";
1616
import { WikipediaSearchResult } from "../model/WikipediaSearchResult";
1717
import { WikipediaPageResult } from "../model/WikipediaPageResult";
1818
import { MessageCategory, UpdateUserMessage, UserMessage } from "../model/UserMessage";
19+
import { MonthStats, YearStats } from "../model/YearStats";
1920

2021
class DataService {
2122

@@ -59,6 +60,8 @@ class DataService {
5960

6061
private API_USER_MESSAGES = '/user-messages';
6162

63+
private API_STATS = '/stats';
64+
6265
private MODE: string;
6366

6467
private BASE_URL: string;
@@ -978,6 +981,54 @@ class DataService {
978981
}
979982
}
980983

984+
yearStats = async () => {
985+
try {
986+
const response = await this.apiClient.get<Array<YearStats>>(`${this.API_STATS}`);
987+
console.log("called stats")
988+
console.log(response)
989+
return response.data;
990+
}
991+
catch (error) {
992+
if (axios.isAxiosError(error) && error.response) {
993+
console.log("error axios " + error.response.status + " " + error.response.data.error)
994+
}
995+
console.log("error stats " + (error as AxiosError).code)
996+
throw new Error("error stats " + error)
997+
}
998+
}
999+
1000+
monthStatsForYear = async (year: number) => {
1001+
try {
1002+
const response = await this.apiClient.get<Array<MonthStats>>(`${this.API_STATS}/${year}`);
1003+
console.log("called stats months")
1004+
console.log(response)
1005+
return response.data;
1006+
}
1007+
catch (error) {
1008+
if (axios.isAxiosError(error) && error.response) {
1009+
console.log("error axios " + error.response.status + " " + error.response.data.error)
1010+
}
1011+
console.log("error stats months " + (error as AxiosError).code)
1012+
throw new Error("error stats months " + error)
1013+
}
1014+
}
1015+
1016+
yearsWithStats = async () => {
1017+
try {
1018+
const response = await this.apiClient.get<Array<number>>(`${this.API_STATS}/years`);
1019+
console.log("called stats years")
1020+
console.log(response)
1021+
return response.data;
1022+
}
1023+
catch (error) {
1024+
if (axios.isAxiosError(error) && error.response) {
1025+
console.log("error axios " + error.response.status + " " + error.response.data.error)
1026+
}
1027+
console.log("error stats years " + (error as AxiosError).code)
1028+
throw new Error("error stats years " + error)
1029+
}
1030+
}
1031+
9811032
}
9821033

9831034

0 commit comments

Comments
 (0)