From 73840c91c4403ab3adf13f7dccf10b0c7f3c8bd7 Mon Sep 17 00:00:00 2001 From: Toni Kangas Date: Sun, 4 May 2025 15:55:38 +0300 Subject: [PATCH 1/5] Use state for current path --- front-end/src/App.svelte | 147 ++++++++++++++++++------------- front-end/src/lib/Link.svelte | 19 ++++ front-end/src/lib/path.svelte.ts | 39 ++++++++ 3 files changed, 142 insertions(+), 63 deletions(-) create mode 100644 front-end/src/lib/Link.svelte create mode 100644 front-end/src/lib/path.svelte.ts diff --git a/front-end/src/App.svelte b/front-end/src/App.svelte index af777ef..1381d87 100644 --- a/front-end/src/App.svelte +++ b/front-end/src/App.svelte @@ -23,87 +23,87 @@ import BarChart from "./lib/BarChart.svelte"; import Footer from "./lib/Footer.svelte"; import Share from "./views/Share.svelte"; + import { initializePath, navigate, parsePath } from "./lib/path.svelte"; + import Link from "./lib/Link.svelte"; let loading = $state(true); - let view = $state("form"); + let view = $derived.by(() => parsePath().view); let error = $state(null); let question = $state(null); let answer = $state(null); let summary = $state(null); - onMount(() => { - const initAnswer = async () => { - try { - // Wait until the server has started. - await waitUntilLive(); - - // Parse the question key from URL path or URL query parameters. - const pathComponents = window.location.pathname.split("/").slice(1); - const query = new URLSearchParams(window.location.search); - - const key = pathComponents[0] || query.get("key"); - // Replace path if query parameter is used. This is for backwards compatibility. - if (key && !pathComponents[0]) { - window.history.replaceState({}, "", `/${key}`); - } - if (!key) { - error = { - status: 404, - title: "Question not found", - }; - return; - } + const initAnswer = async () => { + try { + // Wait until the server has started. + await waitUntilLive(); - view = pathComponents[1] || "form"; - if (["form", "share", "summary"].includes(view) === false) { - error = { - status: 404, - title: "Page not found", - }; - return; - } + const { key, view, id } = parsePath(); + if (!key) { + error = { + status: 404, + title: "Question not found", + }; + return; + } - // Fetch the question using the key. - const qr = await getQuestion(key); - if (qr.error) { - error = qr.error; + if (["form", "share", "summary"].includes(view) === false) { + error = { + status: 404, + title: "Page not found", + }; + return; + } + + // Fetch the question using the key. + const qr = await getQuestion(key); + if (qr.error) { + error = qr.error; + return; + } + question = qr.data; + + // Initialize new answer or get existings answer. + if (view === "form") { + const ar = id ? await getAnswer(id) : await createAnswer(key); + if (ar.error) { + error = ar.error; return; } - question = qr.data; - - // Initialize new answer or get existings answer. - const id = query.get("id"); - if (view === "form") { - const ar = id ? await getAnswer(id) : await createAnswer(key); - if (ar.error) { - error = ar.error; - return; - } - answer = ar.data; - window.history.replaceState({}, "", `/${key}?id=${answer.id}`); - } + answer = ar.data; + navigate(`/${key}?id=${answer.id}`, true); + } - // Fetch the summary. - if (view === "summary") { - fetchSummary(key); - } - } catch (err) { - error = { - status: 500, - title: "Failed to initialize feedback form.", - }; - } finally { - loading = false; + // Fetch the summary. + if (view === "summary") { + fetchSummary(key); } - }; + } catch (err) { + error = { + status: 500, + title: "Failed to initialize feedback form.", + }; + } finally { + loading = false; + } + }; - window.addEventListener("popstate", (event) => { + onMount(() => { + initializePath(); + + window.addEventListener("popstate", () => { initAnswer(); }); initAnswer(); }); + $effect(() => { + if (view === "form" && answer === null) { + initAnswer(); + } + }); + const handleChange = async (payload: UpdateAnswerPayload) => { if (!answer) { return; @@ -146,9 +146,9 @@ const handleSubmit = async () => { loading = true; await handleChange({ submit: true }); - view = "summary"; - window.history.pushState({ id: answer?.id }, "", `/${answer?.key}/summary`); + navigate(`/${answer?.key}/summary`); await fetchSummary(answer?.key); + answer = null; loading = false; }; @@ -192,6 +192,19 @@ {:else if question && view === "share"} {/if} + {#if question} + + {/if}