diff --git a/front-end/src/App.svelte b/front-end/src/App.svelte index af777ef..2b1097a 100644 --- a/front-end/src/App.svelte +++ b/front-end/src/App.svelte @@ -2,155 +2,70 @@ import { onMount } from "svelte"; import logo from "/logo.svg"; - import RadioGroup from "./lib/RadioGroup.svelte"; - import { - createAnswer, - getAnswer, - getQuestion, - getSummary, - updateAnswer, - waitUntilLive, - type Answer, - type Problem, - type Question, - type Summary, - type UpdateAnswerPayload, - } from "./lib/api"; + import { getQuestion, waitUntilLive, type Question } from "./lib/api"; import Loading from "./lib/Loading.svelte"; import Error from "./lib/Error.svelte"; - import Submit from "./lib/Submit.svelte"; - import Comment from "./lib/Comment.svelte"; - import BarChart from "./lib/BarChart.svelte"; import Footer from "./lib/Footer.svelte"; import Share from "./views/Share.svelte"; - - let loading = $state(true); - let view = $state("form"); - let error = $state(null); + import { initializePath, parsePath, updatePath } from "./lib/path.svelte"; + import Link from "./lib/Link.svelte"; + import { getStatus, setError, setLoading } from "./lib/status.svelte"; + import Summary from "./views/Summary.svelte"; + import Form from "./views/Form.svelte"; + + let { loading, error } = $derived.by(getStatus); + let view = $derived.by(() => parsePath().view); 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; - } - - view = pathComponents[1] || "form"; - 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. - 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}`); - } - - // 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) => { - initAnswer(); - }); - - initAnswer(); - }); - - const handleChange = async (payload: UpdateAnswerPayload) => { - if (!answer) { - return; - } + const initializeQuestion = async () => { try { - const ar = await updateAnswer(answer?.id, payload); - if (ar.error) { - error = ar.error; + // Wait until the server has started. + await waitUntilLive(); + + const { key } = parsePath(); + if (!key) { + setError({ + status: 404, + title: "Question not found", + }); return; } - answer = ar.data; - } catch (_) { - error = { - status: 500, - title: "Failed to update feedback.", - }; - } - }; - const fetchSummary = async (key?: string) => { - loading = true; - try { - const sr = await getSummary(key ?? ""); - if (sr.error) { - error = sr.error; + // Fetch the question using the key. + const qr = await getQuestion(key); + if (qr.error) { + setError(qr.error); return; } - summary = sr.data; - } catch (_) { - error = { + question = qr.data; + } catch (err) { + setError({ status: 500, - title: "Failed to fetch summary.", - }; + title: "Failed to initialize feedback application.", + }); } finally { - loading = false; + setLoading(false); } }; - const handleSubmit = async () => { - loading = true; - await handleChange({ submit: true }); - view = "summary"; - window.history.pushState({ id: answer?.id }, "", `/${answer?.key}/summary`); - await fetchSummary(answer?.key); - loading = false; - }; + onMount(() => { + initializePath(); + initializeQuestion(); + + window.addEventListener("popstate", () => { + updatePath(); + }); + }); + + $effect(() => { + if (["form", "share", "summary"].includes(view) === false) { + setError({ + status: 404, + title: "Page not found", + }); + return; + } + });
@@ -164,34 +79,31 @@ {:else if error} - {:else if question && view === "form"} -
- {question.choice_text} - handleChange({ value })} - value={answer?.value} - /> -
- {#if answer?.value != undefined} - {#if question?.with_comment} - handleChange({ comment })} - value={answer?.comment} - /> - {/if} - - {/if} - {:else if question && view === "summary" && summary} -
-

Thank you for your feedback!

- -
+ {/if} + {#if question && view === "form"} +
+ {:else if question && view === "summary"} + {:else if question && view === "share"} {/if} + {#if question} + + {/if}