aboutsummaryrefslogtreecommitdiff
path: root/fe/src/lib
diff options
context:
space:
mode:
authorZach Berwaldt <zberwaldt@tutamail.com>2024-03-15 18:49:43 -0400
committerZach Berwaldt <zberwaldt@tutamail.com>2024-03-15 18:49:43 -0400
commit9cae9c1d2a0b4f7fa72f3075541b9ffafe1a7275 (patch)
tree960fa4f96a1328861a06d97180da8601af6855da /fe/src/lib
parent8fab2d03bce82e4dee798ebffb1e93c557f62a4b (diff)
Add routes for preference, clean up and add types
Diffstat (limited to 'fe/src/lib')
-rw-r--r--fe/src/lib/Card.svelte1
-rw-r--r--fe/src/lib/Chart.svelte63
-rw-r--r--fe/src/lib/DataView.svelte40
-rw-r--r--fe/src/lib/Layout.svelte8
-rw-r--r--fe/src/lib/LoginForm.svelte2
-rw-r--r--fe/src/lib/PreferencesForm.svelte145
-rw-r--r--fe/src/lib/errors.ts6
-rw-r--r--fe/src/lib/utils.ts2
8 files changed, 193 insertions, 74 deletions
diff --git a/fe/src/lib/Card.svelte b/fe/src/lib/Card.svelte
index d7cd900..cd1e02c 100644
--- a/fe/src/lib/Card.svelte
+++ b/fe/src/lib/Card.svelte
@@ -1,6 +1,5 @@
1<script lang="ts"> 1<script lang="ts">
2 export let title = ""; 2 export let title = "";
3 export let height: number | undefined = undefined;
4</script> 3</script>
5 4
6<div class="card"> 5<div class="card">
diff --git a/fe/src/lib/Chart.svelte b/fe/src/lib/Chart.svelte
new file mode 100644
index 0000000..b19d932
--- /dev/null
+++ b/fe/src/lib/Chart.svelte
@@ -0,0 +1,63 @@
1<script lang="ts">
2import { onDestroy } from "svelte";
3import ChartJS from "chart.js/auto";
4
5export let data;
6export let labels;
7export let type = 'bar';
8
9let ref: HTMLCanvasElement;
10let chart
11
12function setupChart(result) {
13 [labels, data] = result;
14 chart = new ChartJS(ref, {
15 type,
16 data: {
17 labels,
18 datasets: [
19 {
20 label: "Totals",
21 data,
22 backgroundColor: "rgba(255, 192, 192, 0.2)"
23 }
24 ]
25 },
26 options: {
27 responsive: true,
28 maintainAspectRatio: false,
29 scales: {
30 y: {
31 suggestedMax: 30,
32 beginAtZero: true,
33 ticks: {
34 autoSkip: true,
35 stepSize: 5
36 }
37 }
38 },
39 plugins: {
40 legend: {
41 display: false
42 },
43 title: {
44 display: true,
45 text: "Weekly Breakdown"
46 },
47 subtitle: {
48 display: true,
49 text: "Water consumption over the last week",
50 padding: {bottom: 10}
51 }
52 }
53 }
54 });
55
56 onDestroy(() => {
57 if (chart) chart.destroy();
58 chart = null;
59 })
60}
61</script>
62
63<canvas bind:this={ref} /> \ No newline at end of file
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 0a6b81b..5e81a5a 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,10 +1,11 @@
1<script lang="ts"> 1<script lang="ts">
2 import { onDestroy, onMount } from "svelte"; 2 import { onDestroy, onMount } from "svelte";
3 import HttpClient from "../http"; 3 import http from "../http";
4 import { token } from "../stores/auth"; 4 import { token } from "../stores/auth";
5 import { addFormOpen } from "../stores/forms"; 5 import { addFormOpen } from "../stores/forms";
6 import Table from "./Table.svelte"; 6 import Table from "./Table.svelte";
7 import Chart from "chart.js/auto"; 7 import ChartJS from "chart.js/auto";
8 import Chart from './Chart.svelte'
8 import Card from "./Card.svelte"; 9 import Card from "./Card.svelte";
9 import Column from "./Column.svelte"; 10 import Column from "./Column.svelte";
10 import AddForm from "./forms/AddForm.svelte"; 11 import AddForm from "./forms/AddForm.svelte";
@@ -46,8 +47,8 @@
46 47
47 if (res.ok) { 48 if (res.ok) {
48 const json = await res.json(); 49 const json = await res.json();
49 let labels = json.map(d => d.name); 50 let labels = json.map((d: any) => d.name);
50 let data = json.map(d => d.total); 51 let data = json.map((d: any) => d.total);
51 return [labels, data]; 52 return [labels, data];
52 } else { 53 } else {
53 throw new Error("There was a problem with your request"); 54 throw new Error("There was a problem with your request");
@@ -65,8 +66,8 @@
65 66
66 if (res.ok) { 67 if (res.ok) {
67 const json = await res.json(); 68 const json = await res.json();
68 let labels = json.map(d => d.date); 69 let labels = json.map((d: any) => d.date);
69 let data = json.map(d => d.total); 70 let data = json.map((d: any) => d.total);
70 return [labels, data]; 71 return [labels, data];
71 } else { 72 } else {
72 throw new Error("There was a problem with your request"); 73 throw new Error("There was a problem with your request");
@@ -84,9 +85,9 @@
84 fetchDailyUserStatistics().then(updateDailyUserTotalsChart).catch(err => console.error(err)); 85 fetchDailyUserStatistics().then(updateDailyUserTotalsChart).catch(err => console.error(err));
85 } 86 }
86 87
87 function setupWeeklyTotalsChart(result) { 88 function setupWeeklyTotalsChart(result: any) {
88 [lastSevenDays, lastSevenDaysData] = result; 89 [lastSevenDays, lastSevenDaysData] = result;
89 lineChart = new Chart(lineCanvasRef, { 90 lineChart = new ChartJS(lineCanvasRef, {
90 type: "line", 91 type: "line",
91 data: { 92 data: {
92 labels: lastSevenDays, 93 labels: lastSevenDays,
@@ -129,10 +130,10 @@
129 }); 130 });
130 } 131 }
131 132
132 function setupDailyUserTotalsChart(result) { 133 function setupDailyUserTotalsChart(result: any) {
133 [userTotalsLabels, userTotalsData] = result; 134 [userTotalsLabels, userTotalsData] = result;
134 135
135 barChart = new Chart(barCanvasRef, { 136 barChart = new ChartJS(barCanvasRef, {
136 type: "bar", 137 type: "bar",
137 data: { 138 data: {
138 labels: userTotalsLabels, 139 labels: userTotalsLabels,
@@ -177,13 +178,13 @@
177 }); 178 });
178 } 179 }
179 180
180 function updateWeeklyTotalsChart(result) { 181 function updateWeeklyTotalsChart(result: any) {
181 [, lastSevenDaysData] = result; 182 [, lastSevenDaysData] = result;
182 lineChart.data.datasets[0].data = lastSevenDaysData; 183 lineChart.data.datasets[0].data = lastSevenDaysData;
183 lineChart.update(); 184 lineChart.update();
184 } 185 }
185 186
186 function updateDailyUserTotalsChart(result) { 187 function updateDailyUserTotalsChart(result: any) {
187 [, userTotalsData] = result; 188 [, userTotalsData] = result;
188 barChart.data.datasets[0].data = userTotalsData; 189 barChart.data.datasets[0].data = userTotalsData;
189 barChart.update(); 190 barChart.update();
@@ -205,6 +206,7 @@
205 206
206<Column --width="500px"> 207<Column --width="500px">
207 <Card --height="300px"> 208 <Card --height="300px">
209 <!--<Chart />-->
208 <canvas bind:this={barCanvasRef} /> 210 <canvas bind:this={barCanvasRef} />
209 </Card> 211 </Card>
210 <Card --height="300px"> 212 <Card --height="300px">
@@ -223,17 +225,3 @@
223 </Card> 225 </Card>
224</Column> 226</Column>
225<!-- <Chart /> --> 227<!-- <Chart /> -->
226
227
228<style>
229 dialog {
230 background: red;
231 box-shadow: 0 20px 5em 10px rgba(0, 0, 0, 0.8);
232 }
233
234 dialog::backdrop {
235 padding: 20px;
236 box-shadow: 20px 20px rgba(0, 0, 0, 0.8);
237 background-color: red;
238 }
239</style>
diff --git a/fe/src/lib/Layout.svelte b/fe/src/lib/Layout.svelte
index f208f34..2728dd3 100644
--- a/fe/src/lib/Layout.svelte
+++ b/fe/src/lib/Layout.svelte
@@ -1,9 +1,13 @@
1<script> 1<script>
2 import { authenticated, token } from "../stores/auth"; 2 import { authenticated, token, user, preferences } from "../stores/auth";
3 import PreferencesForm from "./PreferencesForm.svelte"; 3 import PreferencesForm from "./PreferencesForm.svelte";
4 import { addFormOpen } from "../stores/forms"; 4 import { addFormOpen } from "../stores/forms";
5 5
6 const logout = () => token.unauthenticate(); 6 const logout = () => {
7 preferences.reset();
8 user.reset();
9 token.unauthenticate();
10 }
7 let preferenceFormOpen = false; 11 let preferenceFormOpen = false;
8 12
9 function showPreferencesDialog() { 13 function showPreferencesDialog() {
diff --git a/fe/src/lib/LoginForm.svelte b/fe/src/lib/LoginForm.svelte
index bf6d9ad..8c3c288 100644
--- a/fe/src/lib/LoginForm.svelte
+++ b/fe/src/lib/LoginForm.svelte
@@ -47,7 +47,7 @@
47 preferences: userPreferences, 47 preferences: userPreferences,
48 } = await response.json(); 48 } = await response.json();
49 user.setUser(userData); 49 user.setUser(userData);
50 preferences.set(userPreferences); 50 preferences.setPreference(userPreferences);
51 token.authenticate(apiToken); 51 token.authenticate(apiToken);
52 } 52 }
53 53
diff --git a/fe/src/lib/PreferencesForm.svelte b/fe/src/lib/PreferencesForm.svelte
index 95e04c1..875393c 100644
--- a/fe/src/lib/PreferencesForm.svelte
+++ b/fe/src/lib/PreferencesForm.svelte
@@ -1,51 +1,118 @@
1<script lang="ts"> 1<script lang="ts">
2 import { preferences } from '../stores/auth'; 2 import { user, preferences, token } from "../stores/auth";
3 import type { Size, Preference } from '../types'; 3 import { createEventDispatcher, onDestroy, onMount } from "svelte";
4 import { createEventDispatcher } from 'svelte'; 4 import type { User } from "../types";
5 export let open: boolean; 5
6 6 export let open: boolean;
7 let preference: Preference = { 7
8 color: "#00FF00", 8 let sizes: Array<any>;
9 size: { 9 let selectedSize: number = 1;
10 size: 8, 10 let color: string = "#000000";
11 unit: 'oz' 11
12 } 12 const dispatch = createEventDispatcher();
13 } 13
14 14 const unsubscribe = preferences.subscribe(
15 const dispatch = createEventDispatcher(); 15 (value: any) => {
16 16 console.log('update value: ', value);
17 preferences.subscribe((value) => { 17 color = value.color;
18 preference = value; 18 selectedSize = value.size_id;
19 },
20 );
21
22 function closeDialog() {
23 dispatch("close");
24 }
25
26 async function updateUserPreferences() {
27 const res = await fetch("http://localhost:8080/api/v1/user/preferences", {
28 method: "PATCH",
29 headers: {
30 Authorization: `Bearer ${$token}`,
31 },
32 body: JSON.stringify($preferences),
19 }); 33 });
34 }
20 35
21 function onPreferencesSave(): void { 36 async function getUserPreferences() {
22 preferences.set(preference); 37 const res = await fetch(
23 dispatch('close') 38 `http://localhost:8080/api/v1/user/${($user as User)!.id}/preferences`,
24 } 39 {
40 method: "GET",
41 headers: {
42 Authorization: `Bearer ${$token}`,
43 },
44 },
45 );
46 const updatePreferences = await res.json();
47 preferences.set(updatePreferences);
48 }
25 49
50 async function onPreferencesSave(): Promise<void> {
51 preferences.update((value) => ({
52 ...value!,
53 size_id: selectedSize,
54 color: color,
55 }));
56
57 await updateUserPreferences();
58 await getUserPreferences();
59
60 dispatch("close");
61 }
62
63 onMount(() => {
64 fetch("http://localhost:8080/api/v1/sizes", {
65 method: "GET",
66 headers: {
67 Authorization: `Bearer ${$token}`,
68 },
69 })
70 .then((res) => res.json())
71 .then((val) => (sizes = val));
72 });
73
74 onDestroy(() => {
75 unsubscribe();
76 });
26</script> 77</script>
78
27<dialog {open} on:submit|preventDefault={onPreferencesSave}> 79<dialog {open} on:submit|preventDefault={onPreferencesSave}>
28 <h2>User Preferences</h2> 80 <h2>User Preferences</h2>
29 <form method="dialog"> 81 <form method="dialog">
30 <div class="form input group"> 82 <div class="form input group">
31 <label for="color">Color</label> 83 <label for="color">Color</label>
32 <input id="color" name="color" type="color" bind:value={preference.color}/> 84 <input
33 </div> 85 id="color"
34 <div class="form input group"> 86 name="color"
35 <label for="size">Bottle Size</label> 87 type="color"
36 <input id="size" name="size" type="number" min="8" max="48" step="8" bind:value={preference.size.size}/> 88 bind:value={color}
37 </div> 89 />
38 <button type="submit">Save</button> 90 </div>
39 </form> 91 <div class="form input group">
92 <label for="size">Bottle Size</label>
93 <select
94 bind:value={selectedSize}
95 >
96 {#if sizes}
97 {#each sizes as size}
98 <option value={size.id}>{size.size} {size.unit}</option>
99 {/each}
100 {/if}
101 </select>
102 </div>
103 <button on:click={closeDialog}>Cancel</button>
104 <button type="submit">Save</button>
105 </form>
40</dialog> 106</dialog>
107
41<style> 108<style>
42dialog { 109 dialog {
43 background: white; 110 background: white;
44 color: black; 111 color: black;
45} 112 }
46 113
47input[type="color"] { 114 input[type="color"] {
48 width: 100%; 115 width: 4em;
49 height: 100%; 116 height: 4em;
50} 117 }
51</style> 118</style>
diff --git a/fe/src/lib/errors.ts b/fe/src/lib/errors.ts
index d44bec5..81f7145 100644
--- a/fe/src/lib/errors.ts
+++ b/fe/src/lib/errors.ts
@@ -1,7 +1,5 @@
1export class UnauthorizedError extends Error { 1export class UnauthorizedError extends Error {
2 constructor(message?: string, options?: ErrorOptions) { 2 constructor(message?: string) {
3 super(message, options); 3 super(message);
4 } 4 }
5} 5}
6
7
diff --git a/fe/src/lib/utils.ts b/fe/src/lib/utils.ts
index 22d4e9a..e78556c 100644
--- a/fe/src/lib/utils.ts
+++ b/fe/src/lib/utils.ts
@@ -1,5 +1,5 @@
1export function processFormInput(form: HTMLFormElement) { 1export function processFormInput(form: HTMLFormElement) {
2 const formData = new FormData(form); 2 const formData: FormData = new FormData(form);
3 const data: Record<string, any> = {}; 3 const data: Record<string, any> = {};
4 for (let field of formData) { 4 for (let field of formData) {
5 const [key, value] = field; 5 const [key, value] = field;