Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion back-end/feedback/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ def question_answers(request: HttpRequest, key: str):

@_feedback_error_as_json
def answer(request: HttpRequest, id_: str):
if request.method != "PATCH":
if request.method not in ["GET", "PATCH"]:
raise FeedbackError("Method not allowed", 405)

try:
a = Answer.objects.get(id=id_)
except Answer.DoesNotExist:
raise FeedbackError("Answer not found", 404)

if request.method == "GET":
return JsonResponse(a.json)

data = _parse_json_body(request)
if data.pop("submit", None):
a.submitted_at = datetime.now(timezone.utc)
Expand Down
2 changes: 1 addition & 1 deletion front-end/default.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ server {

location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html /index.htm;
}

location /static/ {
Expand Down
66 changes: 52 additions & 14 deletions front-end/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import RadioGroup from "./lib/RadioGroup.svelte";
import {
createAnswer,
getAnswer,
getQuestion,
getSummary,
updateAnswer,
Expand All @@ -23,6 +24,7 @@
import Footer from "./lib/Footer.svelte";

let loading = $state(true);
let view = $state<string>("form");
let error = $state<Problem | null>(null);
let question = $state<Question | null>(null);
let answer = $state<Answer | null>(null);
Expand All @@ -34,9 +36,15 @@
// Wait until the server has started.
await waitUntilLive();

// Parse the question key from URL query parameters.
// 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 = query.get("key");

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,
Expand All @@ -45,6 +53,15 @@
return;
}

view = pathComponents[1] || "form";
if (["form", "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) {
Expand All @@ -53,13 +70,22 @@
}
question = qr.data;

// Initialize the answer.
const ar = await createAnswer(key);
if (ar.error) {
error = ar.error;
return;
// 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);
}
answer = ar.data;
} catch (err) {
error = {
status: 500,
Expand All @@ -70,6 +96,10 @@
}
};

window.addEventListener("popstate", (event) => {
initAnswer();
});

initAnswer();
});

Expand All @@ -79,7 +109,7 @@
}

try {
const ar = await updateAnswer(answer?.key, answer?.id, payload);
const ar = await updateAnswer(answer?.id, payload);
if (ar.error) {
error = ar.error;
return;
Expand All @@ -93,11 +123,10 @@
}
};

const handleSubmit = async () => {
const fetchSummary = async (key?: string) => {
loading = true;
await handleChange({ submit: true });
try {
const sr = await getSummary(answer?.key ?? "");
const sr = await getSummary(key ?? "");
if (sr.error) {
error = sr.error;
return;
Expand All @@ -112,6 +141,15 @@
loading = 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;
};
</script>

<header>
Expand All @@ -125,7 +163,7 @@
<Loading />
{:else if error}
<Error {error} />
{:else if question && !answer?.submitted_at}
{:else if question && view === "form"}
<fieldset>
<legend>{question.choice_text}</legend>
<RadioGroup
Expand All @@ -145,7 +183,7 @@
{/if}
<Submit onSubmit={handleSubmit} />
{/if}
{:else if question && answer?.submitted_at && summary}
{:else if question && view === "summary" && summary}
<div class="summary">
<p>Thank you for your feedback!</p>
<BarChart choices={question.choices} {summary} />
Expand Down
6 changes: 5 additions & 1 deletion front-end/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export const getQuestion = async (
return buildResponse<Question>(response);
};

export const getAnswer = async (id: string): Promise<APIResponse<Answer>> => {
const response = await fetch(`${baseUrl()}/answer/${id}`);
return buildResponse<Answer>(response);
};

export const createAnswer = async (
key: string,
): Promise<APIResponse<Answer>> => {
Expand All @@ -82,7 +87,6 @@ export const createAnswer = async (
};

export const updateAnswer = async (
key: string,
id: string,
payload: UpdateAnswerPayload,
): Promise<APIResponse<Answer>> => {
Expand Down
6 changes: 3 additions & 3 deletions test/suites/send_feedback.robot
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ${URL} %{BASE_URL}

*** Test cases ***
Open feedback form
New Page ${URL}?key=thumbs
New Page ${URL}/thumbs
Wait For Elements State text=How are you feeling? timeout=1 minute

Send positive feedback
Expand All @@ -21,13 +21,13 @@ Check feedback was recorded
Get value count Thumbs up 1

Send another positive feedback and check summary
Reload
New Page ${URL}/thumbs
Click text=👍
Click text=Submit
Get value count Thumbs up 2

Send negative feedback and check summary
Reload
New Page ${URL}/thumbs
Click text=👎
Click text=Submit
Get value count Thumbs down 1
Expand Down