hackathon/web_src/routes/dashboard/question/[id]@dashboard.svelte

225 lines
5.4 KiB
Svelte

<script lang="ts">
import SvelteMarkdown from 'svelte-markdown';
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { getContext, onMount } from 'svelte';
import { type Question, QuestService } from '$lib/pb/all.pb';
import { withToken } from '$lib/pb/pbutil';
import { auth } from '$lib/stores';
import ErrorModal from '$lib/components/ErrorModal.svelte';
import SubmitModal from '$lib/components/SubmitModal.svelte';
type Status = 'available' | 'partial' | 'full';
const { open } = getContext('simple-modal');
let id = $page.params.id;
let q: Question;
let status: Status = 'available';
let solved = 0;
$: {
if (q?.part1?.completed && q?.part2?.completed) {
status = 'full';
solved = 2;
} else if (q?.part1?.completed || q?.part2?.completed) {
status = 'partial';
solved = 1;
} else {
status = 'available';
solved = 0;
}
}
const loadQuestion = () => {
QuestService.QuestionByID({ id }, withToken($auth.token))
.then((question) => {
q = question;
})
.catch((err) => {
open(ErrorModal, {
title: 'Could not load',
reason: err.message || 'Something went wrong',
btn: {
title: 'Go to questions',
do: () => {
goto('/dashboard/questions');
}
}
});
});
};
let queried = false;
onMount(() => {
auth.subscribe(() => {
if (!queried && $auth.loggedIn()) {
queried = true;
loadQuestion();
}
});
});
let value = '';
const submit = () => {
if (value == '') {
open(ErrorModal, { title: 'Could not Submit', reason: 'Please provide a value to submit' });
return;
}
let part = 1;
switch (solved) {
case 0:
part = 1;
break;
case 1:
part = 2;
break;
default:
return;
}
// @ts-ignore
QuestService.Submit({ id, Body: { answer: value, code: '' }, part }, withToken($auth.token))
.then((sr) => {
open(SubmitModal, { ...sr, part });
value = '';
if (sr.correct) {
$auth.info.points += sr.points;
}
loadQuestion();
})
.catch((err) => {
open(ErrorModal, {
reason: err.message || 'Something went wrong'
});
});
};
</script>
<svelte:head>
<title>{q?.title || ''} | CodeQuest</title>
</svelte:head>
{#if q}
<div class="relative flex min-h-[calc(100vh-164px)] pb-8 mx-2">
<main class="container mx-auto pt-4 flex flex-col gap-4">
<div class="grid grid-cols-1 gap-4">
<div class={`box h-24 ${status}`}>
<span class="font-bold text-4xl">{q.title}</span>
</div>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-4 xl:grid-cols-5">
<a class="box h-12 hover:bg-neutral-200 border-neutral-300" href="/dashboard/questions">
<span class="txt text-neutral-600 flex items-center gap-1">
<!-- prettier-ignore -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Puzzles
</span>
</a>
<div class="box h-12 border-indigo-600 md:col-span-2 md:col-end-5 xl:col-end-6">
<div class="txt text-indigo-600 flex px-4 w-full items-center justify-between">
<span>
Progress: {solved}/2
</span>
<span>
Points Earned: {q.part1.pointsWorth + q.part2.pointsWorth}
</span>
</div>
</div>
</div>
<div class="relative">
<div class="grid grid-cols-1 lg:grid-cols-5 gap-4">
<div
class="prose text-justify md:col-span-1 lg:col-span-3 md:justify-self-center lg:justify-self-start"
>
<SvelteMarkdown source={q.text} />
</div>
{#if solved != 2}
<div class="submit h-[600px]">
<a
class="btn ghost mb-2 py-2 rounded-md"
href={`/dashboard/question/${id}/input`}
target="_blank"
>
View Puzzle Input
</a>
<form class="flex gap-4 h-12" on:submit|preventDefault={submit}>
<input
type="text"
bind:value
placeholder={`Answer Part ${solved + 1}`}
class="rounded-md shadow-md border w-3/4 font-mono"
/>
<input
type="submit"
value="Submit"
class="btn ghost rounded-md shadow-md w-1/4 cursor-pointer"
/>
</form>
</div>
{:else}
<div class="submit h-[600px]">
<a
class="btn ghost mb-2 py-2 rounded-md"
href={`/dashboard/question/${id}/input`}
target="_blank"
>
View Puzzle Input
</a>
<form class="flex gap-4 h-12">
<input
type="text"
disabled
value={'Puzzle Solved'}
class="rounded-md shadow-md border font-mono bg-neutral-300 w-full"
/>
</form>
</div>
{/if}
</div>
</div>
</main>
</div>
{/if}
<style lang="postcss">
.box {
@apply flex items-center justify-center w-full rounded-md shadow-md border;
@apply transition;
}
.available {
@apply border-gray-400 hover:bg-gray-100;
@apply text-gray-600;
}
.partial {
@apply border-yellow-400 bg-yellow-50 hover:bg-yellow-100;
@apply text-yellow-700;
}
.full {
@apply border-green-400 bg-green-50 hover:bg-green-100;
@apply text-green-700;
}
.txt {
@apply font-bold tracking-wider uppercase;
}
.question {
}
.submit {
@apply w-3/4 md:w-1/2 lg:w-3/4 sticky top-12 mt-8;
@apply md:justify-self-center xl:justify-self-end;
@apply lg:col-span-2 lg:col-end-6;
}
</style>