@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
212 lines (194 loc) • 6.66 kB
JavaScript
/** @jsx jsx */
import {Component} from 'react'
import PropTypes from 'prop-types'
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
import {Checkbox} from '@instructure/ui-checkbox'
import {Heading} from '@instructure/ui-heading'
import {jsx} from '@instructure/emotion'
import t from '@instructure/quiz-i18n/format-message'
import {ItemBodyWrapper} from '@instructure/quiz-rce/components/ItemBodyWrapper/index'
import {RichContentRenderer} from '@instructure/quiz-rce/components/RichContentRenderer/index'
import {FeedbackWrapper, NoResponse} from '@instructure/quiz-results-feedback'
import generateStyle from './styles'
import generateComponentTheme from './theme'
import {withStyleOverrides} from '@instructure/quiz-common/util/withStyleOverrides'
/**
---
category: MultipleAnswer
---
Multiple Answer Result component
```jsx_example
<SettingsSwitcher locales={LOCALES}>
<MultipleAnswerResult
itemBody="Who was in the first cabinet of the USA?"
interactionData={{
choices: [
{ id: 'uuid1', position: 1, itemBody: '<p>Thomas Jefferson</p>' },
{ id: 'uuid2', position: 2, itemBody: '<p>John Marshall</p>' },
{ id: 'uuid3', position: 3, itemBody: '<p>John Knox</p>' },
{ id: 'uuid4', position: 4, itemBody: '<p>Alexander Hamilton</p>' },
{ id: 'uuid5', position: 5, itemBody: '<p>Aaron Burr</p>' },
{ id: 'uuid6', position: 6, itemBody: '<p>Ben Franklin</p>' }
]
}}
scoredData={{
correct: false,
value: {
uuid1: { resultScore: 1, userResponded: true },
uuid2: { resultScore: 1, userResponded: false },
uuid3: { resultScore: 0, userResponded: true }
}
}}
/>
</SettingsSwitcher>
```
**/
(generateStyle, generateComponentTheme)
export default class MultipleAnswerResult extends Component {
static displayName = 'MultipleAnswerResult'
static componentId = `Quizzes${this.displayName}`
static propTypes = {
MultipleAnswerFeedback: PropTypes.object,
interactionData: PropTypes.shape({
choices: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
itemBody: PropTypes.string,
position: PropTypes.number,
}),
),
}).isRequired,
itemBody: PropTypes.string.isRequired,
scoredData: PropTypes.shape({
correct: PropTypes.bool,
value: PropTypes.objectOf(
PropTypes.shape({
correct: PropTypes.bool,
resultScore: PropTypes.number,
userResponded: PropTypes.bool,
}),
),
}).isRequired,
styles: PropTypes.object,
}
renderPlainChoice = ({id, itemBody}, checked) => {
let srtext = t('Answer, ')
if (typeof checked !== 'undefined') {
srtext = checked ? t('Selected Answer, ') : t('Unselected Answer, ')
}
const choiceFeedback = this.props.MultipleAnswerFeedback?.[id]
return (
<div key={id} css={this.props.styles.responseWrapper}>
<Checkbox
value={id}
label={
<div>
<ScreenReaderContent>{srtext}</ScreenReaderContent>
<RichContentRenderer content={itemBody} />
</div>
}
checked={checked}
onChange={() => {}}
readOnly
/>
{checked && this.renderAnswerFeedback(choiceFeedback)}
</div>
)
}
renderFeedbackChoice = ({id, itemBody}, checked, status) => {
let feedbackText,
wrapperStatus = 'unknown'
if (checked) {
if (status === 'correct') {
feedbackText = t('Selected Answer - Correct')
wrapperStatus = 'correct'
} else if (status === 'incorrect') {
feedbackText = t('Selected Answer - Incorrect')
wrapperStatus = 'incorrect'
}
} else if (status === 'correct') {
feedbackText = t('Missed Option - Incorrect')
wrapperStatus = 'incorrect'
}
const choiceFeedback = this.props.MultipleAnswerFeedback?.[id]
return (
<div key={id} css={this.props.styles.responseWrapper}>
<FeedbackWrapper
correctAnswer={feedbackText}
hiddenCorrectAnswerText={t('Correct answer: ')}
hiddenIncorrectAnswerText={t('Incorrect answer: ')}
status={wrapperStatus}
subTitleDescription=""
richContent
>
<Checkbox
value={id}
label={<RichContentRenderer content={itemBody} />}
checked={checked}
onChange={() => {}}
readOnly
/>
</FeedbackWrapper>
{checked && this.renderAnswerFeedback(choiceFeedback)}
</div>
)
}
renderAnswerFeedback = choiceFeedback => {
if (!choiceFeedback) return null
return (
<div
css={this.props.styles.answerFeedbackWrapper}
data-automation="sdk-answer-feedback-display"
>
<Heading level="h4" margin="0 0 xx-small 0">
{t('Feedback')}
</Heading>
<RichContentRenderer content={choiceFeedback} />
</div>
)
}
noResponseStatus() {
const {correct} = this.props.scoredData
if (typeof correct === 'undefined') return 'unknown'
return correct ? 'correct' : 'incorrect'
}
render() {
const {scoredData} = this.props
const choices = this.props.interactionData.choices.map(choice => {
const choiceData = (scoredData.value && scoredData.value[choice.id]) || {}
const correct = choiceData.hasOwnProperty('correct')
? choiceData.correct
: choiceData.resultScore
const checked = choiceData.userResponded
return {choice, correct, checked}
})
const nothingSelected = choices.every(({checked}) => !checked)
return (
<ItemBodyWrapper itemBody={this.props.itemBody}>
{choices.map(({choice, correct, checked}) => {
let status
if (typeof checked !== 'undefined') {
if (correct === true || correct > 0) {
status = 'correct'
} else if (correct === false || correct === 0) {
status = 'incorrect'
}
}
if (!status) {
// Choice has no feedback
return this.renderPlainChoice(choice, checked)
} else {
return this.renderFeedbackChoice(choice, checked, status)
}
})}
{nothingSelected && (
<NoResponse
css={this.props.styles.noResponseWrapper}
responseHidden={!scoredData.value}
status={this.noResponseStatus()}
/>
)}
</ItemBodyWrapper>
)
}
}