Merge pull request #203 from mawoka-myblock/save-game-results
This commit is contained in:
@@ -157,7 +157,11 @@
|
||||
"backup_code": "Backup-code",
|
||||
"totp": "Totp",
|
||||
"text": "Text",
|
||||
"order": "order"
|
||||
"order": "order",
|
||||
"results": "Results",
|
||||
"note": "Note",
|
||||
"player_plural": "Players",
|
||||
"score": "Score"
|
||||
},
|
||||
"editor": {
|
||||
"time_in_seconds": "Time in seconds",
|
||||
@@ -189,7 +193,8 @@
|
||||
"show_next_question": "Show next question",
|
||||
"start_by_showing_first_question": "Start by showing the first question.",
|
||||
"no_answers": "No answers!",
|
||||
"stop_time": "Stop time"
|
||||
"stop_time": "Stop time",
|
||||
"save_results": "Save results"
|
||||
},
|
||||
"password_reset_page": {
|
||||
"reset_password": "Reset password"
|
||||
@@ -253,5 +258,19 @@
|
||||
"clothe_graphic_type": "Graphic",
|
||||
"thats_you": "That's You!",
|
||||
"start_over": "Start over"
|
||||
},
|
||||
"results_page": {
|
||||
"no_results_so_far": "No results saved so far...",
|
||||
"quiz_title": "Quiz Title",
|
||||
"date_played": "Date Played",
|
||||
"player_count": "Player count"
|
||||
},
|
||||
"result_page": {
|
||||
"player_name": "Player name",
|
||||
"custom_field": "Custom field",
|
||||
"average_score": "Average score: {{average_score}}",
|
||||
"correct_answer": "{{count}} correct answer",
|
||||
"correct_answer_plural": "{{count}} correct answers",
|
||||
"time_taken": "Time taken"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { onMount } from 'svelte';
|
||||
import FinalResults from '$lib/play/admin/final_results.svelte';
|
||||
import GrayButton from '$lib/components/buttons/gray.svelte';
|
||||
|
||||
navbarVisible.set(false);
|
||||
|
||||
@@ -98,6 +99,10 @@
|
||||
}, 200);
|
||||
});
|
||||
|
||||
socket.on('results_saved_successfully', (_) => {
|
||||
results_saved = true;
|
||||
});
|
||||
|
||||
const confirmUnload = () => {
|
||||
if (warnToLeave) {
|
||||
event.preventDefault();
|
||||
@@ -110,6 +115,9 @@
|
||||
const request_answer_export = async () => {
|
||||
await socket.emit('get_export_token');
|
||||
};
|
||||
const save_quiz = async () => {
|
||||
await socket.emit('save_quiz');
|
||||
};
|
||||
|
||||
let darkMode = false;
|
||||
if (browser) {
|
||||
@@ -132,6 +140,7 @@
|
||||
};
|
||||
let bg_color;
|
||||
let bg_image;
|
||||
let results_saved = false;
|
||||
$: bg_color = quiz_data ? quiz_data.background_color : undefined;
|
||||
$: bg_image = quiz_data ? quiz_data.background_image : undefined;
|
||||
let show_final_results = false;
|
||||
@@ -152,9 +161,34 @@
|
||||
{#if JSON.stringify(final_results) !== JSON.stringify([null])}
|
||||
{#if control_visible}
|
||||
<div class="w-screen flex justify-center mt-16">
|
||||
<button on:click={request_answer_export} class="admin-button"
|
||||
>{$t('admin_page.export_results')}</button
|
||||
>
|
||||
<div class="w-fit">
|
||||
<GrayButton on:click={request_answer_export}
|
||||
>{$t('admin_page.export_results')}</GrayButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-screen flex justify-center mt-2">
|
||||
<div class="w-fit">
|
||||
<GrayButton on:click={save_quiz} flex={true} disabled={results_saved}>
|
||||
{#if results_saved}
|
||||
<svg
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5 13l4 4L19 7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
{:else}{$t('admin_page.save_results')}{/if}
|
||||
</GrayButton>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<FinalResults bind:data={player_scores} bind:show_final_results />
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<div class="w-full grid grid-cols-4 gap-2">
|
||||
<BrownButton href="/create">{$t('words.create')}</BrownButton>
|
||||
<BrownButton href="/import">{$t('words.import')}</BrownButton>
|
||||
<BrownButton href="/api/v1/users/logout">{$t('words.logout')}</BrownButton>
|
||||
<BrownButton href="/results">{$t('words.results')}</BrownButton>
|
||||
<BrownButton href="/account/settings">
|
||||
{$t('words.settings')}
|
||||
</BrownButton>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center w-full">
|
||||
<div class="w-11/12 m-auto">
|
||||
{#if data.results.length === 0}
|
||||
<p class="text-center text-3xl mt-8">{$t('results_page.no_results_so_far')}</p>
|
||||
{:else}
|
||||
<table class="w-full">
|
||||
<tr class="border-b-2 dark:border-gray-500 text-left border-gray-300">
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('results_page.quiz_title')}
|
||||
</th>
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('results_page.date_played')}
|
||||
</th>
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('results_page.player_count')}
|
||||
</th>
|
||||
<th class="mx-auto p-1">{$t('words.note')}</th>
|
||||
</tr>
|
||||
{#each data.results as result}
|
||||
<tr class="text-left">
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
><a href="/results/{result.id}" class="underline text-lg"
|
||||
>{result.title}</a
|
||||
></td
|
||||
>
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
>{new Date(result.timestamp).toLocaleString()}</td
|
||||
>
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
>{Object.keys(result.player_scores).length}</td
|
||||
>
|
||||
<td class:p-1={result.note}>
|
||||
{#if result.note}
|
||||
{result.note}
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ fetch }) => {
|
||||
const res = await fetch('/api/v1/results/list?include_quiz=true');
|
||||
let json;
|
||||
if (res.ok) {
|
||||
json = await res.json();
|
||||
} else {
|
||||
json = [];
|
||||
}
|
||||
return {
|
||||
results: json
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
@@ -0,0 +1,96 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { PageData } from './$types';
|
||||
import PlayerOverview from './player_overview.svelte';
|
||||
import QuestionOverview from './question_overview.svelte';
|
||||
import GeneralOverview from './general_overview.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
enum SelectedTab {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
Overview,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
Players,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
Questions
|
||||
}
|
||||
|
||||
let selected_tab: SelectedTab = SelectedTab.Overview;
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="flex flex-row w-full justify-around border-b-2 border-gray-500 mb-4">
|
||||
<div
|
||||
class="w-full py-2 flex transition-all hover:opacity-100"
|
||||
class:text-lg={selected_tab === SelectedTab.Overview}
|
||||
class:opacity-60={selected_tab !== SelectedTab.Overview}
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
selected_tab = SelectedTab.Overview;
|
||||
}}
|
||||
class="m-auto w-full h-full"
|
||||
>{$t('words.overview')}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="w-full py-2 flex border-x-2 border-gray-500 transition-all hover:opacity-100"
|
||||
class:text-lg={selected_tab === SelectedTab.Players}
|
||||
class:opacity-60={selected_tab !== SelectedTab.Players}
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
selected_tab = SelectedTab.Players;
|
||||
}}
|
||||
class="m-auto w-full h-full"
|
||||
>
|
||||
{$t('words.player', { count: 2 })}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="w-full py-2 flex transition-all hover:opacity-100"
|
||||
class:text-lg={selected_tab === SelectedTab.Questions}
|
||||
class:opacity-60={selected_tab !== SelectedTab.Questions}
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
selected_tab = SelectedTab.Questions;
|
||||
}}
|
||||
class="m-auto w-full h-full"
|
||||
>{$t('words.question', { count: 2 })}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{#if selected_tab === SelectedTab.Overview}
|
||||
<div in:fade={{ duration: 150 }}>
|
||||
<GeneralOverview
|
||||
questions={data.results.questions}
|
||||
answers={data.results.answers}
|
||||
scores={data.results.player_scores}
|
||||
title={data.results.title}
|
||||
timestamp={data.results.timestamp}
|
||||
/>
|
||||
</div>
|
||||
{:else if selected_tab === SelectedTab.Questions}
|
||||
<div in:fade={{ duration: 150 }}>
|
||||
<QuestionOverview questions={data.results.questions} answers={data.results.answers} />
|
||||
</div>
|
||||
{:else if selected_tab === SelectedTab.Players}
|
||||
<div in:fade={{ duration: 150 }}>
|
||||
<PlayerOverview
|
||||
custom_field={data.results.custom_field_data}
|
||||
scores={data.results.player_scores}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// import type { PageLoad } from './$types';
|
||||
|
||||
export const load = async ({ params, fetch }) => {
|
||||
const res = await fetch(`/api/v1/results/${params.result_id}?include_quiz=true`);
|
||||
let json;
|
||||
if (res.ok) {
|
||||
json = await res.json();
|
||||
} else {
|
||||
json = undefined;
|
||||
}
|
||||
return {
|
||||
results: json
|
||||
};
|
||||
}; //satisfies PageLoad;
|
||||
@@ -0,0 +1,56 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Question } from '$lib/quiz_types';
|
||||
|
||||
export let questions: Question[];
|
||||
export let answers: {
|
||||
username: string;
|
||||
answer: string;
|
||||
right: boolean;
|
||||
tike_taken: number;
|
||||
score: number;
|
||||
}[][];
|
||||
|
||||
export let scores: {
|
||||
[key: string]: string;
|
||||
};
|
||||
export let title: string;
|
||||
export let timestamp: string;
|
||||
|
||||
const usernames = Object.keys(scores);
|
||||
|
||||
const get_average_final_score = () => {
|
||||
let score_data = 0;
|
||||
for (const username of usernames) {
|
||||
score_data += parseInt(scores[username]);
|
||||
}
|
||||
return score_data / usernames.length;
|
||||
};
|
||||
</script>
|
||||
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center w-full">
|
||||
<p class="text-3xl w-5/6 text-center">
|
||||
The quiz with the title '<strong>{title}</strong>' was played on
|
||||
<strong>{new Date(timestamp).toLocaleString()}</strong>
|
||||
with <strong>{usernames.length}</strong> players. The players achieved an average score
|
||||
of <strong>{get_average_final_score()}</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
export let scores: {
|
||||
[key: string]: string;
|
||||
};
|
||||
export let custom_field: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
let usernames = Object.keys(scores);
|
||||
console.log(custom_field);
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center w-full">
|
||||
<table class="w-11/12 m-auto">
|
||||
<tr class="border-b-2 dark:border-gray-500 text-left border-gray-300">
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.player_name')}
|
||||
</th>
|
||||
<th class="p-1 mx-auto">Player Score</th>
|
||||
{#if Object.keys(custom_field).length !== 0}
|
||||
<th class="border-l dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.custom_field')}
|
||||
</th>
|
||||
{/if}
|
||||
</tr>
|
||||
{#each usernames as uname}
|
||||
<tr class="text-left">
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300">{uname}</td>
|
||||
<td class="p-1">{scores[uname]}</td>
|
||||
{#if custom_field[uname]}
|
||||
<td class="border-l dark:border-gray-500 p-1 border-gray-300"
|
||||
>{custom_field[uname]}</td
|
||||
>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,87 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { Question } from '$lib/quiz_types';
|
||||
import { fly } from 'svelte/transition';
|
||||
import QuestionTab from './question_tab_thing.svelte';
|
||||
import { QuizQuestionType } from '$lib/quiz_types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let questions: Question[];
|
||||
export let answers: {
|
||||
username: string;
|
||||
answer: string;
|
||||
right: boolean;
|
||||
tike_taken: number;
|
||||
score: number;
|
||||
}[][];
|
||||
|
||||
const get_average_score = (q_index: number): number => {
|
||||
const q_answers = answers[q_index];
|
||||
let summed_up_scores = 0;
|
||||
for (const answer of q_answers) {
|
||||
summed_up_scores = summed_up_scores + answer.score;
|
||||
}
|
||||
return summed_up_scores / q_answers.length;
|
||||
};
|
||||
|
||||
const get_number_of_correct_answers = (q_index: number): number => {
|
||||
const q_answers = answers[q_index];
|
||||
let correct_answer = 0;
|
||||
for (const answer of q_answers) {
|
||||
if (answer.right) {
|
||||
correct_answer++;
|
||||
}
|
||||
}
|
||||
return correct_answer;
|
||||
};
|
||||
|
||||
const toggle_dropdown = (q_index: number) => {
|
||||
if (question_open === q_index) {
|
||||
question_open = false;
|
||||
} else {
|
||||
question_open = q_index;
|
||||
}
|
||||
};
|
||||
let question_open: number | boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="w-full flex justify-center">
|
||||
<div class="w-11/12 flex flex-col w-full gap-4">
|
||||
{#each questions as question, i}
|
||||
<div class="transition-all">
|
||||
<div class="w-full bg-white bg-opacity-60 p-2 rounded grid grid-cols-3 z-40">
|
||||
<button
|
||||
class="text-center underline text-xl"
|
||||
on:click={() => {
|
||||
toggle_dropdown(i);
|
||||
}}>{@html question.question}</button
|
||||
>
|
||||
{#if question.type !== QuizQuestionType.VOTING}
|
||||
{@const correct_answers = get_number_of_correct_answers(i)}
|
||||
<p class="text-center text-sm my-auto">
|
||||
{$t('result_page.average_score', {
|
||||
average_score: get_average_score(i)
|
||||
})}
|
||||
</p>
|
||||
<p class="text-center text-sm my-auto">
|
||||
{$t('result_page.correct_answer', { count: correct_answers })}
|
||||
<!-- {correct_answers} correct
|
||||
{#if correct_answers === 1}Answer{:else}Answers{/if}-->
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if question_open === i}
|
||||
<div in:fly|local={{ y: -10 }}>
|
||||
<QuestionTab {question} answers={answers[i]} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,110 @@
|
||||
<!--
|
||||
- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { QuizQuestionType } from '$lib/quiz_types';
|
||||
import { getLocalization } from '$lib/i18n';
|
||||
|
||||
const { t } = getLocalization();
|
||||
|
||||
export let question;
|
||||
|
||||
interface Answer {
|
||||
username: string;
|
||||
answer: string;
|
||||
right: boolean;
|
||||
time_taken: number;
|
||||
score: number;
|
||||
}
|
||||
|
||||
export let answers: Answer[];
|
||||
// console.log(question);
|
||||
|
||||
const get_answer_count_for_answer = (answer: string): number => {
|
||||
let count = 0;
|
||||
for (const a of answers) {
|
||||
if (a.answer === answer) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<div class="bg-white p-2 -z-10 w-10/12 rounded">
|
||||
{#if question.type !== QuizQuestionType.ORDER && question.type !== QuizQuestionType.RANGE}
|
||||
<div class="flex flex-col mb-4">
|
||||
{#each question.answers as answer}
|
||||
<div class="grid grid-cols-4">
|
||||
<p>{answer.answer}</p>
|
||||
<div
|
||||
class="col-span-3 flex w-full border-l border-gray-300 px-1 dark:border-gray-500"
|
||||
>
|
||||
<div class="my-auto w-full mr-1">
|
||||
<span
|
||||
class="h-1 block bg-green-600 my-auto"
|
||||
style="width: {(get_answer_count_for_answer(answer.answer) /
|
||||
answers.length) *
|
||||
100}%"
|
||||
/>
|
||||
</div>
|
||||
<p>{get_answer_count_for_answer(answer.answer)}</p>
|
||||
{#if question.type !== QuizQuestionType.VOTING && question.type !== QuizQuestionType.TEXT}
|
||||
<p class="ml-1">
|
||||
{#if answer.right}✅{:else}❌{/if}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
<table class="w-full text-left">
|
||||
<tr class="border-b-2 dark:border-gray-500 text-left border-gray-300">
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.player_name')}
|
||||
</th>
|
||||
{#if question.type !== QuizQuestionType.VOTING}
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('words.score')}</th
|
||||
>
|
||||
{/if}
|
||||
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('result_page.time_taken')}
|
||||
</th>
|
||||
<th class="p-1 mx-auto">{$t('words.answer')} </th>
|
||||
{#if question.type !== QuizQuestionType.VOTING}
|
||||
<th class="border-l dark:border-gray-500 p-1 mx-auto border-gray-300"
|
||||
>{$t('words.correct')}?</th
|
||||
>
|
||||
{/if}
|
||||
</tr>
|
||||
{#each answers as answer}
|
||||
<tr>
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
>{answer.username}</td
|
||||
>
|
||||
{#if question.type !== QuizQuestionType.VOTING}
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
>{answer.score}</td
|
||||
>
|
||||
{/if}
|
||||
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
|
||||
>{(answer.time_taken / 1000).toFixed(3)}s
|
||||
</td>
|
||||
<td class="p-1">{answer.answer}</td>
|
||||
{#if question.type !== QuizQuestionType.VOTING}
|
||||
<td class="p-1 border-l dark:border-gray-500 border-gray-300">
|
||||
{#if answer.right}✅{:else}❌{/if}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user