Bug fixes and correct answer count in results
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user