From 99bd6cc32974ae06a3cb3319e55851eb7043b369 Mon Sep 17 00:00:00 2001 From: Mawoka Date: Tue, 4 Oct 2022 12:38:04 +0200 Subject: [PATCH] :sparkles: Implemented in Editor --- classquiz/db/models.py | 13 ++- .../lib/editor/RangeSelectorEditorPart.svelte | 4 +- .../src/lib/editor/VotingEditorPart.svelte | 83 +++++++++++++++++++ frontend/src/lib/editor/card.svelte | 13 ++- frontend/src/lib/editor/settings-card.svelte | 4 +- frontend/src/lib/editor/sidebar.svelte | 24 ++++++ frontend/src/lib/quiz_types.ts | 10 ++- frontend/src/lib/yupSchemas.ts | 25 +++++- 8 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 frontend/src/lib/editor/VotingEditorPart.svelte diff --git a/classquiz/db/models.py b/classquiz/db/models.py index dbc41ba..ef79cea 100644 --- a/classquiz/db/models.py +++ b/classquiz/db/models.py @@ -85,24 +85,33 @@ class RangeQuizAnswer(BaseModel): max_correct: int +class VotingQuizAnswer(BaseModel): + answer: str + image: str | None = None + color: str | None + + class QuizQuestionType(str, Enum): ABCD = "ABCD" RANGE = "RANGE" + VOTING = "VOTING" class QuizQuestion(BaseModel): question: str time: str # in Secs type: None | QuizQuestionType = QuizQuestionType.ABCD - answers: list[ABCDQuizAnswer] | RangeQuizAnswer + answers: list[ABCDQuizAnswer] | RangeQuizAnswer | list[VotingQuizAnswer] image: str | None = None @validator("answers") def answers_not_none_if_abcd_type(cls, v, values): - if values["type"] == QuizQuestionType.ABCD and len(v) == 0: + if values["type"] == QuizQuestionType.ABCD and type(v[0]) != ABCDQuizAnswer: raise ValueError("Answers can't be none if type is ABCD") if values["type"] == QuizQuestionType.RANGE and type(v) != RangeQuizAnswer: raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE") + if values["type"] == QuizQuestionType.VOTING and type(v[0]) != VotingQuizAnswer: + raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE") return v diff --git a/frontend/src/lib/editor/RangeSelectorEditorPart.svelte b/frontend/src/lib/editor/RangeSelectorEditorPart.svelte index 541efaf..278bd53 100644 --- a/frontend/src/lib/editor/RangeSelectorEditorPart.svelte +++ b/frontend/src/lib/editor/RangeSelectorEditorPart.svelte @@ -66,10 +66,10 @@ {#await import('svelte-range-slider-pips')} - + {:then c} {#await sleep(100)} - + {:then _} + + + + +
+ {#if Array.isArray(data.questions[selected_question].answers)} + {#each data.questions[selected_question].answers as answer, index} +
+ { + data.questions[selected_question].answers.splice(index, 1); + data.questions[selected_question].answers = + data.questions[selected_question].answers; + }} + class="border-b-2 border-dotted w-5/6 text-center rounded-lg" + style="background-color: {answer.color ?? 'transparent'}" + placeholder="Empty..." + /> + { + answer.color = null; + }} + /> +
+ {/each} + {/if} + {#if data.questions[selected_question].answers.length < 4} + + {/if} +
diff --git a/frontend/src/lib/editor/card.svelte b/frontend/src/lib/editor/card.svelte index c2f4650..0ac4f7d 100644 --- a/frontend/src/lib/editor/card.svelte +++ b/frontend/src/lib/editor/card.svelte @@ -96,11 +96,11 @@ use:tippy={{ content: "Click to learn why it's loading so long." }} class="cursor-help" > - + {:else} {#await import('$lib/editor/uploader.svelte')} - + {:then c} +
{#if data.questions[selected_question].type === QuizQuestionType.ABCD} {#await import('$lib/editor/ABCDEditorPart.svelte')} - + {:then c} {/await} {:else if data.questions[selected_question].type === QuizQuestionType.RANGE} + {:else if data.questions[selected_question].type === QuizQuestionType.VOTING} + {#await import('$lib/editor/VotingEditorPart.svelte')} + + {:then c} + + {/await} {/if}

{$t('editor_page.right_click_to_delete')}

diff --git a/frontend/src/lib/editor/settings-card.svelte b/frontend/src/lib/editor/settings-card.svelte index 1d80891..068192e 100644 --- a/frontend/src/lib/editor/settings-card.svelte +++ b/frontend/src/lib/editor/settings-card.svelte @@ -67,11 +67,11 @@ {:else if pow_data === undefined} - + {:else} {#await import('$lib/editor/uploader.svelte')} - + {:then c} + {:else if question.type === QuizQuestionType.VOTING} + {#if Array.isArray(question.answers)} +
+ {#each question.answers as answer} + {#if answer.answer === ''} + Empty... + {:else} + {answer.answer} + {/if} + {/each} +
+ {/if} {:else}

Unknown Question Type (shouldn't happen)

{/if} diff --git a/frontend/src/lib/quiz_types.ts b/frontend/src/lib/quiz_types.ts index 93b3fde..5793508 100644 --- a/frontend/src/lib/quiz_types.ts +++ b/frontend/src/lib/quiz_types.ts @@ -18,7 +18,8 @@ export interface QuizData { export enum QuizQuestionType { ABCD = 'ABCD', // eslint-disable-line no-unused-vars - RANGE = 'RANGE' // eslint-disable-line no-unused-vars + RANGE = 'RANGE', // eslint-disable-line no-unused-vars + VOTING = 'VOTING' // eslint-disable-line no-unused-vars } export interface RangeQuizAnswer { @@ -33,7 +34,7 @@ export interface Question { question: string; type?: QuizQuestionType; image?: string; - answers: Answer[] | RangeQuizAnswer; + answers: Answer[] | RangeQuizAnswer | VotingAnswer[]; } export interface Answer { @@ -41,6 +42,11 @@ export interface Answer { answer: string; color?: string; } +export interface VotingAnswer { + answer: string; + image?: string; + color?: string; +} export interface EditorData { public: boolean; diff --git a/frontend/src/lib/yupSchemas.ts b/frontend/src/lib/yupSchemas.ts index 6309e1f..3f81e4a 100644 --- a/frontend/src/lib/yupSchemas.ts +++ b/frontend/src/lib/yupSchemas.ts @@ -17,6 +17,17 @@ export const ABCDQuestionSchema = yup .min(2, 'You need at least 2 answers') .max(16, "You can't have more than 16 answers"); +export const VotingQuestionSchema = yup + .array() + .of( + yup.object({ + answer: yup.string().required('You need an answer'), + image: yup.string().optional().nullable() + }) + ) + .min(2, 'You need at least 2 answers') + .max(16, "You can't have more than 16 answers"); + export const RangeQuestionSchema = yup.object({ min: yup.number(), max: yup.number(), @@ -50,9 +61,17 @@ export const dataSchema = yup.object({ "The image-url isn't valid" ) .lowercase(), - answers: yup.lazy((v) => - Array.isArray(v) ? ABCDQuestionSchema : RangeQuestionSchema - ) + answers: yup.lazy((v) => { + if (Array.isArray(v)) { + if (typeof v[0].right === 'boolean') { + return ABCDQuestionSchema; + } else { + return VotingQuestionSchema; + } + } else { + return RangeQuestionSchema; + } + }) }) ) .min(1, 'You need at least one question')