✨ Added Check Choice question type
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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"]))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,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>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user