|
5 | 5 | import RadioGroup from "./lib/RadioGroup.svelte"; |
6 | 6 | import { |
7 | 7 | createAnswer, |
| 8 | + getAnswer, |
8 | 9 | getQuestion, |
9 | 10 | getSummary, |
10 | 11 | updateAnswer, |
|
23 | 24 | import Footer from "./lib/Footer.svelte"; |
24 | 25 |
|
25 | 26 | let loading = $state(true); |
| 27 | + let view = $state<string>("form"); |
26 | 28 | let error = $state<Problem | null>(null); |
27 | 29 | let question = $state<Question | null>(null); |
28 | 30 | let answer = $state<Answer | null>(null); |
|
34 | 36 | // Wait until the server has started. |
35 | 37 | await waitUntilLive(); |
36 | 38 |
|
37 | | - // Parse the question key from URL query parameters. |
| 39 | + // Parse the question key from URL path or URL query parameters. |
| 40 | + const pathComponents = window.location.pathname.split("/").slice(1); |
38 | 41 | const query = new URLSearchParams(window.location.search); |
39 | | - const key = query.get("key"); |
| 42 | +
|
| 43 | + const key = pathComponents[0] || query.get("key"); |
| 44 | + // Replace path if query parameter is used. This is for backwards compatibility. |
| 45 | + if (key && !pathComponents[0]) { |
| 46 | + window.history.replaceState({}, "", `/${key}`); |
| 47 | + } |
40 | 48 | if (!key) { |
41 | 49 | error = { |
42 | 50 | status: 404, |
|
45 | 53 | return; |
46 | 54 | } |
47 | 55 |
|
| 56 | + view = pathComponents[1] || "form"; |
| 57 | + if (["form", "summary"].includes(view) === false) { |
| 58 | + error = { |
| 59 | + status: 404, |
| 60 | + title: "Page not found", |
| 61 | + }; |
| 62 | + return; |
| 63 | + } |
| 64 | +
|
48 | 65 | // Fetch the question using the key. |
49 | 66 | const qr = await getQuestion(key); |
50 | 67 | if (qr.error) { |
|
53 | 70 | } |
54 | 71 | question = qr.data; |
55 | 72 |
|
56 | | - // Initialize the answer. |
57 | | - const ar = await createAnswer(key); |
58 | | - if (ar.error) { |
59 | | - error = ar.error; |
60 | | - return; |
| 73 | + // Initialize new answer or get existings answer. |
| 74 | + const id = query.get("id"); |
| 75 | + if (view === "form") { |
| 76 | + const ar = id ? await getAnswer(id) : await createAnswer(key); |
| 77 | + if (ar.error) { |
| 78 | + error = ar.error; |
| 79 | + return; |
| 80 | + } |
| 81 | + answer = ar.data; |
| 82 | + window.history.replaceState({}, "", `/${key}?id=${answer.id}`); |
| 83 | + } |
| 84 | +
|
| 85 | + // Fetch the summary. |
| 86 | + if (view === "summary") { |
| 87 | + fetchSummary(key); |
61 | 88 | } |
62 | | - answer = ar.data; |
63 | 89 | } catch (err) { |
64 | 90 | error = { |
65 | 91 | status: 500, |
|
70 | 96 | } |
71 | 97 | }; |
72 | 98 |
|
| 99 | + window.addEventListener("popstate", (event) => { |
| 100 | + initAnswer(); |
| 101 | + }); |
| 102 | +
|
73 | 103 | initAnswer(); |
74 | 104 | }); |
75 | 105 |
|
|
79 | 109 | } |
80 | 110 |
|
81 | 111 | try { |
82 | | - const ar = await updateAnswer(answer?.key, answer?.id, payload); |
| 112 | + const ar = await updateAnswer(answer?.id, payload); |
83 | 113 | if (ar.error) { |
84 | 114 | error = ar.error; |
85 | 115 | return; |
|
93 | 123 | } |
94 | 124 | }; |
95 | 125 |
|
96 | | - const handleSubmit = async () => { |
| 126 | + const fetchSummary = async (key?: string) => { |
97 | 127 | loading = true; |
98 | | - await handleChange({ submit: true }); |
99 | 128 | try { |
100 | | - const sr = await getSummary(answer?.key ?? ""); |
| 129 | + const sr = await getSummary(key ?? ""); |
101 | 130 | if (sr.error) { |
102 | 131 | error = sr.error; |
103 | 132 | return; |
|
112 | 141 | loading = false; |
113 | 142 | } |
114 | 143 | }; |
| 144 | +
|
| 145 | + const handleSubmit = async () => { |
| 146 | + loading = true; |
| 147 | + await handleChange({ submit: true }); |
| 148 | + view = "summary"; |
| 149 | + window.history.pushState({id: answer?.id}, "", `/${answer?.key}/summary`); |
| 150 | + await fetchSummary(answer?.key); |
| 151 | + loading = false; |
| 152 | + }; |
115 | 153 | </script> |
116 | 154 |
|
117 | 155 | <header> |
|
125 | 163 | <Loading /> |
126 | 164 | {:else if error} |
127 | 165 | <Error {error} /> |
128 | | - {:else if question && !answer?.submitted_at} |
| 166 | + {:else if question && view === "form"} |
129 | 167 | <fieldset> |
130 | 168 | <legend>{question.choice_text}</legend> |
131 | 169 | <RadioGroup |
|
145 | 183 | {/if} |
146 | 184 | <Submit onSubmit={handleSubmit} /> |
147 | 185 | {/if} |
148 | | - {:else if question && answer?.submitted_at && summary} |
| 186 | + {:else if question && view === "summary" && summary} |
149 | 187 | <div class="summary"> |
150 | 188 | <p>Thank you for your feedback!</p> |
151 | 189 | <BarChart choices={question.choices} {summary} /> |
|
0 commit comments