210 lines
7 KiB
Svelte
210 lines
7 KiB
Svelte
<script lang="ts">
|
|
import { page } from "$app/stores";
|
|
import axios from "$lib/api.ts";
|
|
import WordForm from "$lib/WordForm.svelte";
|
|
import ButtonMain from "$lib/ButtonMain.svelte";
|
|
import type { Level, Word } from "../../lib/types";
|
|
import { deleteFromArray } from "$lib/arrays";
|
|
|
|
import { snakeToCamelCase } from "$lib/case";
|
|
import { onMount } from "svelte";
|
|
import { createForm } from "svelte-forms-lib";
|
|
import * as yup from "yup";
|
|
|
|
let words: Word[];
|
|
$: words;
|
|
let levels: Level[];
|
|
let promise;
|
|
let promiseLevels;
|
|
|
|
// Form
|
|
const { form, errors, state, handleChange, handleSubmit } = createForm({
|
|
initialValues: {
|
|
level: "",
|
|
word: "",
|
|
definition: "",
|
|
},
|
|
validationSchema: yup.object().shape({
|
|
level: yup.number().required(),
|
|
word: yup.string().required(),
|
|
definition: yup.string().required(),
|
|
}),
|
|
onSubmit: (values) => {
|
|
submitNewWord(values);
|
|
},
|
|
});
|
|
|
|
function fetchLevels() {
|
|
try {
|
|
promiseLevels = axios
|
|
.get("levels/")
|
|
.then((data) => {
|
|
levels = snakeToCamelCase(data.data);
|
|
})
|
|
.then(() => {
|
|
$form.level = levels[0].id.toString();
|
|
});
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
function fetchData() {
|
|
try {
|
|
promise = axios.get("words/").then((data) => {
|
|
words = snakeToCamelCase(data.data);
|
|
});
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
let isFormNewShown = false;
|
|
|
|
function toggleFormNew() {
|
|
isFormNewShown = !isFormNewShown;
|
|
}
|
|
|
|
function submitNewWord(values) {
|
|
const formData = {
|
|
level_id: values.level,
|
|
word: values.word,
|
|
definition: values.definition,
|
|
};
|
|
|
|
try {
|
|
axios
|
|
.post("words/", formData)
|
|
.then((data) => {
|
|
words = [snakeToCamelCase(data.data), ...words];
|
|
})
|
|
.then(() => {
|
|
$form.definition = "";
|
|
$form.word = "";
|
|
});
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
function deleteWord(word: Word) {
|
|
if (!(word && word.id)) return;
|
|
try {
|
|
axios.delete("/words/" + word.id).then(() => {
|
|
words = deleteFromArray(words, word);
|
|
});
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
onMount(() => {
|
|
fetchData();
|
|
fetchLevels();
|
|
|
|
window.addEventListener("keyup", (e) => {
|
|
if (e.key == "Escape") {
|
|
toggleFormNew();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<main>
|
|
{#await promise}
|
|
<p>…</p>
|
|
{:then}
|
|
<form on:submit={handleSubmit}>
|
|
<table class="w-full text-left">
|
|
<thead>
|
|
<tr
|
|
class="bg-slate-100 rounded-lg font-bold text-slate-700 border-separate border-b"
|
|
>
|
|
<th class="font-bold p-2">Live</th>
|
|
<th class="font-bold p-2">Ger</th>
|
|
<th class="font-bold p-2">Termenadur</th>
|
|
<th />
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
{#if !isFormNewShown}
|
|
<tr>
|
|
<td colspan="4" class="text-center p-2 border-b">
|
|
<ButtonMain onClick={toggleFormNew}>
|
|
<span
|
|
class="fa-regular fa-plus align-top"
|
|
/>
|
|
</ButtonMain>
|
|
</td>
|
|
</tr>
|
|
{:else}
|
|
<tr class="border-b">
|
|
<td class="p-2">
|
|
<select
|
|
id="level"
|
|
name="level"
|
|
on:change={handleChange}
|
|
bind:value={$form.level}
|
|
class="p-1 rounded-md border"
|
|
>
|
|
{#await promiseLevels then}
|
|
{#each levels as level}
|
|
<option value={level.levelNumber}>
|
|
{level.levelString}</option
|
|
>
|
|
{/each}
|
|
{/await}
|
|
</select>
|
|
{#if $errors.level}
|
|
<div class="text-red-500 text-sm">
|
|
{$errors.level}
|
|
</div>
|
|
{/if}
|
|
</td>
|
|
<td class="p-2">
|
|
<input
|
|
name="word"
|
|
placeholder="Ger"
|
|
on:change={handleChange}
|
|
bind:value={$form.word}
|
|
class="p-1 rounded-md border w-full"
|
|
/>
|
|
</td>
|
|
<td class="p-2">
|
|
<input
|
|
name="definition"
|
|
placeholder="Termenadur"
|
|
on:change={handleChange}
|
|
bind:value={$form.definition}
|
|
class="p-1 rounded-md border w-full"
|
|
/>
|
|
</td>
|
|
<td class="p-2">
|
|
<button
|
|
type="submit"
|
|
class="bg-violet-600 hover:bg-violet-700 rounded-md text-white p-1 w-6 h-6 justify-center"
|
|
>
|
|
<span
|
|
class="fa-regular fa-plus align-top"
|
|
/>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{/if}
|
|
{#if words}
|
|
{#each words as word}
|
|
<WordForm
|
|
{...word}
|
|
on:deleteWord={deleteWord(word)}
|
|
/>
|
|
{/each}
|
|
{/if}
|
|
</tbody>
|
|
</table>
|
|
</form>
|
|
{:catch error}
|
|
{error}
|
|
{/await}
|
|
</main>
|