Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 10x 10x 10x 10x 10x 10x 56x 10x 56x 7x 1x 7x 1x 7x 1x 7x 1x 7x 1x 4x 7x 28x 1x 1x 1x 1x | import update from 'immutability-helper' import { ReactComponent as AddIcon } from '../../assets/svg/add.svg' import { ReactComponent as CheckedIcon } from '../../assets/svg/checked.svg' import { ReactComponent as DeleteIcon } from '../../assets/svg/delete.svg' import { ReactNode } from 'react' import { Choice, Question, createChoice } from 'sqc-core-functions' import { Editor } from '../Editor' export type QuizEditorParams = { /** The quiz question object */ question: Question /** Whether richtext mode is enabled */ richtextMode?: boolean /** Function to handle any changes on the question, including adding/editing/removing answers */ onChange: (question: Question) => void /** Warning message component to display */ warning?: ReactNode } const isAnswerTogglable = (answer: Choice) => answer.isCorrect /** * Renders a QuizEditor component with question, answers, and warning. */ export const QuizEditor = ({ question, richtextMode, onChange, warning }: QuizEditorParams) => { const isAnswerNonRemovable = (answer: Choice) => question.choices.length < 2 || answer.isCorrect const handleQuestionUpdate = (value: string) => { onChange({ ...question, question: value, }) } const handleAnswerUpdate = (index: number, value: string) => { onChange(update(question, { choices: { [index]: { answer: { $set: value } } } })) } const handleAddAnswer = (index: number) => { onChange( update(question, { choices: { $splice: [[index + 1, 0, createChoice()]], }, }) ) } const handleRemoveAnswer = (index: number) => { onChange(update(question, { choices: { $splice: [[index, 1]] } })) } const handleToggleAnswer = (choice: Choice) => { onChange( update(question, { choices: { $apply: (x: Choice[]): Choice[] => x.map((c) => ({ ...c, isCorrect: c.id === choice.id, })), }, }) ) } return ( <div key={question.id}> <h2 className='sqc-mb-2 sqc-text-xl sqc-font-semibold'>Question:</h2> <Editor value={question.question} onChange={handleQuestionUpdate} richtextMode={richtextMode} /> {warning} <h2 className='sqc-my-2 sqc-text-xl sqc-font-semibold'>Answers:</h2> {question.choices.map((choice, index) => ( <div key={choice.id}> <h3 className='sqc-mb-2 sqc-font-semibold sqc-text-l'> Answer {index + 1}: {choice.isCorrect && <span className='sqc-text-emerald-500'>Correct</span>} </h3> <div className='sqc-relative sqc-mb-6'> <div className='sqc-absolute sqc-inset-y-0 sqc-left-0 sqc-flex sqc-flex-col sqc-items-center sqc-justify-center sqc-gap-2 sqc-pl-3'> <button type='button' role='toggle-answer' aria-disabled={isAnswerTogglable(choice)} disabled={isAnswerTogglable(choice)} className='sqc-text-slate-400 hover:sqc-rounded-lg hover:sqc-border hover:sqc-bg-emerald-200 disabled:sqc-cursor-not-allowed disabled:sqc-bg-transparent disabled:sqc-text-emerald-400' onClick={() => handleToggleAnswer(choice)} > <CheckedIcon className='sqc-w-8 sqc-h-8' fill='currentColor' /> <span className='sqc-sr-only'>Mark as correct answer</span> </button> <button type='button' role='remove-answer' aria-disabled={isAnswerNonRemovable(choice)} disabled={isAnswerNonRemovable(choice)} className='sqc-text-red-400 hover:sqc-rounded-lg hover:sqc-border hover:sqc-bg-red-200 disabled:sqc-cursor-not-allowed disabled:sqc-bg-transparent' onClick={() => handleRemoveAnswer(index)} > <DeleteIcon className='sqc-w-8 sqc-h-8' fill='currentColor' /> <span className='sqc-sr-only'>Remove this answer</span> </button> <button type='button' role='add-answer' onClick={() => handleAddAnswer(index)} className='sqc-text-blue-400 hover:sqc-rounded-lg hover:sqc-border hover:sqc-bg-blue-200' > <AddIcon className='sqc-w-8 sqc-h-8' fill='currentColor' /> <span className='sqc-sr-only'>Add an answer after</span> </button> </div> <div className='sqc-block sqc-w-full sqc-rounded-lg sqc-border sqc-border-gray-300 sqc-bg-gray-50 sqc-p-2.5 sqc-pl-14 lg:sqc-py-5'> <Editor value={choice.answer} onChange={(val) => handleAnswerUpdate(index, val)} richtextMode={richtextMode} /> {warning} </div> </div> </div> ))} </div> ) } |