diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 7825a44..4d5c57d 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,7 +11,9 @@
"@fortawesome/fontawesome-free": "^6.4.2",
"@sveltejs/adapter-auto": "^2.1.0",
"@sveltejs/kit": "^1.24.1",
- "axios": "^1.5.0"
+ "axios": "^1.5.0",
+ "svelte-forms-lib": "^2.0.1",
+ "yup": "^1.2.0"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.4.2",
@@ -1756,6 +1758,11 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
+ "node_modules/property-expr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
+ "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -2071,6 +2078,14 @@
"svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0"
}
},
+ "node_modules/svelte-forms-lib": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/svelte-forms-lib/-/svelte-forms-lib-2.0.1.tgz",
+ "integrity": "sha512-kwbJ3ynsepsrrJyAMrvSc0Lj/myc9vfI2DL8OKxgArZimrNYsRh1gENYhvrcKEI3BiZrv8q3VFfmGo/GMyk7Zg==",
+ "dependencies": {
+ "dequal": "^2.0.2"
+ }
+ },
"node_modules/svelte-hmr": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
@@ -2226,6 +2241,11 @@
"node": ">=0.8"
}
},
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
+ },
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
@@ -2247,6 +2267,11 @@
"node": ">=8.0"
}
},
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
+ },
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
@@ -2267,6 +2292,17 @@
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
+ "node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/typescript": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@@ -2408,6 +2444,17 @@
"engines": {
"node": ">= 14"
}
+ },
+ "node_modules/yup": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz",
+ "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
}
}
}
diff --git a/frontend/package.json b/frontend/package.json
index 01ae778..916c447 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -25,6 +25,8 @@
"@fortawesome/fontawesome-free": "^6.4.2",
"@sveltejs/adapter-auto": "^2.1.0",
"@sveltejs/kit": "^1.24.1",
- "axios": "^1.5.0"
+ "axios": "^1.5.0",
+ "svelte-forms-lib": "^2.0.1",
+ "yup": "^1.2.0"
}
}
diff --git a/frontend/src/lib/ButtonMain.svelte b/frontend/src/lib/ButtonMain.svelte
new file mode 100644
index 0000000..9e72b45
--- /dev/null
+++ b/frontend/src/lib/ButtonMain.svelte
@@ -0,0 +1,11 @@
+
+
+
diff --git a/frontend/src/lib/ButtonTrash.svelte b/frontend/src/lib/ButtonTrash.svelte
new file mode 100644
index 0000000..c7d482c
--- /dev/null
+++ b/frontend/src/lib/ButtonTrash.svelte
@@ -0,0 +1,11 @@
+
+
+
diff --git a/frontend/src/lib/WordForm.svelte b/frontend/src/lib/WordForm.svelte
index 45e4116..b281f65 100644
--- a/frontend/src/lib/WordForm.svelte
+++ b/frontend/src/lib/WordForm.svelte
@@ -1,14 +1,102 @@
-
-
-
-{word}
-{definition}
+
+
+ {#if !isEditLevel}
+
+ {:else}
+
+ {/if}
+ |
+
+ {#if !isEditWord}
+
+ {word}
+
+ {:else}
+
+ {/if}
+ |
+
+ {#if !isEditDefinition}
+
+ {definition}
+
+ {:else}
+
+ {/if}
+ |
+
+
+ |
+
diff --git a/frontend/src/lib/arrays.ts b/frontend/src/lib/arrays.ts
new file mode 100644
index 0000000..5e0326b
--- /dev/null
+++ b/frontend/src/lib/arrays.ts
@@ -0,0 +1,7 @@
+export function deleteFromArray(arr: any[], obj: any): any[] {
+ const index = arr.indexOf(obj, 0);
+ if (index > -1) {
+ arr.splice(index, 1);
+ }
+ return arr;
+}
\ No newline at end of file
diff --git a/frontend/src/routes/ma_geriou/+page.svelte b/frontend/src/routes/ma_geriou/+page.svelte
index bd050d9..d8e53c4 100644
--- a/frontend/src/routes/ma_geriou/+page.svelte
+++ b/frontend/src/routes/ma_geriou/+page.svelte
@@ -2,80 +2,197 @@
import { page } from "$app/stores";
import axios from "$lib/api.ts";
import WordForm from "$lib/WordForm.svelte";
- import { type Word } from "../../lib/types";
+ 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, tick } from "svelte";
+ import type { AxiosResponse } from "axios";
+ import { createForm } from "svelte-forms-lib";
+ import * as yup from "yup";
let words: Word[];
- const wordResponse = axios.get("words/").then((data) => {
- words = snakeToCamelCase(data.data);
+ $: 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);
+ });
+ } 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 newWord(e) {
- const formData = new FormData(e.target);
+ function submitNewWord(values) {
+ const formData = {
+ level_id: values.level,
+ word: values.word,
+ definition: values.definition,
+ };
- const data = {};
- for (let field of formData) {
- const [key, value] = field;
- data[key] = value;
+ try {
+ axios
+ .post("words/", formData)
+ .then((data) => {
+ words = [snakeToCamelCase(data.data), ...words];
+ })
+ .then(() => {
+ $form.definition = "";
+ $form.word = "";
+ });
+ } catch (e) {
+ console.log(e);
}
- console.log(data);
}
+
+ 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();
+ });
- {#await wordResponse}
+ {#await promise}
…
{:then}
-
-
Live
-
Ger
-
Termenadur
+
+ {:catch error}
+ {error}
{/await}
diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js
index a2553f7..601dd5b 100644
--- a/frontend/svelte.config.js
+++ b/frontend/svelte.config.js
@@ -1,4 +1,4 @@
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+import { vitePreprocess } from '@sveltejs/kit/vite'
import adapter from "@sveltejs/adapter-auto"
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index c4e1c5f..e323630 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -1,5 +1,5 @@
{
- "extends": "@tsconfig/svelte/tsconfig.json",
+ "extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
@@ -15,6 +15,15 @@
"checkJs": true,
"isolatedModules": true
},
- "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
- "references": [{ "path": "./tsconfig.node.json" }]
-}
+ "include": [
+ "src/**/*.d.ts",
+ "src/**/*.ts",
+ "src/**/*.js",
+ "src/**/*.svelte"
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/grids/serializers.py b/grids/serializers.py
index e039bf0..b622ebb 100644
--- a/grids/serializers.py
+++ b/grids/serializers.py
@@ -10,10 +10,22 @@ class LevelSerializer(serializers.ModelSerializer):
class WordSerializer(serializers.ModelSerializer):
level = LevelSerializer(many=False, read_only=True)
+ level_id = serializers.PrimaryKeyRelatedField(
+ write_only=True, source="level", queryset=Level.objects.all()
+ )
class Meta:
model = Word
- fields = ["id", "word", "definition", "level"]
+ fields = ["id", "word", "definition", "level", "level_id"]
+
+ # def create(self, validated_data):
+ # print(validated_data)
+ # level_data = validated_data.pop("level")
+ # level = Level.objects.get(pk=level_data)
+
+ # word = Word.objects.create(level=level, **validated_data)
+
+ # return word
class GridSerializer(serializers.ModelSerializer):