@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
185 lines (170 loc) • 5.25 kB
JavaScript
/** @jsx jsx */
import {Component} from 'react'
import PropTypes from 'prop-types'
import {jsx} from '@instructure/emotion'
import {Text} from '@instructure/ui-text'
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: Ordering
---
Ordering Result component
```jsx_example
<SettingsSwitcher locales={LOCALES}>
<OrderingResult
itemBody="Order these characters from tallest to shortest:"
interactionData={{
choices: {
uuid4: { id: 'uuid4', itemBody: '<p>Aragorn</p>' },
uuid3: { id: 'uuid3', itemBody: '<p>Gimli</p>' },
uuid2: { id: 'uuid2', itemBody: '<p>Frodo</p>' },
uuid1: { id: 'uuid1', itemBody: '<p>Gollum</p>' }
}
}}
properties={{
displayAnswersParagraph: true,
includeLabels: true,
topLabel: 'Taller',
bottomLabel: 'Shorter'
}}
scoredData={{
value: [{
userResponded: 'uuid3',
resultScore: 0,
value: 'uuid4'
}, {
userResponded: 'uuid4',
resultScore: 0,
value: 'uuid3'
}, {
userResponded: 'uuid2',
resultScore: 1,
value: 'uuid2'
}, {
userResponded: 'uuid1',
resultScore: 1,
value: 'uuid1'
}]
}}
/>
</SettingsSwitcher>
```
**/
(generateStyle, generateComponentTheme)
export default class OrderingResult extends Component {
static displayName = 'OrderingResult'
static componentId = `Quizzes${this.displayName}`
static propTypes = {
interactionData: PropTypes.shape({
choices: PropTypes.objectOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
itemBody: PropTypes.string.isRequired,
}),
).isRequired,
}).isRequired,
itemBody: PropTypes.string.isRequired,
properties: PropTypes.shape({
displayAnswersParagraph: PropTypes.bool,
includeLabels: PropTypes.bool,
topLabel: PropTypes.string,
bottomLabel: PropTypes.string,
}).isRequired,
scoredData: PropTypes.shape({
correct: PropTypes.bool,
value: PropTypes.arrayOf(
PropTypes.shape({
resultScore: PropTypes.number,
userResponded: PropTypes.string,
value: PropTypes.string,
}),
),
}).isRequired,
makeStyles: PropTypes.func,
styles: PropTypes.object,
}
componentDidMount() {
this.props.makeStyles()
}
componentDidUpdate() {
this.props.makeStyles()
}
renderLabel(labelPosition) {
const {properties} = this.props
if (properties.includeLabels) {
return (
<div className={labelPosition} css={this.props.styles[labelPosition]}>
<Text color="primary">{properties[labelPosition]}</Text>
</div>
)
}
}
renderChoices() {
const {choices} = this.props.interactionData
const {correct, value} = this.props.scoredData
if (!value || value.length === 0) {
return (
<NoResponse
responseHidden={!value}
status={typeof correct === 'undefined' ? 'unknown' : 'incorrect'}
richContent
/>
)
}
return value.map((answer, idx) => {
let status
if (answer.resultScore >= 1) {
status = 'correct'
} else if (answer.resultScore <= 0) {
status = 'incorrect'
} else {
status = 'unknown'
}
const userChoice = choices[answer.userResponded]
const correctAnswer = choices[answer.value] ? choices[answer.value].itemBody : null
const key = `choice_${idx}`
return (
<div css={this.props.styles.feedbackWrapper} key={key}>
{userChoice ? (
<FeedbackWrapper
hiddenCorrectAnswerText={t('Correct Order Answer: ')}
hiddenIncorrectAnswerText={t('Incorrect Order Answer: ')}
correctAnswer={correctAnswer}
status={status}
richContent
>
<RichContentRenderer
customStyles={this.props.styles.userResponse}
content={userChoice.itemBody}
/>
</FeedbackWrapper>
) : (
<NoResponse
correctAnswerLabel={correctAnswer}
responseHidden={answer.userResponded === void 0}
status={status}
richContent
/>
)}
</div>
)
})
}
render() {
return (
<div css={this.props.styles.holder}>
<ItemBodyWrapper itemBody={this.props.itemBody}>
{this.renderLabel('topLabel')}
<div css={this.props.styles.choicesWrapper}>{this.renderChoices()}</div>
{this.renderLabel('bottomLabel')}
</ItemBodyWrapper>
</div>
)
}
}