Added Check Choice question type

This commit is contained in:
Mawoka
2023-05-24 21:40:53 +02:00
parent d713f76d0a
commit c6dc71b941
13 changed files with 164 additions and 68 deletions
+4
View File
@@ -120,6 +120,7 @@ class QuizQuestionType(str, Enum):
SLIDE = "SLIDE"
TEXT = "TEXT"
ORDER = "ORDER"
CHECK = "CHECK"
class TextQuizAnswer(BaseModel):
@@ -136,6 +137,7 @@ class QuizQuestion(BaseModel):
@validator("answers")
def answers_not_none_if_abcd_type(cls, v, values):
print(values)
# print(values)
if values["type"] == QuizQuestionType.ABCD and type(v[0]) != ABCDQuizAnswer:
raise ValueError("Answers can't be none if type is ABCD")
@@ -149,6 +151,8 @@ class QuizQuestion(BaseModel):
raise ValueError("Answer must be from type VotingQuizAnswer if type is ORDER")
if values["type"] == QuizQuestionType.SLIDE and type(v[0]) != str:
raise ValueError("Answer must be from type SlideElement if type is SLIDE")
if values["type"] == QuizQuestionType.CHECK and type(v[0]) != ABCDQuizAnswer:
raise ValueError("Answers can't be none if type is CHECK")
return v
+9
View File
@@ -359,6 +359,15 @@ async def submit_answer(sid: str, data: dict):
if data.answer.lower() == q.answer.lower():
answer_right = True
break
elif game_data.questions[int(data.question_index)].type == QuizQuestionType.CHECK:
correct_string = ""
for i, a in enumerate(game_data.questions[int(float(data.question_index))].answers):
if a.right:
correct_string += str(i)
if correct_string == data.answer:
answer_right = True
else:
answer_right = False
else:
raise NotImplementedError
latency = int(float((await sio.get_session(sid))["ping"]))
+1 -1
View File
@@ -231,7 +231,7 @@
/>
</div>
{/if}
{#if quiz_data.questions[selected_question].type === QuizQuestionType.ABCD || quiz_data.questions[selected_question].type === QuizQuestionType.VOTING}
{#if quiz_data.questions[selected_question].type === QuizQuestionType.ABCD || quiz_data.questions[selected_question].type === QuizQuestionType.VOTING || quiz_data.questions[selected_question].type === QuizQuestionType.CHECK}
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4">
{#each quiz_data.questions[selected_question].answers as answer, i}
<div
+4 -10
View File
@@ -13,7 +13,7 @@
import { QuizQuestionType } from '$lib/quiz_types.js';
import { getLocalization } from '$lib/i18n';
import StartGamePopup from './start_game.svelte';
import { onMount } from 'svelte';
// import { onMount } from 'svelte';
import viewport from './useViewportAction.js';
import Spinner from '$lib/Spinner.svelte';
import GrayButton from '$lib/components/buttons/gray.svelte';
@@ -34,12 +34,6 @@
};
let visibleImages = Array.from(Array(quizzes.length), () => []);
const close_start_game_if_esc_is_pressed = (key: KeyboardEvent) => {
if (key.code === 'Escape') {
start_game = null;
}
};
const copy_id = (quiz_id: string) => {
navigator.clipboard.writeText(quiz_id);
copy_toast_open = true;
@@ -58,9 +52,9 @@
game_in_lobby = await res.json();
}
};
onMount(() => {
document.body.addEventListener('keydown', close_start_game_if_esc_is_pressed);
});
// onMount(() => {
// document.body.addEventListener('keydown', close_start_game_if_esc_is_pressed);
// });
get_game_in_lobby_fn();
</script>
@@ -4,7 +4,8 @@
- file, You can obtain one at https://mozilla.org/MPL/2.0/.
-->
<script lang="ts">
import type { EditorData, Answer } from '../quiz_types';
import type { Answer, EditorData } from '../quiz_types';
import { QuizQuestionType } from '../quiz_types';
import { fade } from 'svelte/transition';
import { reach } from 'yup';
import { ABCDQuestionSchema } from '$lib/yupSchemas';
@@ -18,6 +19,7 @@
console.log(get_foreground_color(default_colors[0]));
export let selected_question: number;
export let check_choice = false;
export let data: EditorData;
if (!Array.isArray(data.questions[selected_question].answers)) {
data.questions[selected_question].answers = [];
@@ -41,6 +43,9 @@
};
};
$: save_colors(data);
data.questions[selected_question].type = check_choice
? QuizQuestionType.ABCD
: QuizQuestionType.CHECK;
</script>
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-4 w-full px-10">
+18 -11
View File
@@ -52,11 +52,11 @@
set_unique();
}
/*
if (typeof data.questions[selected_question].type !== QuizQuestionType) {
console.log(data.questions[selected_question].type !== QuizQuestionType.ABCD || data.questions[selected_question].type !== QuizQuestionType.RANGE)
data.questions[selected_question].type = QuizQuestionType.ABCD;
}
*/
if (typeof data.questions[selected_question].type !== QuizQuestionType) {
console.log(data.questions[selected_question].type !== QuizQuestionType.ABCD || data.questions[selected_question].type !== QuizQuestionType.RANGE)
data.questions[selected_question].type = QuizQuestionType.ABCD;
}
*/
</script>
<div class="w-full max-h-full pb-20 px-20 h-full">
@@ -81,6 +81,7 @@
<svelte:component this={c.default} bind:data={data.questions[selected_question]} />
{/await}
{:else}
{@const type = data.questions[selected_question].type}
<div class="flex flex-col">
<div class="flex justify-center pt-10 w-full">
{#key unique}
@@ -194,30 +195,36 @@
<option value={QuizQuestionType.VOTING}>{$t('words.voting')}</option>
<option value={QuizQuestionType.TEXT}>{$t('words.text')}</option>
<option value={QuizQuestionType.ORDER}>{$t('words.order')}</option>
<option value={QuizQuestionType.CHECK}>{$t('words.check_choice')}</option>
</select>
</div>
<div class="flex justify-center py-10 w-full">
{#if data.questions[selected_question].type === QuizQuestionType.ABCD}
{#if type === QuizQuestionType.ABCD || QuizQuestionType.CHECK}
{#await import('$lib/editor/ABCDEditorPart.svelte')}
<Spinner my_20={false} />
{:then c}
<svelte:component this={c.default} bind:data bind:selected_question />
<svelte:component
this={c.default}
bind:data
bind:selected_question
check_choice={type === QuizQuestionType.CHECK}
/>
{/await}
{:else if data.questions[selected_question].type === QuizQuestionType.RANGE}
{:else if type === QuizQuestionType.RANGE}
<RangeEditor bind:selected_question bind:data />
{:else if data.questions[selected_question].type === QuizQuestionType.VOTING}
{:else if type === QuizQuestionType.VOTING}
{#await import('$lib/editor/VotingEditorPart.svelte')}
<Spinner my_20={false} />
{:then c}
<svelte:component this={c.default} bind:data bind:selected_question />
{/await}
{:else if data.questions[selected_question].type === QuizQuestionType.TEXT}
{:else if type === QuizQuestionType.TEXT}
{#await import('$lib/editor/TextEditorPart.svelte')}
<Spinner my_20={false} />
{:then c}
<svelte:component this={c.default} bind:data bind:selected_question />
{/await}
{:else if data.questions[selected_question].type === QuizQuestionType.ORDER}
{:else if type === QuizQuestionType.ORDER}
{#await import('$lib/editor/OrderEditorPart.svelte')}
<Spinner my_20={false} />
{:then c}
+1 -1
View File
@@ -211,7 +211,7 @@
/>
</div>
{/if}
{#if question.type === QuizQuestionType.ABCD}
{#if question.type === QuizQuestionType.ABCD || question.type === QuizQuestionType.CHECK}
<div class="grid grid-cols-2 gap-2">
{#if Array.isArray(question.answers)}
{#each question.answers as answer}
+2 -1
View File
@@ -174,7 +174,8 @@
"select": "Select",
"quiz": "Quiz",
"quiztivity": "Quiztivity",
"next": "Next"
"next": "Next",
"check_choice": "Check Choice"
},
"editor": {
"time_in_seconds": "Time in seconds",
+32 -36
View File
@@ -32,10 +32,10 @@
}
/* if (typeof question_index === 'string') {
question_index = parseInt(question_index);
} else {
throw new Error('question_index must be a string or number');
}*/
question_index = parseInt(question_index);
} else {
throw new Error('question_index must be a string or number');
}*/
let timer_res = question.time;
let selected_answer: string;
@@ -251,30 +251,6 @@
</BrownButton>
</div>
</div>
{:else if question.type === QuizQuestionType.ABCD}
{#if solution === undefined}
<Spinner />
{:else}
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4">
{#each solution.answers as answer}
{#if answer.right}
<button
class="text-3xl rounded-lg h-fit flex align-middle justify-center p-3 bg-green-600"
disabled
class:opacity-30={answer.answer !== selected_answer}
>{answer.answer}</button
>
{:else}
<button
class="text-3xl rounded-lg h-fit flex align-middle justify-center p-3 bg-red-500"
disabled
class:opacity-30={answer.answer !== selected_answer}
>{answer.answer}</button
>
{/if}
{/each}
</div>
{/if}
{:else if question.type === QuizQuestionType.RANGE}
{#if solution === undefined}
<Spinner />
@@ -291,8 +267,8 @@
{/if}
{:else if question.type === QuizQuestionType.ORDER}
<!-- {#if solution === undefined}
<Spinner />
{:else}-->
<Spinner />
{:else}-->
<div class="flex flex-col w-full h-full gap-4 px-4 py-6">
{#each question.answers as answer, i (answer.id)}
<div
@@ -365,14 +341,34 @@
</div>
</div>
<!--{/if}-->
{:else if question.type === QuizQuestionType.CHECK}
{#await import('./questions/check.svelte')}
<Spinner />
{:then c}
<svelte:component
this={c.default}
bind:question
bind:selected_answer
bind:game_mode
/>
<div class="flex justify-center h-[5%]">
<div class="w-1/2">
<BrownButton
disabled={!selected_answer}
on:click={() => selectAnswer(selected_answer)}
>{$t('words.submit')}
</BrownButton>
</div>
</div>
{/await}
{/if}
<!--{:else if question.type === QuizQuestionType.VOTING}
{#await import('$lib/play/admin/voting_results.svelte')}
<Spinner />
{:then c}
<svelte:component this={c.default} bind:data={question_results}
bind:question={quiz_data.questions[selected_question]} />
{/await}-->
{#await import('$lib/play/admin/voting_results.svelte')}
<Spinner />
{:then c}
<svelte:component this={c.default} bind:data={question_results}
bind:question={quiz_data.questions[selected_question]} />
{/await}-->
{/if}
</div>
@@ -0,0 +1,63 @@
<!--
- 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 { get_foreground_color } from '$lib/helpers';
import { kahoot_icons } from '$lib/play/kahoot_mode_assets/kahoot_icons';
// import CircularTimer from '$lib/play/circular_progress.svelte';
const default_colors = ['#D6EDC9', '#B07156', '#7F7057', '#4E6E58'];
export let question: Question;
export let selected_answer = '';
export let game_mode;
let _selected_answers = [false, false, false, false];
const selectAnswer = (i: number) => {
_selected_answers[i] = !_selected_answers[i];
selected_answer = '';
for (let i = 0; i < _selected_answers.length; i++) {
if (_selected_answers[i]) {
selected_answer += String(i);
}
}
selected_answer = selected_answer;
console.log(_selected_answers, selected_answer);
};
</script>
<div class="w-full h-[95%]">
<!--
<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-50"
>
<CircularTimer
bind:text={timer_res}
bind:progress={circular_prgoress}
color="#ef4444"
/>
</div>
-->
<div class="grid grid-rows-2 grid-flow-col auto-cols-auto gap-2 w-full p-4 h-full">
{#each question.answers as answer, i}
<button
class="rounded-lg h-full flex align-middle justify-center disabled:opacity-60 p-3 border-2 border-black opacity-50 transition-all"
style="background-color: {answer.color ??
default_colors[i]}; color: {get_foreground_color(
answer.color ?? default_colors[i]
)}"
on:click={() => selectAnswer(i)}
class:opacity-100={_selected_answers[i]}
>
{#if game_mode === 'kahoot'}
<img class="h-2/3 inline-block m-auto" alt="Icon" src={kahoot_icons[i]} />
{:else}
<p class="m-auto">{answer.answer}</p>
{/if}
</button>
{/each}
</div>
</div>
+2 -1
View File
@@ -31,7 +31,8 @@ export enum QuizQuestionType {
VOTING = 'VOTING', // eslint-disable-line no-unused-vars
SLIDE = 'SLIDE', // eslint-disable-line no-unused-vars
TEXT = 'TEXT', // eslint-disable-line no-unused-vars
ORDER = 'ORDER' // eslint-disable-line no-unused-vars
ORDER = 'ORDER', // eslint-disable-line no-unused-vars
CHECK = 'CHECK' // eslint-disable-line no-unused-vars
}
export interface RangeQuizAnswer {
@@ -6,10 +6,11 @@
<script lang="ts">
import { QuizQuestionType } from '$lib/quiz_types';
import { getLocalization } from '$lib/i18n';
import type { Question } from '$lib/quiz_types';
const { t } = getLocalization();
export let question;
export let question: Question;
interface Answer {
username: string;
@@ -24,8 +25,23 @@
const get_answer_count_for_answer = (answer: string): number => {
let count = 0;
for (const a of answers) {
if (a.answer === answer) {
let answer_id = 0;
if (question.type === QuizQuestionType.CHECK) {
for (let i = 0; i < question.answers.length; i++) {
if (answer === question.answers[i].answer) {
answer_id = i;
break;
}
}
}
for (let i = 0; i < answers.length; i++) {
const a = answers[i];
if (question.type === QuizQuestionType.CHECK) {
console.log(a.answer.includes('2'), answer_id);
if (a.answer.includes(String(answer_id))) {
count++;
}
} else if (a.answer === answer) {
count++;
}
}
@@ -79,8 +95,8 @@
<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
>
>{$t('words.correct')}?
</th>
{/if}
</tr>
{#each answers as answer}
@@ -211,7 +211,7 @@
</svg>
<span class="text-lg">{question.time}s</span>
</p>
{#if question.type === QuizQuestionType.ABCD || question.type === undefined}
{#if question.type === QuizQuestionType.ABCD || question.type === undefined || question.type === QuizQuestionType.CHECK}
<div class="grid grid-cols-2 gap-4 m-4 p-6">
{#each question.answers as answer, index_answer}
<div