aboutsummaryrefslogtreecommitdiff
path: root/fe/src/App.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'fe/src/App.svelte')
-rw-r--r--fe/src/App.svelte167
1 files changed, 167 insertions, 0 deletions
diff --git a/fe/src/App.svelte b/fe/src/App.svelte
new file mode 100644
index 0000000..cc4e594
--- /dev/null
+++ b/fe/src/App.svelte
@@ -0,0 +1,167 @@
1<script lang="ts">
2 import {onMount} from 'svelte';
3 import svelteLogo from './assets/svelte.svg'
4 import viteLogo from '/vite.svg'
5 import Counter from './lib/Counter.svelte'
6 import Table from './lib/Table.svelte'
7 import Card from './lib/Card.svelte'
8 import { UnauthorizedError } from './lib/errors';
9
10 let data;
11 let error;
12
13 let user = {
14 username: '',
15 password: ''
16 }
17
18 interface CredentialObject {
19 username: string;
20 password: string;
21 }
22
23 function sleep(ms) {
24 return new Promise(resolve => setTimeout(resolve, ms));
25 }
26
27 async function getData() {
28 const res = await fetch('http://localhost:8080/api/v1/stats/');
29 if (res.ok) {
30 await sleep(3000);
31 return await res.json();
32 } else {
33 throw new Error('There was a problem with your request');
34 }
35 }
36
37 function handleClick () {
38 data = getData();
39 }
40
41 let authenticated: boolean = false;
42
43 function prepareCredentials ({ username, password }: CredentialObject): string {
44 return btoa(`${username}:${password}`);
45 }
46
47
48 async function onSubmit(e) {
49 if (!user.username || !user.password) {
50 error = 'please enter your username and password';
51 return;
52 }
53 const auth = prepareCredentials(user);
54
55 const response = await fetch('http://localhost:8080/api/v1/auth', {
56 method: 'POST',
57 headers: {
58 'Authorization': `Basic ${auth}`,
59 },
60 });
61
62 if (response.status === 401) {
63 error = "Your username or password is wrong";
64 return;
65 }
66
67 if (response.ok) {
68 const { token } = await response.json();
69 console.log(token);
70 localStorage.user = JSON.stringify(user);
71 localStorage.token = token;
72 authenticated = true;
73 }
74
75
76 error = null;
77 }
78
79 function logout() {
80 localStorage.removeItem("user");
81 localStorage.removeItem("token");
82 authenticated = false;
83 }
84
85
86 onMount(() => {
87 if (localStorage.token) {
88 authenticated = true;
89 }
90 });
91</script>
92
93<main>
94 {#if !authenticated}
95 <Card>
96 <form class="form" on:submit|preventDefault={onSubmit}>
97 <div class='form input group'>
98 <label for="username">Username</label>
99 <input bind:value={user.username} id="username" name='username' type="text" />
100 </div>
101 <div class='form input group'>
102 <label for="password">Password</label>
103 <input bind:value={user.password} id="password" name='password' type="password" />
104 </div>
105 {#if error}
106 <p class="error">{error}</p>
107 {/if}
108 <button type="submit">Log in</button>
109 </form>
110 </Card>
111 {:else}
112 <div>
113 <button on:click={logout}>Logout</button>
114 </div>
115 <div>
116 <a href="https://vitejs.dev" target="_blank" rel="noreferrer">
117 <img src={viteLogo} class="logo" alt="Vite Logo" />
118 </a>
119 <a href="https://svelte.dev" target="_blank" rel="noreferrer">
120 <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
121 </a>
122 </div>
123
124 <button on:click={handleClick}>
125 Get Data
126 </button>
127
128 {#await data}
129 <p>...fetching</p>
130 {:then data}
131 {#if data}
132 <p>Status</p>
133 <p>{data.status}</p>
134 <Table />
135 <Table nofooter title="No Footer"/>
136 <Table noheader title="No Header"/>
137 {:else}
138 <p>No data yet</p>
139 {/if}
140 {:catch errror}
141 <p>{error.message}</p>
142 {/await}
143 {/if}
144</main>
145
146<style>
147 .logo {
148 height: 6em;
149 padding: 1.5em;
150 will-change: filter;
151 transition: filter 300ms;
152 }
153 .logo:hover {
154 filter: drop-shadow(0 0 2em #646cffaa);
155 }
156 .logo.svelte:hover {
157 filter: drop-shadow(0 0 2em #ff3e00aa);
158 }
159 .read-the-docs {
160 color: #888;
161 }
162
163 .error {
164 font-size: 0.75em;
165 color: red;
166 }
167</style>