143 lines
4.8 KiB
Svelte
143 lines
4.8 KiB
Svelte
|
<script context="module" lang="ts">
|
||
|
export type User = {
|
||
|
id: string,
|
||
|
name: string,
|
||
|
score: number,
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { onMount } from "svelte";
|
||
|
import Table from "../../Table.svelte";
|
||
|
import { mdiPlus, mdiDelete, mdiPencil, mdiCheck } from '@mdi/js';
|
||
|
import Button from "../../Button.svelte";
|
||
|
import { apiRequest } from "../../util";
|
||
|
|
||
|
let headers = ["Id", "Username", "Score", ""];
|
||
|
|
||
|
let users: User[] | undefined;
|
||
|
|
||
|
let loading = false;
|
||
|
let newUsername: string | undefined;
|
||
|
|
||
|
let scoreEdit: string | undefined;
|
||
|
let newScore: string | undefined;
|
||
|
|
||
|
const loadUsers = async () => {
|
||
|
loading = true;
|
||
|
|
||
|
let response = await apiRequest('GET', '/user');
|
||
|
|
||
|
if (response.status == 200) {
|
||
|
users = await response.json();
|
||
|
} else {
|
||
|
console.error(`Request failed: got code ${response.status}, expected 200`);
|
||
|
}
|
||
|
|
||
|
loading = false;
|
||
|
};
|
||
|
|
||
|
const addUser = async () => {
|
||
|
loading = true;
|
||
|
|
||
|
let response = await apiRequest('POST', '/user', JSON.stringify(newUsername));
|
||
|
|
||
|
if (response.status == 201) {
|
||
|
let user: User = await response.json();
|
||
|
|
||
|
if (users !== undefined) {
|
||
|
users = [...users, user];
|
||
|
} else {
|
||
|
users = [user];
|
||
|
}
|
||
|
} else {
|
||
|
console.error(`Request failed: got code ${response.status}, expected 201`);
|
||
|
}
|
||
|
|
||
|
loading = false;
|
||
|
};
|
||
|
|
||
|
const removeUser = async (id: string) => {
|
||
|
loading = true;
|
||
|
|
||
|
let response = await apiRequest('DELETE', `/user/${id}`);
|
||
|
|
||
|
if (response.status == 200) {
|
||
|
users = users?.filter(user => user.id != id);
|
||
|
} else {
|
||
|
console.error(`Request failed: got code ${response.status}, expected 200`);
|
||
|
}
|
||
|
|
||
|
loading = false;
|
||
|
};
|
||
|
|
||
|
const updateScore = async (id: string) => {
|
||
|
loading = true;
|
||
|
scoreEdit = undefined;
|
||
|
|
||
|
if (newScore !== undefined) {
|
||
|
let response = await apiRequest('POST', `/user/${id}/score`, JSON.stringify(parseInt(newScore)));
|
||
|
|
||
|
if (response.status == 200) {
|
||
|
users = users?.map(u => {
|
||
|
if (u.id == id && newScore !== undefined) {
|
||
|
u.score = parseInt(newScore);
|
||
|
}
|
||
|
return u
|
||
|
});
|
||
|
} else {
|
||
|
console.error(`Request failed: got code ${response.status}, expected 200`);
|
||
|
scoreEdit = id;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
loading = false;
|
||
|
};
|
||
|
|
||
|
onMount(async () => {
|
||
|
await loadUsers();
|
||
|
});
|
||
|
|
||
|
</script>
|
||
|
|
||
|
<div class="max-w-7xl mx-auto">
|
||
|
<Table {headers} {loading}>
|
||
|
{#if users !== undefined}
|
||
|
{#each users as user}
|
||
|
<tr>
|
||
|
<td class="font-mono whitespace-nowrap px-3 py-4 text-sm text-slate-500">{user.id}</td>
|
||
|
<td class="whitespace-nowrap px-3 py-4 text-sm text-slate-400">{user.name}</td>
|
||
|
<td class="whitespace-nowrap px-3 text-sm text-slate-400">
|
||
|
{#if scoreEdit === user.id}
|
||
|
<span class="inline-block">
|
||
|
<input class="mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-10 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500" placeholder={user.score.toString()} bind:value={newScore}>
|
||
|
</span>
|
||
|
<Button icon={mdiCheck} on:click={() => updateScore(user.id)} />
|
||
|
{:else}
|
||
|
<span class="my-3 w-20">
|
||
|
{user.score}
|
||
|
</span>
|
||
|
<Button icon={mdiPencil} on:click={() => scoreEdit = user.id} />
|
||
|
{/if}
|
||
|
</td>
|
||
|
<td class="whitespace-nowrap py-4 text-sm text-slate-400">
|
||
|
<Button icon={mdiDelete} on:click={() => removeUser(user.id)} />
|
||
|
</td>
|
||
|
</tr>
|
||
|
{/each}
|
||
|
{/if}
|
||
|
<tr>
|
||
|
<td colspan={1} />
|
||
|
<td colspan={1}>
|
||
|
<input class="mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-4 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500" placeholder="username" bind:value={newUsername}>
|
||
|
</td>
|
||
|
<td colspan={1} />
|
||
|
{#if loading === false}
|
||
|
<td colspan={1} class="py-3">
|
||
|
<Button icon={mdiPlus} on:click={() => addUser()} />
|
||
|
</td>
|
||
|
{/if}
|
||
|
</tr>
|
||
|
</Table>
|
||
|
</div>
|