diff options
Diffstat (limited to 'fe/src/lib/DataView.svelte')
-rw-r--r-- | fe/src/lib/DataView.svelte | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte new file mode 100644 index 0000000..ffc2fe8 --- /dev/null +++ b/fe/src/lib/DataView.svelte | |||
@@ -0,0 +1,228 @@ | |||
1 | <script lang="ts"> | ||
2 | import { onDestroy, onMount } from "svelte"; | ||
3 | import http from "../http"; | ||
4 | import { token } from "../stores/auth"; | ||
5 | import { addFormOpen } from "../stores/forms"; | ||
6 | import Table from "./Table.svelte"; | ||
7 | import ChartJS from "chart.js/auto"; | ||
8 | import Chart from './Chart.svelte' | ||
9 | import Card from "./Card.svelte"; | ||
10 | import Column from "./Column.svelte"; | ||
11 | import AddForm from "./forms/AddForm.svelte"; | ||
12 | import { apiURL } from "../utils"; | ||
13 | |||
14 | let json: Promise<any>; | ||
15 | |||
16 | let barCanvasRef: HTMLCanvasElement; | ||
17 | let lineCanvasRef: HTMLCanvasElement; | ||
18 | let barChart: any; | ||
19 | let lineChart: any; | ||
20 | |||
21 | let lastSevenDays: string[]; | ||
22 | let lastSevenDaysData: number[]; | ||
23 | |||
24 | let userTotalsLabels: string[]; | ||
25 | let userTotalsData: number[]; | ||
26 | |||
27 | async function fetchData() { | ||
28 | const res = await fetch(apiURL("stats"), { | ||
29 | method: "GET", | ||
30 | headers: { | ||
31 | Authorization: `Bearer ${$token}` | ||
32 | } | ||
33 | }); | ||
34 | if (res.ok) { | ||
35 | json = res.json(); | ||
36 | } else { | ||
37 | throw new Error("There was a problem with your request"); | ||
38 | } | ||
39 | } | ||
40 | |||
41 | async function fetchDailyUserStatistics() { | ||
42 | const res = await fetch(apiURL("stats/daily"), { | ||
43 | method: "GET", | ||
44 | headers: { | ||
45 | Authorization: `Bearer ${$token}` | ||
46 | } | ||
47 | }); | ||
48 | |||
49 | if (res.ok) { | ||
50 | const json = await res.json(); | ||
51 | let labels = json.map((d: any) => d.name); | ||
52 | let data = json.map((d: any) => d.total); | ||
53 | return [labels, data]; | ||
54 | } else { | ||
55 | throw new Error("There was a problem with your request"); | ||
56 | } | ||
57 | |||
58 | } | ||
59 | |||
60 | async function fetchWeeklyTotals() { | ||
61 | const res = await fetch(apiURL("stats/weekly"), { | ||
62 | method: "GET", | ||
63 | headers: { | ||
64 | Authorization: `Bearer ${$token}` | ||
65 | } | ||
66 | }); | ||
67 | |||
68 | if (res.ok) { | ||
69 | const json = await res.json(); | ||
70 | let labels = json.map((d: any) => d.date); | ||
71 | let data = json.map((d: any) => d.total); | ||
72 | return [labels, data]; | ||
73 | } else { | ||
74 | throw new Error("There was a problem with your request"); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | function closeDialog() { | ||
79 | addFormOpen.set(false); | ||
80 | } | ||
81 | |||
82 | function onStatisticAdd() { | ||
83 | closeDialog(); | ||
84 | fetchData(); | ||
85 | fetchWeeklyTotals().then(updateWeeklyTotalsChart).catch(err => console.error(err)); | ||
86 | fetchDailyUserStatistics().then(updateDailyUserTotalsChart).catch(err => console.error(err)); | ||
87 | } | ||
88 | |||
89 | function setupWeeklyTotalsChart(result: any) { | ||
90 | [lastSevenDays, lastSevenDaysData] = result; | ||
91 | lineChart = new ChartJS(lineCanvasRef, { | ||
92 | type: "line", | ||
93 | data: { | ||
94 | labels: lastSevenDays, | ||
95 | datasets: [ | ||
96 | { | ||
97 | label: "Totals", | ||
98 | data: lastSevenDaysData, | ||
99 | backgroundColor: "rgba(255, 192, 192, 0.2)" | ||
100 | } | ||
101 | ] | ||
102 | }, | ||
103 | options: { | ||
104 | responsive: true, | ||
105 | maintainAspectRatio: false, | ||
106 | scales: { | ||
107 | y: { | ||
108 | suggestedMax: 30, | ||
109 | beginAtZero: true, | ||
110 | ticks: { | ||
111 | autoSkip: true, | ||
112 | stepSize: 5 | ||
113 | } | ||
114 | } | ||
115 | }, | ||
116 | plugins: { | ||
117 | legend: { | ||
118 | display: false | ||
119 | }, | ||
120 | title: { | ||
121 | display: true, | ||
122 | text: "Weekly Breakdown" | ||
123 | }, | ||
124 | subtitle: { | ||
125 | display: true, | ||
126 | text: "Water consumption over the last week", | ||
127 | padding: {bottom: 10} | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | }); | ||
132 | } | ||
133 | |||
134 | function setupDailyUserTotalsChart(result: any) { | ||
135 | [userTotalsLabels, userTotalsData] = result; | ||
136 | |||
137 | barChart = new ChartJS(barCanvasRef, { | ||
138 | type: "bar", | ||
139 | data: { | ||
140 | labels: userTotalsLabels, | ||
141 | datasets: [ | ||
142 | { | ||
143 | data: userTotalsData, | ||
144 | backgroundColor: [ | ||
145 | "#330000", | ||
146 | "rgba(100, 200, 192, 0.2)" | ||
147 | ] | ||
148 | } | ||
149 | ] | ||
150 | }, | ||
151 | options: { | ||
152 | responsive: true, | ||
153 | maintainAspectRatio: false, | ||
154 | scales: { | ||
155 | y: { | ||
156 | beginAtZero: true, | ||
157 | suggestedMax: 10, | ||
158 | ticks: { | ||
159 | autoSkip: true, | ||
160 | stepSize: 1 | ||
161 | } | ||
162 | } | ||
163 | }, | ||
164 | plugins: { | ||
165 | legend: { | ||
166 | display: false | ||
167 | }, | ||
168 | title: { | ||
169 | display: true, | ||
170 | text: "Daily Total" | ||
171 | }, | ||
172 | subtitle: { | ||
173 | display: true, | ||
174 | text: "Water Drank Today", | ||
175 | padding: {bottom: 10} | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | }); | ||
180 | } | ||
181 | |||
182 | function updateWeeklyTotalsChart(result: any) { | ||
183 | [, lastSevenDaysData] = result; | ||
184 | lineChart.data.datasets[0].data = lastSevenDaysData; | ||
185 | lineChart.update(); | ||
186 | } | ||
187 | |||
188 | function updateDailyUserTotalsChart(result: any) { | ||
189 | [, userTotalsData] = result; | ||
190 | barChart.data.datasets[0].data = userTotalsData; | ||
191 | barChart.update(); | ||
192 | } | ||
193 | |||
194 | onMount(() => { | ||
195 | fetchData(); | ||
196 | fetchWeeklyTotals().then(setupWeeklyTotalsChart); | ||
197 | fetchDailyUserStatistics().then(setupDailyUserTotalsChart); | ||
198 | }); | ||
199 | |||
200 | onDestroy(() => { | ||
201 | if (barChart) barChart.destroy(); | ||
202 | if (lineChart) lineChart.destroy(); | ||
203 | barChart = null; | ||
204 | lineChart = null; | ||
205 | }); | ||
206 | </script> | ||
207 | |||
208 | <Column --width="500px"> | ||
209 | <Card --height="300px"> | ||
210 | <!--<Chart />--> | ||
211 | <canvas bind:this={barCanvasRef} /> | ||
212 | </Card> | ||
213 | <Card --height="300px"> | ||
214 | <canvas bind:this={lineCanvasRef} /> | ||
215 | </Card> | ||
216 | </Column> | ||
217 | |||
218 | <AddForm open={$addFormOpen} on:submit={onStatisticAdd} on:close={closeDialog} /> | ||
219 | <Column> | ||
220 | <Card> | ||
221 | {#await json then data} | ||
222 | <Table {data} nofooter /> | ||
223 | {:catch error} | ||
224 | <p>{error}</p> | ||
225 | {/await} | ||
226 | </Card> | ||
227 | </Column> | ||
228 | <!-- <Chart /> --> | ||