Files
Jeopardy/src/lib/Wall.svelte

172 lines
5.9 KiB
Svelte

<script lang="ts">
import axios from "axios";
import {
isWall,
type Category,
type CategoryId,
type QuestionId,
type VisitedQuestions,
type Wall
} from "./Types";
import { url } from "./util";
import { onMount } from "svelte";
import type { FullWall } from "./games/games";
import Button from "./Button.svelte";
import Modal from "./Modal.svelte";
import Textfield from "./Textfield.svelte";
import { fetchCategory } from "../routes/editor/fetchers";
interface Props {
wall: Wall | FullWall | undefined;
onclick?: (catIndex: number, questionIndex: number) => unknown;
onclickIds?: (catId: CategoryId, questionId: QuestionId) => unknown;
visited: VisitedQuestions;
isEditor?: boolean;
}
function isVisited(catIndex: number, queIndex: number): boolean {
return visited[catIndex] && visited[catIndex].includes(queIndex);
}
let { wall, onclick, onclickIds, visited, isEditor = false }: Props = $props();
let categories: Category[] = $state([]);
let showRenameCategory = $state(false);
let catToRename: Category | undefined = $state();
let newCatName = $state("");
let error = $state("");
async function fetchCategories(wall: Wall | FullWall | undefined) {
if (wall && isWall(wall)) {
let cats: Promise<Category>[] = [];
for (const catId of wall.categories) {
cats.push(fetchCategory(catId));
}
return Promise.all(cats).then((cats) => {
categories = cats;
});
}
}
async function renameCategory() {
if (!newCatName || !catToRename) return false;
return axios
.post(
url(`/category/rename`),
{
categoryid: catToRename._id,
name: newCatName
},
{ withCredentials: true }
)
.then((response) => {
if (response.status === 200) {
newCatName = "";
catToRename = undefined;
fetchCategories(wall);
return true;
} else {
console.error(`Failed to rename category: ${response.status}`);
return false;
}
})
.catch((err) => {
console.error(err);
return false;
});
}
function renameCategoryCancel() {
newCatName = "";
catToRename = undefined;
}
$effect(() => {
fetchCategories(wall);
});
onMount(() => {
fetchCategories(wall);
});
</script>
{#if wall != undefined}
<div class="grid h-full grow grid-flow-col grid-cols-5 grid-rows-6 gap-4 pb-4">
{#if isWall(wall)}
{#each categories as category, catIndex}
<div class="flex items-center justify-center gap-2 text-3xl font-semibold">
<div>{category.name}</div>
{#if isEditor}
<Button
onclick={() => {
catToRename = category;
newCatName = category.name;
showRenameCategory = true;
}}><i class="fa-solid fa-pen"></i></Button
>
{/if}
</div>
{#each category.questions as question, queIndex}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="card {isVisited(catIndex, queIndex) ? 'visited' : ''}"
role="button"
aria-pressed="false"
tabindex="0"
onclick={() => {
if (onclickIds) onclickIds(category._id, question._id);
}}
>
<div class="text-6xl font-thin">
{question.points >= 0 ? question.points : "???"}
</div>
</div>
{/each}
{/each}
{:else}
{#each wall.categories as category, catIndex}
<div class="flex items-center justify-center text-3xl font-semibold">
<div>{category.name}</div>
</div>
{#each category.questions as question, queIndex}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="card {isVisited(catIndex, queIndex) ? 'visited' : ''}"
role="button"
aria-pressed="false"
tabindex="0"
onclick={() => {
if (onclick) onclick(catIndex, queIndex);
}}
>
<div class="text-6xl font-thin">
{question.points >= 0 ? question.points : "???"}
</div>
</div>
{/each}
{/each}
{/if}
</div>
{:else}
<p>Wall is undefined</p>
{/if}
<Modal bind:showModal={showRenameCategory} okFn={renameCategory} cancelFn={renameCategoryCancel}>
{#snippet header()}
<h2 class="text-3xl">Kategorie umbenennen</h2>
{/snippet}
<div>
<Textfield bind:value={newCatName} label="Name"></Textfield>
{#if error.length > 0}
<div class="text-red-700">{error}</div>
{/if}
</div>
</Modal>
<style>
.visited {
background-color: gray;
}
</style>