From 4d24b90afac6c44c79712153f2669a9abaa4479e Mon Sep 17 00:00:00 2001 From: Mihkel Martin Kasterpalu Date: Wed, 22 Jan 2025 17:49:25 +0200 Subject: [PATCH] Fix desync in dragged elements with client side state object --- src/lib/client/AlbumClientState.svelte.ts | 44 +++++++++++++++++++++ src/lib/components/DNDGroup.svelte | 10 ++++- src/routes/(games)/pakubiiti/+layout.svelte | 9 +++++ src/routes/(games)/pakubiiti/+page.svelte | 15 ++----- 4 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 src/lib/client/AlbumClientState.svelte.ts create mode 100644 src/routes/(games)/pakubiiti/+layout.svelte diff --git a/src/lib/client/AlbumClientState.svelte.ts b/src/lib/client/AlbumClientState.svelte.ts new file mode 100644 index 0000000..7328a37 --- /dev/null +++ b/src/lib/client/AlbumClientState.svelte.ts @@ -0,0 +1,44 @@ +import { getContext, onDestroy, setContext } from 'svelte'; +import type { AlbumData, AlbumDataField } from '$lib/types'; + +export class AlbumClientState { + albums = $state({ + names: [], + artists: [], + images: [] + }); + + constructor() { + onDestroy(() => { + this.albums = { + names: [], + artists: [], + images: [] + }; + }); + } + + update(items: AlbumDataField[], type: string) { + if (type === 'names') { + this.albums.names = items; + } + + if (type === 'artists') { + this.albums.artists = items; + } + + if (type === 'images') { + this.albums.images = items; + } + } +} + +const ALBUM_KEY = Symbol('ALBUM'); + +export function setAlbumClientState() { + return setContext(ALBUM_KEY, new AlbumClientState()); +} + +export function getAlbumClientState() { + return getContext>(ALBUM_KEY); +} diff --git a/src/lib/components/DNDGroup.svelte b/src/lib/components/DNDGroup.svelte index b21b9c5..34ff7a6 100644 --- a/src/lib/components/DNDGroup.svelte +++ b/src/lib/components/DNDGroup.svelte @@ -11,16 +11,20 @@ type Item } from 'svelte-dnd-action'; import * as Card from '$lib/components/ui/card/index.js'; + import { getAlbumClientState } from '$lib/client/AlbumClientState.svelte'; + import { onMount } from 'svelte'; - let { items = $bindable(), image = false, type = 'default' } = $props(); + let { items, image = false, type = 'default' } = $props(); const flipDurationMs = 300; + const clientState = getAlbumClientState(); function handleDndConsider(e: CustomEvent>) { items = e.detail.items; } function handleDndFinalize(e: CustomEvent>) { items = e.detail.items; + clientState.update(e.detail.items as AlbumDataField[], type); } function transformDraggedElement(draggedEl: HTMLElement | undefined) { if (!draggedEl) { @@ -44,6 +48,10 @@ : 'border-blue-400' }` ); + + onMount(() => { + clientState.update(items as AlbumDataField[], type); + }); {#snippet card(item: AlbumDataField, i: number)} diff --git a/src/routes/(games)/pakubiiti/+layout.svelte b/src/routes/(games)/pakubiiti/+layout.svelte new file mode 100644 index 0000000..8a1809d --- /dev/null +++ b/src/routes/(games)/pakubiiti/+layout.svelte @@ -0,0 +1,9 @@ + + +{@render children()} diff --git a/src/routes/(games)/pakubiiti/+page.svelte b/src/routes/(games)/pakubiiti/+page.svelte index f3f29f8..0df8211 100644 --- a/src/routes/(games)/pakubiiti/+page.svelte +++ b/src/routes/(games)/pakubiiti/+page.svelte @@ -10,20 +10,13 @@ import type { AlbumData } from '$lib/types'; import { fade } from 'svelte/transition'; import { expoIn, expoOut } from 'svelte/easing'; + import { getAlbumClientState } from '$lib/client/AlbumClientState.svelte'; let { data }: { data: PageData; form: FormData } = $props(); let loading = $state(false); - let oldAlbums: AlbumData | undefined = $state(); - // Used when user answers wrong and no new data comes in - $effect(() => { - if (data.streamed?.albums) { - data.streamed.albums.then((data) => { - oldAlbums = data as AlbumData; - }); - } - }); + const clientState = getAlbumClientState(); {#snippet footer(loading: boolean)} @@ -93,7 +86,7 @@ -
+

Paku biiti

Lohista kokku õiged albumi nimed, @@ -126,7 +119,7 @@ {/await} {:else}

- {@render playArea(oldAlbums)} + {@render playArea(clientState.albums)}
{@render footer(false)} {/if}