From 3ea54d5a210093ba64c6c1b0f7282084e3387e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dorien=20Gr=C3=B6nwald?= <dorien.groenwald@visuellverstehen.de> Date: Wed, 20 Dec 2023 11:24:40 +0100 Subject: [PATCH] fix(web-service): add functionality for deleting entries --- .../frontend/src/lib/forms/Checkbox.svelte | 10 +++-- .../shopping-list/ShoppingListEntry.svelte | 42 ++++++++++++++----- .../routes/shopping-lists/[id]/+page.svelte | 17 +++++--- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/web-service/frontend/src/lib/forms/Checkbox.svelte b/src/web-service/frontend/src/lib/forms/Checkbox.svelte index 3849455a..1ebbe3fb 100644 --- a/src/web-service/frontend/src/lib/forms/Checkbox.svelte +++ b/src/web-service/frontend/src/lib/forms/Checkbox.svelte @@ -2,14 +2,15 @@ import Checkmark from "../../assets/svg/Checkmark.svelte"; import {createEventDispatcher} from "svelte"; - export let label: string; export let id: number; + export let label: string; + export let count: number; export let checked: boolean | undefined; const dispatch = createEventDispatcher(); </script> -<div class="flex items-center mr-4 relative"> +<div class="flex items-center relative"> <input on:click={() => { checked = ! checked; dispatch('updateShoppingListEntry') } } type="checkbox" @@ -23,7 +24,10 @@ <label for="input-{id}" - class="text-sm font-medium cursor-pointer lg:text-base { checked ? 'line-through opacity-50' : '' }"> + class="text-sm font-medium cursor-pointer flex justify-center items-center gap-x-2 lg:text-base { checked ? 'line-through opacity-50' : '' }"> {label} + <span class="border-l-[1.5px] font-normal border-l-gray-dark/50 pl-2 leading-none text-gray-dark text-sm whitespace-nowrap lg:text-base { checked ? 'hidden' : '' }"> + {count} Stk. + </span> </label> </div> \ No newline at end of file diff --git a/src/web-service/frontend/src/lib/shopping-list/ShoppingListEntry.svelte b/src/web-service/frontend/src/lib/shopping-list/ShoppingListEntry.svelte index 75a4e464..22e9594d 100644 --- a/src/web-service/frontend/src/lib/shopping-list/ShoppingListEntry.svelte +++ b/src/web-service/frontend/src/lib/shopping-list/ShoppingListEntry.svelte @@ -2,6 +2,7 @@ import {createEventDispatcher, onMount} from 'svelte'; import Checkbox from "$lib/forms/Checkbox.svelte"; import {handleErrors} from "../../assets/helper/handleErrors"; + import Trash from "../../assets/svg/Trash.svelte"; type ViewState = "detailed" | "compressed"; @@ -47,7 +48,7 @@ }); function updateShoppingListEntry(): void { - if (! listId || !productData.id) return; + if (! listId || ! productData.id ) return; const apiUrl: string = `/api/v1/shoppinglistentries/${listId}/${productData.id}`; const requestOptions = { @@ -61,18 +62,39 @@ .then(()=> dispatch('updateCheckedEntriesCount', { state: entry.checked })) .catch(error => console.error("Failed to fetch data:", error.message)); } + + function deleteShoppingListEntry(): void { + if (! listId || ! productData.id) return; + + const apiUrl: string = `/api/v1/shoppinglistentries/${listId}/${productData.id}`; + const requestOptions = { + method: "DELETE", + headers: { 'Content-Type': 'application/json' }, + }; + + fetch(apiUrl, requestOptions) + .then(handleErrors) + .then(()=> { location.reload(); dispatch('updateCheckedEntriesCount', { state: true }) }) + .catch(error => console.error("Failed to fetch data:", error.message)); + } </script> <li class="border-t-2 border-t-gray-light py-3 lg:py-6"> - <div class="flex gap-x-4 items-start justify-between"> - <Checkbox - label="{productData.description}" - id="{productData.id}" - bind:checked={entry.checked} - on:updateShoppingListEntry={updateShoppingListEntry} /> - <span class="mt-0.5 block text-gray-dark text-sm whitespace-nowrap lg:text-base { entry.checked ? 'opacity-50' : '' }"> - {entry.count} Stk. - </span> + <div class="flex gap-x-2 items-center justify-between"> + <div class="flex gap-x-2 items-center"> + <Checkbox + label={productData.description} + id={productData.id} + count={entry.count} + bind:checked={entry.checked} + on:updateShoppingListEntry={updateShoppingListEntry} /> + </div> + <button + aria-label="Eintrag löschen" + on:click={deleteShoppingListEntry} + class="bg-gray-light rounded-full p-2 text-gray-dark transition-all ease-in-out duration-300 hover:bg-gray-dark/25"> + <Trash classes="w-4 h-4 md:w-5 md:h-5" /> + </button> </div> {#if view === 'detailed' && priceData} <p class="text-gray-dark mt-1 ml-[2.1rem] text-sm flex flex-wrap items-center gap-2 lg:text-sm { entry.checked ? 'opacity-50' : '' }"> diff --git a/src/web-service/frontend/src/routes/shopping-lists/[id]/+page.svelte b/src/web-service/frontend/src/routes/shopping-lists/[id]/+page.svelte index b6981892..4780c357 100644 --- a/src/web-service/frontend/src/routes/shopping-lists/[id]/+page.svelte +++ b/src/web-service/frontend/src/routes/shopping-lists/[id]/+page.svelte @@ -23,6 +23,11 @@ checkedEntriesCount++; } }) + + if (data.entries.length > 0 && data.list.completed && checkedEntriesCount != data.entries.length) { + data.list.completed = false; + updateShoppingList(); + } }); function updateCheckedEntriesCount(event: any): void { @@ -83,6 +88,10 @@ <p class="text-gray-dark text-sm">Deine Einkaufsliste</p> <ul class="mt-4"> + {#if data.entries.length === 0} + <p>Keine Einträge vorhanden.</p> + {/if} + {#each data.entries as entry} <ShoppingListEntry listId={data.list.id} @@ -92,10 +101,8 @@ {/each} </ul> - {#if ! data.list.completed} - <AddEntryModal - listId="{data.list.id}" - currentEntries="{data.entries}"/> - {/if} + <AddEntryModal + listId="{data.list.id}" + currentEntries="{data.entries}"/> </div> </main>