add feedback endpoint (#28) and some other stuff
All checks were successful
delpoy / build-and-deploy (push) Successful in 1m11s

This commit is contained in:
2024-11-29 01:52:19 +01:00
parent dc86dceb2f
commit dc3a404a5b
30 changed files with 599 additions and 104 deletions

View File

@@ -0,0 +1,7 @@
import type { PageLoad } from './$types';
import { redirect } from '@sveltejs/kit';
import { env } from '$env/dynamic/public';
export const load: PageLoad = async () => {
throw redirect(302, `${env.PUBLIC_BASE_PATH}/`);
};

View File

@@ -0,0 +1,3 @@
<div class="flex justify-center items-center w-full min-h-screen h-full">
<slot />
</div>

View File

@@ -0,0 +1,18 @@
import type { PageServerLoad } from './$types';
import { Feedback } from '$lib/server/database';
import { redirect } from '@sveltejs/kit';
import { env } from '$env/dynamic/public';
export const load: PageServerLoad = async ({ params }) => {
const feedback = await Feedback.findOne({
where: { url_hash: params.url_hash }
});
if (!feedback) throw redirect(302, `${env.PUBLIC_BASE_PATH}/`);
return {
draft: feedback.content === null,
event: feedback.event,
anonymous: feedback.user_id === null
};
};

View File

@@ -0,0 +1,30 @@
<script lang="ts">
import { fly } from 'svelte/transition';
import type { PageData } from './$types';
import FeedbackDraft from './FeedbackDraft.svelte';
import FeedbackSent from './FeedbackSent.svelte';
export let data: PageData;
</script>
<svelte:head>
<title>Feedback</title>
<!-- just in case... -->
<meta name="robots" content="noindex" />
</svelte:head>
<div class="absolute top-12 grid card w-11/12 xl:w-2/3 2xl:w-1/2 p-6 shadow-lg">
{#if data.draft}
<div class="col-[1] row-[1]" transition:fly={{ x: -200, duration: 300 }}>
<FeedbackDraft
event={data.event}
anonymous={data.anonymous}
on:submit={() => (data.draft = false)}
/>
</div>
{:else}
<div class="col-[1] row-[1]" transition:fly={{ x: 200, duration: 300 }}>
<FeedbackSent />
</div>
{/if}
</div>

View File

@@ -0,0 +1,24 @@
import type { RequestHandler } from '@sveltejs/kit';
import { Feedback } from '$lib/server/database';
import { FeedbackSubmitSchema } from './schema';
export const POST = (async ({ request, params }) => {
const feedback = await Feedback.findOne({ where: { url_hash: params.url_hash } });
if (feedback == null) return new Response(null, { status: 400 });
const parseResult = await FeedbackSubmitSchema.safeParseAsync(await request.json());
if (!parseResult.success) {
return new Response(null, { status: 400 });
}
const data = parseResult.data;
feedback.content = data.content;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (data.anonymous) feedback.user_id = null;
await feedback.save();
return new Response(null, { status: 200 });
}) satisfies RequestHandler;

View File

@@ -0,0 +1,78 @@
<script lang="ts">
import Input from '$lib/components/Input/Input.svelte';
import Textarea from '$lib/components/Input/Textarea.svelte';
import { createEventDispatcher } from 'svelte';
import { env } from '$env/dynamic/public';
import { page } from '$app/stores';
export let event: string;
export let anonymous: boolean;
const dispatch = createEventDispatcher();
let content = '';
let sendAnonymous = true;
let submitModal: HTMLDialogElement;
async function submitFeedback() {
await fetch(`${env.PUBLIC_BASE_PATH}/feedback/${$page.params.url_hash}`, {
method: 'POST',
body: JSON.stringify({
content: content,
anonymous: sendAnonymous
})
});
}
</script>
<div>
<h2 class="text-3xl text-center">Feedback</h2>
<form on:submit|preventDefault={() => submitModal.show()}>
<div class="space-y-4 my-4">
<Input size="sm" pickyWidth={false} disabled value={event}>
<span slot="label">Event</span>
</Input>
<Textarea required={true} rows={4} label="Feedback" bind:value={content} />
<div>
<Input type="submit" disabled={content === ''} value="Feedback senden" />
</div>
</div>
</form>
</div>
<dialog class="modal" bind:this={submitModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">Feedback abschicken?</h3>
<div class="my-4">
<p>Nach dem Abschicken des Feedbacks lässt es sich nicht mehr bearbeiten.</p>
{#if !anonymous}
<div class="flex items-center gap-2 mt-2">
<Input type="checkbox" id="anonymous" size="xs" checked />
<label
for="anonymous"
title="Dein Spielername wird nach dem Abschicken nicht mit dem Feedback zusammen gespeichert"
>Anonym senden</label
>
</div>
{/if}
</div>
<div class="flex flex-row space-x-1">
<Input
type="submit"
value="Abschicken"
on:click={async () => {
await submitFeedback();
dispatch('submit');
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>

View File

@@ -0,0 +1,4 @@
<div>
<h2 class="text-2xl text-center">Feedback abgeschickt</h2>
<p class="mt-4">Das Feedback wurde abgeschickt.</p>
</div>

View File

@@ -0,0 +1,6 @@
import { z } from 'zod';
export const FeedbackSubmitSchema = z.object({
content: z.string(),
anonymous: z.boolean()
});