Bug fixes and correct answer count in results

This commit is contained in:
Mawoka
2025-10-25 22:49:02 +02:00
parent 932f8dfbcf
commit caa2a6002f
37 changed files with 164 additions and 157 deletions
+3 -3
View File
@@ -216,7 +216,7 @@ async def register_as_admin(sid: str, data: dict):
if await redis.get(f"game_session:{game_pin}") is not None:
await sio.emit("already_registered_as_admin", room=sid)
return
GameSession(admin=sid, game_id=game_id, answers=[]).save(game_pin)
await GameSession(admin=sid, game_id=game_id, answers=[]).save(game_pin)
await sio.emit(
"registered_as_admin",
{"game_id": game_id, "game": await redis.get(f"game:{game_pin}")},
@@ -251,7 +251,7 @@ async def set_question_number(sid: str, data: str):
game_data = await PlayGame.get_from_redis(session["game_pin"])
game_data.current_question = int(float(data))
game_data.question_show = True
game_data.save(session["game_pin"])
await game_data.save(session["game_pin"])
await redis.set(f"game:{session['game_pin']}:current_time", datetime.now().isoformat(), ex=7200)
temp_return = game_data.model_dump(include={"questions"})["questions"][int(float(data))]
if game_data.questions[int(float(data))].type == QuizQuestionType.SLIDE:
@@ -296,7 +296,7 @@ async def submit_answer(sid: str, data: dict):
if already_answered:
await sio.emit("already_replied", room=sid)
return
(answer_right, answer) = check_answer(game_data, data)
answer_right, answer = check_answer(game_data, data)
latency = int(float(session["ping"]))
time_q_started = datetime.fromisoformat(await redis.get(f"game:{session['game_pin']}:current_time"))
diff = (time_q_started - now).total_seconds() * 1000 # - timedelta(milliseconds=latency)
+7 -11
View File
@@ -30,7 +30,6 @@ async def check_captcha(captcha_data: str) -> bool:
) as resp:
resp_data = await resp.model_dump_json()
if not resp_data["success"]:
print("CAPTCHA FAILED")
return
except KeyError:
return False
@@ -60,7 +59,7 @@ def check_answer(game_data: PlayGame, data: SubmitAnswerData) -> (bool, str):
q_answers = game_data.questions[q_i].answers
q_answer = data.answer
if q_type == QuizQuestionType.ABCD:
return (check_abcd_question, data.answer)
return (check_abcd_question(q_answer, q_answers), data.answer)
elif q_type == QuizQuestionType.RANGE:
return (
check_range_question(q_answer, q_answers),
@@ -69,7 +68,7 @@ def check_answer(game_data: PlayGame, data: SubmitAnswerData) -> (bool, str):
elif q_type == QuizQuestionType.VOTING:
return (False, q_answer)
elif q_type == QuizQuestionType.ORDER:
return check_order_question(q_answer, q_answers)
return check_order_question(data.complex_answer, q_answer, q_answers)
elif q_type == QuizQuestionType.TEXT:
return (
check_text_question(q_answer, q_answers),
@@ -105,14 +104,11 @@ def check_order_question(
) -> (bool, str):
if complex_answer is None:
return (False, answer)
correct_answers = []
for a in answers:
correct_answers.append({"answer": a.answer})
answer_order = []
for a in complex_answer.model_dump():
answer_order.append(a["answer"])
answer = ", ".join(answer_order)
return (correct_answers == complex_answer.model_dump(), answer)
correct_answers = [{"answer": a.answer} for a in answers]
submitted_answers = [{"answer": a.answer} for a in complex_answer]
answer_str = ", ".join(a["answer"] for a in submitted_answers)
is_correct = submitted_answers == correct_answers
return is_correct, answer_str
def check_text_question(answer: str, answers: list[TextQuizAnswer]) -> bool:
@@ -5,19 +5,14 @@ SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
import { createBubbler } from 'svelte/legacy';
const bubble = createBubbler();
interface Props {
disabled?: boolean;
flex?: boolean;
href?: undefined | string;
target?: undefined | string;
type?: undefined | string;
type?: 'button' | 'submit' | 'reset';
children?: import('svelte').Snippet;
onclick?: (event: MouseEvent) => void;
}
let {
@@ -26,7 +21,8 @@ SPDX-License-Identifier: MPL-2.0
href = undefined,
target = '_self',
type = 'button',
children
children,
onclick
}: Props = $props();
</script>
@@ -39,7 +35,7 @@ SPDX-License-Identifier: MPL-2.0
class:cursor-not-allowed={disabled}
class:pointer-events-none={disabled}
class="text-black hover:bg-bg-[#B07156]/80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center outline-hidden hover:cursor-pointer"
onclick={bubble('click')}
{onclick}
class:flex
class:justify-center={flex}
>
@@ -50,7 +46,7 @@ SPDX-License-Identifier: MPL-2.0
{disabled}
{type}
class="text-black hover:cursor-pointer hover:opacity-80 w-full px-4 py-2 leading-5 transition-all duration-200 transform bg-[#B07156] rounded-sm text-center focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 outline-hidden"
onclick={bubble('click')}
{onclick}
class:flex
class:justify-center={flex}
>
@@ -5,16 +5,13 @@ SPDX-License-Identifier: MPL-2.0
-->
<script lang="ts">
import { createBubbler } from 'svelte/legacy';
const bubble = createBubbler();
interface Props {
disabled?: boolean;
flex?: boolean;
href?: undefined | string;
target?: undefined | string;
children?: import('svelte').Snippet;
onclick?: (event: MouseEvent) => void;
}
let {
@@ -22,7 +19,8 @@ SPDX-License-Identifier: MPL-2.0
flex = false,
href = undefined,
target = '_self',
children
children,
onclick
}: Props = $props();
</script>
@@ -31,7 +29,7 @@ SPDX-License-Identifier: MPL-2.0
{href}
{target}
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
onclick={bubble('click')}
{onclick}
class:flex
class:block={!flex}
class:justify-center={flex}
@@ -42,7 +40,7 @@ SPDX-License-Identifier: MPL-2.0
<button
{disabled}
class="w-full px-4 py-2 leading-5 text-black dark:text-white transition-colors duration-200 transform bg-gray-50 dark:bg-gray-700 rounded-sm text-center hover:bg-gray-300 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-gray-600"
onclick={bubble('click')}
{onclick}
class:flex
class:justify-center={flex}
>
+7 -5
View File
@@ -34,7 +34,11 @@ SPDX-License-Identifier: MPL-2.0
edit_id: string;
}
let { data = $bindable(), selected_question = $bindable(), edit_id = $bindable() }: Props = $props();
let {
data = $bindable(),
selected_question = $bindable(),
edit_id = $bindable()
}: Props = $props();
let advanced_options_open = $state(false);
@@ -155,9 +159,7 @@ SPDX-License-Identifier: MPL-2.0
'questions[].question'
).isValidSync(data.questions[selected_question].question)}
>
<c.default
bind:text={data.questions[selected_question].question}
/>
<c.default bind:text={data.questions[selected_question].question} />
</div>
{/await}
{/key}
@@ -287,7 +289,7 @@ SPDX-License-Identifier: MPL-2.0
/>
</label>
<div class="mt-auto w-full">
<BrownButton on:click={() => (advanced_options_open = false)}
<BrownButton onclick={() => (advanced_options_open = false)}
>{$t('words.close')}</BrownButton
>
</div>
+1 -1
View File
@@ -76,7 +76,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="h-screen relative">
<div class="h-10 flex justify-center w-full p-1 absolute z-20">
<div>
<BrownButton on:click={() => (reorder_mode = !reorder_mode)}
<BrownButton onclick={() => (reorder_mode = !reorder_mode)}
>{#if reorder_mode}{$t('editor.disable_reorder')}{:else}{$t(
'editor.enable_reorder'
)}{/if}</BrownButton
+5 -5
View File
@@ -150,7 +150,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="flex flex-row gap-4">
<div class="w-full">
<BrownButton
on:click={() => {
onclick={() => {
selected_type = AvailableUploadTypes.Image;
}}
>{$t('words.image')}
@@ -159,7 +159,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-full">
<BrownButton
disabled={!video_upload}
on:click={() => {
onclick={() => {
selected_type = AvailableUploadTypes.Video;
}}
>{$t('words.video')}
@@ -168,7 +168,7 @@ SPDX-License-Identifier: MPL-2.0
{#if library_enabled}
<div class="w-full">
<BrownButton
on:click={() => {
onclick={() => {
selected_type = AvailableUploadTypes.Library;
}}
>{$t('words.library')}
@@ -177,7 +177,7 @@ SPDX-License-Identifier: MPL-2.0
{/if}
<div class="w-full">
<BrownButton
on:click={() => {
onclick={() => {
selected_type = AvailableUploadTypes.Pixabay;
}}
>Pixabay
@@ -202,7 +202,7 @@ SPDX-License-Identifier: MPL-2.0
{$t('uploader.upload_video_popup_notice')}
</p>
{:else}
<BrownButton on:click={upload_video} type="button"
<BrownButton onclick={upload_video} type="button"
>{$t('uploader.upload_video')}</BrownButton
>
{/if}
@@ -58,7 +58,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<p class="text-center">{image.filename ?? 'No name available'}</p>
<BrownButton
on:click={() => {
onclick={() => {
set_image(image.id);
}}>{$t('words.select')}</BrownButton
>
@@ -93,7 +93,7 @@ SPDX-License-Identifier: MPL-2.0
/>
</div>
<BrownButton
on:click={() => {
onclick={() => {
set_image(image.id);
}}>{$t('words.select')}</BrownButton
>
@@ -102,14 +102,14 @@ SPDX-License-Identifier: MPL-2.0
<div class="flex gap-2">
<BrownButton
disabled={page < 2}
on:click={() => {
onclick={() => {
page -= 1;
fetched_data = fetch_data();
}}
>{$t('uploader.previous_page')}
</BrownButton>
<BrownButton
on:click={() => {
onclick={() => {
page += 1;
fetched_data = fetch_data();
}}>{$t('uploader.next_page')}</BrownButton
+2 -1
View File
@@ -378,7 +378,8 @@
"time_taken": "benötigte Zeit",
"player_name": "Spielername",
"correct_answer_plural": "{{count}} richtige Antworten",
"player_score": "Spieler Score"
"player_score": "Spieler Score",
"player_correct_questions": "Richtige Antworten"
},
"navbar": {
"donate": "Spenden"
+2 -1
View File
@@ -366,7 +366,8 @@
"correct_answer": "{{count}} correct answer",
"correct_answer_plural": "{{count}} correct answers",
"time_taken": "Time taken",
"player_score": "Player Score"
"player_score": "Player Score",
"player_correct_questions": "Correct Answers"
},
"controllers": {
"add_new_controller": "Add new controller",
@@ -18,12 +18,7 @@ SPDX-License-Identifier: MPL-2.0
cqc_code: string;
}
let {
game_pin,
players = $bindable(),
socket,
cqc_code = $bindable()
}: Props = $props();
let { game_pin, players = $bindable(), socket, cqc_code = $bindable() }: Props = $props();
let fullscreen_open = $state(false);
const { t } = getLocalization();
@@ -97,7 +92,7 @@ SPDX-License-Identifier: MPL-2.0
<div>
<GrayButton
disabled={players.length < 1}
on:click={() => {
onclick={() => {
socket.emit('start_game', '');
}}
>{$t('admin_page.start_game')}
+10 -3
View File
@@ -25,7 +25,11 @@ SPDX-License-Identifier: MPL-2.0
username: any;
}
let { game_pin = $bindable(), game_mode = $bindable(), username = $bindable() }: Props = $props();
let {
game_pin = $bindable(),
game_mode = $bindable(),
username = $bindable()
}: Props = $props();
let custom_field = $state();
let custom_field_value = $state();
let captcha_enabled = $state();
@@ -207,7 +211,10 @@ SPDX-License-Identifier: MPL-2.0
{#if game_pin === '' || game_pin.length < 6}
<div class="flex flex-col justify-center align-center w-screen h-screen">
<form onsubmit={preventDefault(bubble('submit'))} class="flex-col flex justify-center align-center mx-auto">
<form
onsubmit={preventDefault(bubble('submit'))}
class="flex-col flex justify-center align-center mx-auto"
>
<h1 class="text-lg text-center">{$t('words.game_pin')}</h1>
<input
class="border border-gray-400 self-center text-center text-black ring-0 outline-hidden p-2 rounded-lg focus:shadow-2xl transition-all"
@@ -244,7 +251,7 @@ SPDX-License-Identifier: MPL-2.0
{/if}
<div class="mt-2">
<BrownButton disabled={username.length <= 3} on:click={setUsername}
<BrownButton disabled={username.length <= 3} onclick={setUsername}
>{$t('words.submit')}</BrownButton
>
</div>
+10 -14
View File
@@ -82,9 +82,6 @@ SPDX-License-Identifier: MPL-2.0
});
const selectAnswer = (answer: string) => {
if (selected_answer !== undefined) {
return;
}
selected_answer = answer;
//timer_res = '0';
socket.emit('submit_answer', {
@@ -244,9 +241,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="flex justify-center">
<div class="w-1/2">
<BrownButton
disabled={selected_answer !== undefined}
on:click={() => selectAnswer(slider_value[0])}
<BrownButton onclick={() => selectAnswer(slider_value[0])}
>{$t('words.submit')}
</BrownButton>
</div>
@@ -274,8 +269,8 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-1/3">
<BrownButton
type="button"
disabled={selected_answer !== undefined}
on:click={() => {
disabled={!text_input || text_input.length === 0}
onclick={() => {
selectAnswer(text_input);
}}
>
@@ -370,8 +365,8 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-full mt-2">
<BrownButton
type="button"
disabled={selected_answer !== undefined}
on:click={() => {
disabled={selected_answer}
onclick={() => {
select_complex_answer(question.answers);
}}>{$t('words.submit')}</BrownButton
>
@@ -383,17 +378,18 @@ SPDX-License-Identifier: MPL-2.0
<Spinner />
{:then c}
<c.default
bind:question
{question}
bind:selected_answer
bind:game_mode
{game_mode}
{timer_res}
{circular_progress}
/>
<div class="flex justify-center h-[5%]">
<div class="w-1/2">
<BrownButton
disabled={selected_answer !== undefined}
on:click={() => selectAnswer(selected_answer)}
type="button"
disabled={selected_answer === undefined}
onclick={() => selectAnswer(selected_answer)}
>{$t('words.submit')}
</BrownButton>
</div>
+4 -5
View File
@@ -12,7 +12,6 @@ SPDX-License-Identifier: MPL-2.0
// import CircularTimer from '$lib/play/circular_progress.svelte';
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
interface Props {
question: Question;
selected_answer?: string;
@@ -23,10 +22,10 @@ SPDX-License-Identifier: MPL-2.0
let {
question,
selected_answer = $bindable(''),
selected_answer = $bindable(),
game_mode,
timer_res = $bindable(),
circular_progress = $bindable()
timer_res,
circular_progress
}: Props = $props();
let _selected_answers = $state([false, false, false, false]);
@@ -58,7 +57,7 @@ SPDX-License-Identifier: MPL-2.0
<div
class="absolute top-0 bottom-0 left-0 right-0 m-auto rounded-full h-fit w-fit border-2 border-black shadow-2xl z-40"
>
<CircularTimer bind:text={timer_res} bind:progress={circular_progress} color="#ef4444" />
<CircularTimer text={timer_res} progress={circular_progress} color="#ef4444" />
</div>
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4 h-full">
+5 -2
View File
@@ -45,7 +45,10 @@ SPDX-License-Identifier: MPL-2.0
if (question.type === QuizQuestionType.RANGE) {
slider_value[0] = (question.answers.max - question.answers.min) / 2 + question.answers.min;
}
let slider_values = $state([question.answers.min_correct ?? 0, question.answers.max_correct ?? 0]);
let slider_values = $state([
question.answers.min_correct ?? 0,
question.answers.max_correct ?? 0
]);
let text_input = $state();
timer(question.time);
@@ -347,7 +350,7 @@ SPDX-License-Identifier: MPL-2.0
{/each}
<BrownButton
type="button"
on:click={() => {
onclick={() => {
timer_res = '0';
}}>{$t('words.submit')}</BrownButton
>
@@ -84,7 +84,7 @@ SPDX-License-Identifier: MPL-2.0
{#if data.answers.length < 4}
<div class="rounded-sm p-6 bg-gray-700">
<BrownButton
on:click={() => {
onclick={() => {
data.answers = [...data.answers, { ...{ answer: '', correct: false } }];
}}>{$t('editor_page.add_an_answer')}</BrownButton
>
@@ -96,7 +96,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
</div>
<div class="flex justify-center p-2">
<BrownButton on:click={add_card}
<BrownButton onclick={add_card}
>{$t('quiztivity.memory.editor.add_pair')}</BrownButton
>
</div>
@@ -115,13 +115,13 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="grid grid-cols-2 p-2 gap-2">
<BrownButton
on:click={() => {
onclick={() => {
move_card_left(i);
}}
disabled={i === 0}>{$t('quiztivity.editor.move_left')}</BrownButton
>
<BrownButton
on:click={() => {
onclick={() => {
move_card_right(i);
}}
disabled={i + 1 === data.cards.length}
+9 -9
View File
@@ -83,7 +83,7 @@ SPDX-License-Identifier: MPL-2.0
{#if data.id}
<div class="mr-auto w-fit pl-2">
<BrownButton
on:click={() => {
onclick={() => {
shares_menu_open = true;
}}>{$t('quiztivity.editor.open_shares_menu')}</BrownButton
>
@@ -99,7 +99,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="self-end pr-2 w-full">
<div class="ml-auto w-fit">
<BrownButton
on:click={() => {
onclick={() => {
dispatch('save');
}}
disabled={!data.title}>{$t('words.save')}</BrownButton
@@ -109,20 +109,20 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="flex flex-row gap-2 w-full p-2">
<BrownButton
on:click={() => {
onclick={() => {
selected_type = null;
}}>{$t('quiztivity.editor.add_new')}</BrownButton
>
<BrownButton on:click={delete_slide} disabled={selected_slide === null}
<BrownButton onclick={delete_slide} disabled={selected_slide === null}
>{$t('quiztivity.editor.delete')}</BrownButton
>
<BrownButton
on:click={move_slide_left}
onclick={move_slide_left}
disabled={selected_slide === null || selected_slide === 0}
>{$t('quiztivity.editor.move_left')}</BrownButton
>
<BrownButton
on:click={move_slide_right}
onclick={move_slide_right}
disabled={selected_slide === null || selected_slide === data.pages.length - 1}
>{$t('quiztivity.editor.move_right')}</BrownButton
>
@@ -140,7 +140,7 @@ SPDX-License-Identifier: MPL-2.0
class:opacity-0={selected_slide !== i}
>
<BrownButton
on:click={() => {
onclick={() => {
selected_slide = selected_slide === i ? null : i;
}}
>
@@ -149,7 +149,7 @@ SPDX-License-Identifier: MPL-2.0
)}{/if}
</BrownButton>
<BrownButton
on:click={() => {
onclick={() => {
opened_slide = i;
}}>{$t('words.edit')}</BrownButton
>
@@ -164,7 +164,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="h-full">
<div class="mb-2">
<BrownButton
on:click={() => {
onclick={() => {
opened_slide = null;
}}>{$t('words.back')}</BrownButton
>
@@ -117,7 +117,7 @@ SPDX-License-Identifier: MPL-2.0
? !navigator.canShare({
title: 'title',
url: `${window.location.origin}/quiztivity`
})
})
: false;
} catch {
return false;
@@ -137,7 +137,7 @@ SPDX-License-Identifier: MPL-2.0
>
<div class="flex justify-center flex-col">
<BrownButton
on:click={() => {
onclick={() => {
add_shares_open = !add_shares_open;
}}>{$t('quiztivity.editor.shares.add_new_share')}</BrownButton
>
@@ -175,7 +175,7 @@ SPDX-License-Identifier: MPL-2.0
<BrownButton
flex={true}
disabled={share_available()}
on:click={() => {
onclick={() => {
navigator.share({
title: 'Quiztivity on ClassQuiz',
text: 'Play this Quiztivity now on ClassQuiz!',
@@ -204,7 +204,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-full mx-auto">
<BrownButton
flex={true}
on:click={() => {
onclick={() => {
copyToClipboard(
`${window.location.origin}/quiztivity/share/${share.id}?ref=copy`
);
@@ -242,7 +242,7 @@ SPDX-License-Identifier: MPL-2.0
</p>
<div class="w-fit my-auto ml-auto">
<BrownButton
on:click={() => {
onclick={() => {
delete_share(share.id);
}}>{$t('words.delete')}</BrownButton
>
+1 -1
View File
@@ -322,7 +322,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<!--<div
class="m-2 rounded-lg p-2 bg-opacity-40 bg-white transition-all cursor-pointer lg:h-full"
on:click={() => {
onclick={() => {
selected_create_thing = SelectedCreateThing.Import;
}}
class:shadow-2xl={selected_create_thing === SelectedCreateThing.Import}
@@ -131,7 +131,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="mx-auto">
<BrownButton
disabled={newest_version === controller.os_version}
on:click={allow_update_to_version}
onclick={allow_update_to_version}
>
{#if newest_version === controller.os_version}
{$t('controllers.already_latest_version')}
@@ -214,7 +214,7 @@ SPDX-License-Identifier: MPL-2.0
</form>
<div>
<div class="w-fit">
<BrownButton on:click={add_api_key}
<BrownButton onclick={add_api_key}
>{$t('settings_page.add_api_key')}</BrownButton
>
</div>
@@ -226,7 +226,7 @@ SPDX-License-Identifier: MPL-2.0
{key.key}
<div class="inline-block">
<BrownButton
on:click={() => {
onclick={() => {
delete_api_key(key.key);
}}
>{$t('words.delete')}
@@ -95,7 +95,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="flex pl-2">
<div class="mr-auto">
<BrownButton
on:click={() => {
onclick={() => {
index = index - 1;
}}
disabled={index < 1}>{$t('words.back')}</BrownButton
@@ -150,12 +150,12 @@ SPDX-License-Identifier: MPL-2.0
/>
<div class="m-auto grid grid-cols-2 gap-4" in:fade|global={{ delay: 3500 }}>
<BrownButton
on:click={() => {
onclick={() => {
index = 0;
finished = false;
}}>{$t('avatar_settings.start_over')}</BrownButton
>
<BrownButton on:click={save_avatar} flex={true} disabled={save_finished === true}>
<BrownButton onclick={save_avatar} flex={true} disabled={save_finished === true}>
{#if save_finished === undefined}{$t('words.save')}
{:else if save_finished === true}
<svg
@@ -175,7 +175,7 @@ SPDX-License-Identifier: MPL-2.0
</BrownButton>
<BrownButton href="/account/settings">{$t('avatar_settings.go_back')}</BrownButton>
<BrownButton
on:click={() => {
onclick={() => {
finished = false;
}}>{$t('words.close')}</BrownButton
>
@@ -162,7 +162,7 @@ SPDX-License-Identifier: MPL-2.0
<h2 class="text-center text-2xl">{$t('security_settings.backup_code')}</h2>
<div class="flex h-full w-full justify-center">
<div class="m-auto">
<BrownButton on:click={get_backup_code}
<BrownButton onclick={get_backup_code}
>{$t('security_settings.get_backup_code')}</BrownButton
>
</div>
@@ -238,7 +238,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="flex justify-center">
<div class="m-auto">
<BrownButton on:click={add_security_key}
<BrownButton onclick={add_security_key}
>{$t('security_settings.add_security_key')}</BrownButton
>
</div>
@@ -271,11 +271,11 @@ SPDX-License-Identifier: MPL-2.0
<div class="flex justify-center">
<div class="m-auto">
{#if totp_activated}
<BrownButton on:click={disable_totp}
<BrownButton onclick={disable_totp}
>{$t('security_settings.disable_totp')}</BrownButton
>
{:else}
<BrownButton on:click={enable_totp}
<BrownButton onclick={enable_totp}
>{$t('security_settings.enable_totp')}</BrownButton
>
{/if}
+2 -2
View File
@@ -165,7 +165,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-screen flex justify-center mt-16">
<div class="w-fit">
{#if export_token === undefined}
<GrayButton on:click={request_answer_export}
<GrayButton onclick={request_answer_export}
>{$t('admin_page.request_export_results')}</GrayButton
>
{:else}
@@ -179,7 +179,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="w-screen flex justify-center mt-2">
<div class="w-fit">
<GrayButton on:click={save_quiz} flex={true} disabled={results_saved}>
<GrayButton onclick={save_quiz} flex={true} disabled={results_saved}>
{#if results_saved}
<svg
class="w-4 h-4"
+5 -5
View File
@@ -161,7 +161,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
{:else}
<BrownButton
on:click={() => {
onclick={() => {
create_button_clicked = true;
}}>{$t('words.create')}</BrownButton
>
@@ -267,7 +267,7 @@ SPDX-License-Identifier: MPL-2.0
</BrownButton>
<BrownButton
flex={true}
on:click={() => (analytics_quiz_selected = quiz)}
onclick={() => (analytics_quiz_selected = quiz)}
>
<!-- heroicons/legacy-outline/ChartBar -->
<svg
@@ -311,7 +311,7 @@ SPDX-License-Identifier: MPL-2.0
</BrownButton>
{#if quiz.type === 'quiz'}
<BrownButton
on:click={() => {
onclick={() => {
start_game = quiz.id;
}}
flex={true}
@@ -365,7 +365,7 @@ SPDX-License-Identifier: MPL-2.0
{/if}
<BrownButton
on:click={() => {
onclick={() => {
deleteQuiz(quiz.id, quiz.type);
}}
flex={true}
@@ -387,7 +387,7 @@ SPDX-License-Identifier: MPL-2.0
</svg>
</BrownButton>
<BrownButton
on:click={() => (download_id = quiz.id)}
onclick={() => (download_id = quiz.id)}
flex={true}
disabled={quiz.type !== 'quiz'}
><!-- heroicons/download -->
@@ -33,7 +33,7 @@ SPDX-License-Identifier: MPL-2.0
{#if quiz}
<div
class="fixed w-full h-full top-0 flex bg-black/50 z-50 overflow-scroll"
on:click={on_parent_click}
onclick={on_parent_click}
transition:fade={{ duration: 100 }}
>
<div
+2 -2
View File
@@ -104,14 +104,14 @@ SPDX-License-Identifier: MPL-2.0
</p>
<div class="flex flex-col gap-2">
<BrownButton
on:click={() => {
onclick={() => {
edit_popup = image;
}}
>{$t('file_dashboard.edit_details')}
</BrownButton>
{#if image.quiztivities.length === 0 && image.quizzes.length === 0}
<BrownButton
on:click={() => {
onclick={() => {
delete_image(image.id);
}}>{$t('file_dashboard.delete_image')}</BrownButton
>
+3 -3
View File
@@ -13,7 +13,7 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization();
let file_input: HTMLInputElement = $state();
navbarVisible.visible= false;
navbarVisible.visible = false;
let stats: { progress: number; time_elapsed: number; speed: number } = $state({
progress: 0,
@@ -197,7 +197,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="flex relative my-2">
<div class="w-full">
<BrownButton disabled={status !== Status.CompressDone} on:click={upload_video}>
<BrownButton disabled={status !== Status.CompressDone} onclick={upload_video}>
{$t('words.upload')}
{file_size_in_mi ? `(${file_size_in_mi.toFixed(2)} Mi)` : ''}</BrownButton
>
@@ -208,7 +208,7 @@ SPDX-License-Identifier: MPL-2.0
></span>
</div>
<div class="flex justify-center">
<BrownButton on:click={compress_video} disabled={status !== Status.Idle}
<BrownButton onclick={compress_video} disabled={status !== Status.Idle}
>{$t('words.submit')}</BrownButton
>
</div>
@@ -22,7 +22,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="my-auto justify-start ml-4">
<BrownButton
disabled={current_slide_index < 1}
on:click={() => {
onclick={() => {
current_slide_index -= 1;
}}>{$t('words.back')}</BrownButton
>
@@ -33,7 +33,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="my-auto justify-end mr-4">
<BrownButton
disabled={current_slide_index === 1}
on:click={() => {
onclick={() => {
current_slide_index += 1;
}}>{$t('words.next')}</BrownButton
>
+1 -1
View File
@@ -43,7 +43,7 @@ SPDX-License-Identifier: MPL-2.0
<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
>{@html result.title}</a
></td
>
<td class="border-r dark:border-gray-500 p-1 border-gray-300"
@@ -95,6 +95,7 @@ SPDX-License-Identifier: MPL-2.0
<PlayerOverview
custom_field={data.results.custom_field_data}
scores={data.results.player_scores}
answers={data.results.answers}
/>
</div>
{/if}
@@ -10,30 +10,23 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization();
interface Props {
questions: Question[];
answers: {
username: string;
answer: string;
right: boolean;
tike_taken: number;
score: number;
}[][];
username: string;
answer: string;
right: boolean;
tike_taken: number;
score: number;
}[][];
scores: {
[key: string]: string;
};
[key: string]: string;
};
title: string;
timestamp: string;
}
let {
questions,
answers,
scores,
title,
timestamp
}: Props = $props();
let { questions, answers, scores, title, timestamp }: Props = $props();
const usernames = Object.keys(scores);
@@ -49,7 +42,7 @@ SPDX-License-Identifier: MPL-2.0
<div class="w-full">
<div class="flex justify-center w-full">
<p class="text-3xl w-5/6 text-center">
{$t('results_page.general_overview.sentence', {
{@html $t('results_page.general_overview.sentence', {
title,
date: new Date(timestamp).toLocaleString(),
player_count: usernames.length,
@@ -10,16 +10,29 @@ SPDX-License-Identifier: MPL-2.0
const { t } = getLocalization();
interface Props {
scores: {
[key: string]: string;
};
[key: string]: string;
};
custom_field: {
[key: string]: string;
};
[key: string]: string;
};
answers: { [key: string]: any }[];
}
let { scores, custom_field }: Props = $props();
let { scores, custom_field, answers }: Props = $props();
let usernames = Object.keys(scores);
const correctCounts = {};
answers.forEach((questionAnswers) => {
questionAnswers.forEach((answer) => {
const user = answer.username;
if (!correctCounts[user]) {
correctCounts[user] = 0;
}
if (answer.right) {
correctCounts[user] += 1;
}
});
});
console.log(custom_field);
</script>
@@ -31,6 +44,9 @@ SPDX-License-Identifier: MPL-2.0
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
>{$t('result_page.player_name')}
</th>
<th class="border-r dark:border-gray-500 p-1 mx-auto border-gray-300"
>{$t('result_page.player_correct_questions')}
</th>
<th class="p-1 mx-auto">{$t('result_page.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"
@@ -43,6 +59,9 @@ SPDX-License-Identifier: MPL-2.0
{#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="border-r dark:border-gray-500 p-1 border-gray-300"
>{correctCounts[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"
@@ -124,7 +124,7 @@ SPDX-License-Identifier: MPL-2.0
{#if logged_in}
<div class="w-full">
<GrayButton
on:click={() => {
onclick={() => {
start_game = quiz.id;
}}
flex={true}
@@ -188,7 +188,7 @@ SPDX-License-Identifier: MPL-2.0
</div>
<div class="w-full">
{#if logged_in}
<GrayButton flex={true} on:click={() => (download_id = quiz.id)}>
<GrayButton flex={true} onclick={() => (download_id = quiz.id)}>
<svg
class="w-5 h-5 inline-block"
fill="none"
@@ -35,25 +35,25 @@ SPDX-License-Identifier: MPL-2.0
<div class="rounded-sm border-2 border-[#B07156] flex flex-col w-fit gap-2 p-2">
<div class:opacity-50={mod_rating !== null && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = null)}>Not Checked</BrownButton>
<BrownButton onclick={() => (mod_rating = null)}>Not Checked</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 0 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 0)}>Ok</BrownButton>
<BrownButton onclick={() => (mod_rating = 0)}>Ok</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 1 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 1)}>Attention</BrownButton>
<BrownButton onclick={() => (mod_rating = 1)}>Attention</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 2 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 2)}>NFSW</BrownButton>
<BrownButton onclick={() => (mod_rating = 2)}>NFSW</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 3 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 3)}>Plausibility Checked</BrownButton>
<BrownButton onclick={() => (mod_rating = 3)}>Plausibility Checked</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 4 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 4)}>Fact Checked</BrownButton>
<BrownButton onclick={() => (mod_rating = 4)}>Fact Checked</BrownButton>
</div>
<div class:opacity-50={mod_rating !== 5 && mod_rating !== undefined} class="transition">
<BrownButton on:click={() => (mod_rating = 5)}>Exceptional</BrownButton>
<BrownButton onclick={() => (mod_rating = 5)}>Exceptional</BrownButton>
</div>
<GrayButton on:click={submit} disabled={mod_rating === undefined}>Submit</GrayButton>
<GrayButton onclick={submit} disabled={mod_rating === undefined}>Submit</GrayButton>
</div>