Skip to content

Commit e21819b

Browse files
authored
Merge pull request #110 from danielemery/108-display-question-and-answer-text-when-available
Add basic view for quiz questions and answers on the quiz details page
2 parents ce704df + 507837c commit e21819b

File tree

6 files changed

+84
-4
lines changed

6 files changed

+84
-4
lines changed

src/QuizDetails.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useMutation, useQuery } from '@apollo/client';
44
import { Fragment } from 'preact';
55

66
import QuizImageComponent from './QuizImage';
7+
import QuizQuestions from './QuizQuestions';
78
import Button from './components/Button';
89
import Loader from './components/Loader';
910
import { Table } from './components/Table';
@@ -65,6 +66,7 @@ export default function Quiz() {
6566
<dd className='text-xs mt-2 lg:text-sm text-gray-500'>{formatDateTime(data.quiz.uploadedAt)}</dd>
6667
</div>
6768
</dl>
69+
{data.quiz.questions.length > 0 ? <QuizQuestions questions={data.quiz.questions} /> : null}
6870
{[...data.quiz.images]
6971
.sort((a, b) => {
7072
return imageTypeSortValues[a.type] - imageTypeSortValues[b.type];

src/QuizImage.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@ interface QuizImageProps {
1212
function typeToHeading(type: QuizImageType) {
1313
switch (type) {
1414
case 'ANSWER':
15-
return { title: 'Answers', subtitle: "This image contains answers, it's hidden by default" };
15+
return { title: 'Answers Image', subtitle: "This image contains answers, it's hidden by default." };
1616
case 'QUESTION':
17-
return { title: 'Questions' };
17+
return { title: 'Questions Image' };
1818
case 'QUESTION_AND_ANSWER':
19-
return { title: 'Questions with Answers', subtitle: "This image contains answers, it's hidden by default" };
19+
return {
20+
title: 'Questions with Answers Image',
21+
subtitle: "This image contains answers, it's hidden by default.",
22+
};
2023
}
2124
}
2225

2326
export default function QuizImageComponent({ image, className }: QuizImageProps) {
2427
const [isShown, setIsShown] = useState(image.type === 'QUESTION');
2528
const { title, subtitle } = typeToHeading(image.type);
2629
return (
27-
<div className={classnames('border-solid border-y-2 py-2', className)}>
30+
<div className={classnames('border-solid border-t-2 py-2', className)}>
2831
<div className='mb-2 lg:mb-4 lg:flex'>
2932
<h2 className='lg:inline lg:flex-auto font-semibold mb-2'>{title}</h2>
3033
<Button danger className='flex-none' onClick={() => setIsShown((prev) => !prev)}>

src/QuizQuestions.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { ExpandCollapseSection } from './components/ExpandCollapseSection';
2+
import { QuizQuestion } from './types/quiz';
3+
4+
export interface QuizQuestionsProps {
5+
questions: QuizQuestion[];
6+
}
7+
8+
export default function QuizQuestions({ questions }: QuizQuestionsProps) {
9+
return (
10+
<>
11+
<ExpandCollapseSection title='Questions' initiallyShown={true}>
12+
<ol>
13+
{questions.map((question) => (
14+
<li key={question.questionNum} className='mb-4'>
15+
{question.questionNum}. {question.question}
16+
</li>
17+
))}
18+
</ol>
19+
</ExpandCollapseSection>
20+
<ExpandCollapseSection title='Answers' fallbackText='Answers are hidden by default.' initiallyShown={false}>
21+
<ol>
22+
{questions.map((question) => (
23+
<li key={question.questionNum} className='mb-4'>
24+
{question.questionNum}. {question.answer}
25+
</li>
26+
))}
27+
</ol>
28+
</ExpandCollapseSection>
29+
</>
30+
);
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ComponentChildren } from 'preact';
2+
import { useState } from 'preact/hooks';
3+
4+
import Button from './Button';
5+
6+
export interface ExpandCollapseSectionProps {
7+
title: string;
8+
children: ComponentChildren;
9+
initiallyShown?: boolean;
10+
fallbackText?: string;
11+
}
12+
13+
export function ExpandCollapseSection({
14+
title,
15+
children,
16+
initiallyShown = true,
17+
fallbackText,
18+
}: ExpandCollapseSectionProps) {
19+
const [sectionShown, setSectionShown] = useState(initiallyShown);
20+
return (
21+
<div className='border-solid border-t-2 py-2'>
22+
<div className='mb-2 lg:mb-4 lg:flex'>
23+
<h2 className='lg:inline lg:flex-auto font-semibold mb-2'>{title}</h2>
24+
<Button danger className='flex-none' onClick={() => setSectionShown((prev) => !prev)}>
25+
{sectionShown ? 'Hide' : 'Show'}
26+
</Button>
27+
</div>
28+
{sectionShown && children}
29+
{!sectionShown && fallbackText && <p className='italic'>{fallbackText}</p>}
30+
</div>
31+
);
32+
}

src/queries/quiz.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ export const QUIZ = gql`
5252
state
5353
type
5454
}
55+
questions {
56+
questionNum
57+
question
58+
answer
59+
}
5560
}
5661
}
5762
`;

src/types/quiz.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ export interface QuizImage {
1414
type: QuizImageType;
1515
}
1616

17+
export interface QuizQuestion {
18+
questionNum: number;
19+
question: string;
20+
answer: string;
21+
}
22+
1723
export interface Quiz {
1824
id: string;
1925
date: string;
@@ -22,4 +28,5 @@ export interface Quiz {
2228
uploadedAt: string;
2329
completions: QuizCompletion[];
2430
images: QuizImage[];
31+
questions: QuizQuestion[];
2532
}

0 commit comments

Comments
 (0)