QuestionCard.jsx (2952B)
1 import { useState } from 'preact/hooks'; 2 import QuestionList from './QuestionList.jsx'; 3 import Card from './Card.jsx'; 4 import { getRandomChoice, getRandomNumber } from '../scripts/randomUtils.js'; 5 6 const seedDiff = 100; 7 8 function resolveParameters(question, variables) { 9 const parameters = question.constants ?? { }; 10 const variableKeys = question.variables ?? { }; 11 Object.keys(variableKeys).forEach((key) => { 12 parameters[key] = variables[variableKeys[key]]; 13 }) 14 return parameters; 15 } 16 17 function renderQuestion(seed, showAnswer, variables) { 18 return (question, i) => { 19 const QuestionComponent = question.type; 20 const parameters = resolveParameters(question, variables); 21 return <QuestionComponent key={i} seed={seed+seedDiff*i} showAnswer={showAnswer} {...parameters} />; 22 }; 23 } 24 25 function getQuestionList(id, questions, showAnswers, seed, variables) { 26 return ( 27 <QuestionList key={id}> 28 {questions.map(renderQuestion(seed, showAnswers, variables))} 29 </QuestionList> 30 ); 31 } 32 33 function shuffleArray(arr, n, seed) { 34 return Array.from({ length: n }).map(() => getRandomChoice(arr, ++seed)); 35 } 36 37 export default function QuestionCard({ data }) { 38 39 const dataVariables = data.variables ?? []; 40 41 const defaultVariables = Object.fromEntries( 42 dataVariables.map(input => [input.id, input.default ?? input.values]) 43 ); 44 45 const [showAnswers, setShowAnswers] = useState(false); 46 const [seed , setSeed ] = useState(Math.random()); 47 const [variables , setVariables ] = useState(defaultVariables); 48 49 function setVariable(id) { 50 return (value) => { 51 setVariables({ 52 ...variables, 53 [id]: value 54 }); 55 } 56 } 57 58 function revealAnswers() { setShowAnswers(!showAnswers); } 59 function triggerRefresh() { setSeed(getRandomNumber(seed)); } 60 61 let current_seed = seed; 62 const questions = data.questionLists.map(questionList => { 63 const { id: id, n: n, questions: unique_questions } = questionList; 64 const questions = shuffleArray(unique_questions, n, current_seed); 65 const randomQuestionList = getQuestionList(id, questions, showAnswers, current_seed, variables); 66 current_seed += seedDiff * n; 67 return randomQuestionList; 68 }); 69 70 const fields = dataVariables.map(input => { 71 const { type: InputComponent, ...props } = input; 72 return <InputComponent key={input.id} variable={variables[input.id]} setVariable={setVariable(input.id)} {...props} />; 73 }); 74 75 return ( 76 <Card title={data.title}> 77 <div class="variables"> 78 {fields} 79 </div> 80 <fieldset> 81 <legend>Display</legend> 82 <button onClick={triggerRefresh}> 83 Randomise questions 84 </button> 85 <button onClick={revealAnswers}> 86 {showAnswers ? "Show questions" : "Show answers"} 87 </button> 88 </fieldset> 89 <div class="print"> 90 <ol class="master-question-list"> 91 {questions} 92 </ol> 93 </div> 94 </Card> 95 ); 96 }