diff --git a/src/lib/js/shoppingSync.svelte.ts b/src/lib/js/shoppingSync.svelte.ts index 4bc3111..b49649b 100644 --- a/src/lib/js/shoppingSync.svelte.ts +++ b/src/lib/js/shoppingSync.svelte.ts @@ -166,6 +166,20 @@ export function createShoppingSync() { } } + /** Seed state from server-loaded data (safe to call during SSR). */ + function seed(initialList: { version: number; items: ShoppingItem[] }, token?: string | null) { + if (token) shareToken = token; + version = initialList.version; + items = initialList.items || []; + status = 'synced'; + } + + /** Connect SSE for real-time updates (client-only, call in onMount). */ + function connect(token?: string | null) { + if (token) shareToken = token; + connectSSE(); + } + function addItem(name: string, user: string, category = 'Sonstiges') { items = [...items, { id: generateId(), @@ -211,6 +225,8 @@ export function createShoppingSync() { get version() { return version; }, apiUrl, init, + seed, + connect, addItem, toggleItem, removeItem, diff --git a/src/routes/[cospendRoot=cospendRoot]/list/+page.server.ts b/src/routes/[cospendRoot=cospendRoot]/list/+page.server.ts index c2f94a9..ee0a7e9 100644 --- a/src/routes/[cospendRoot=cospendRoot]/list/+page.server.ts +++ b/src/routes/[cospendRoot=cospendRoot]/list/+page.server.ts @@ -1,6 +1,8 @@ import type { PageServerLoad } from './$types'; import { redirect } from '@sveltejs/kit'; import { getShoppingUser } from '$lib/server/shoppingAuth'; +import { dbConnect } from '$utils/db'; +import { ShoppingList } from '$models/ShoppingList'; export const load: PageServerLoad = async ({ locals, url }) => { const session = await locals.auth(); @@ -9,9 +11,24 @@ export const load: PageServerLoad = async ({ locals, url }) => { // Allow access with valid share token even without session if (!session && token) { const user = await getShoppingUser(locals, url); - if (user) return { session: null, shareToken: token }; + if (user) { + await dbConnect(); + const list = await ShoppingList.findOne().lean(); + return { + session: null, + shareToken: token, + initialList: list ? { version: list.version, items: list.items } : { version: 0, items: [] } + }; + } } if (!session) throw redirect(302, '/login'); - return { session, shareToken: null }; + + await dbConnect(); + const list = await ShoppingList.findOne().lean(); + return { + session, + shareToken: null, + initialList: list ? { version: list.version, items: list.items } : { version: 0, items: [] } + }; }; diff --git a/src/routes/[cospendRoot=cospendRoot]/list/+page.svelte b/src/routes/[cospendRoot=cospendRoot]/list/+page.svelte index 3031869..5944656 100644 --- a/src/routes/[cospendRoot=cospendRoot]/list/+page.svelte +++ b/src/routes/[cospendRoot=cospendRoot]/list/+page.svelte @@ -20,6 +20,11 @@ let isGuest = $derived(!data.session); const sync = getShoppingSync(); + // Seed sync state immediately so SSR can render the list + if (data.initialList) { + sync.seed(data.initialList, data.shareToken); + } + const lang = $derived(detectCospendLang($page.url.pathname)); const loc = $derived(locale(lang)); @@ -141,7 +146,13 @@ let checkedCount = $derived(sync.items.filter(i => i.checked).length); let totalCount = $derived(sync.items.length); - onMount(() => { sync.init(shareToken); }); + onMount(() => { + if (data.initialList) { + sync.connect(shareToken); + } else { + sync.init(shareToken); + } + }); onDestroy(() => { sync.disconnect(); }); async function addItem() {