@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
180 lines (156 loc) • 5.31 kB
JavaScript
/** @jsx jsx */
import {Component} from 'react'
import PropTypes from 'prop-types'
import {RadioInput} from '@instructure/ui-radio-input'
import {jsx} from '@instructure/emotion'
import t from '@instructure/quiz-i18n/format-message'
import {ItemBodyWrapper} from '@instructure/quiz-rce/components/ItemBodyWrapper/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'
const TRUE_CHOICE = 'trueChoice'
const FALSE_CHOICE = 'falseChoice'
/**
---
category: TrueFalse
---
True False Result component
```jsx_example
<SettingsSwitcher locales={LOCALES}>
<TrueFalseResult
itemBody="The sun is a star"
itemId="12"
interactionData={{
trueChoice: 'True',
falseChoice: 'False'
}}
scoredData={{
value: {
true: { resultScore: 1, userResponded: true },
false: { resultScore: 0, userResponded: false }
}}
}
/>
</SettingsSwitcher>
```
**/
export default class TrueFalseResult extends Component {
static displayName = 'TrueFalseResult'
static componentId = `Quizzes${this.displayName}`
static propTypes = {
interactionData: PropTypes.shape({
trueChoice: PropTypes.string,
falseChoice: PropTypes.string,
}).isRequired,
itemBody: PropTypes.string.isRequired,
itemId: PropTypes.string,
scoredData: PropTypes.shape({
correct: PropTypes.bool,
value: PropTypes.shape({
true: PropTypes.shape({
resultScore: PropTypes.number,
userResponded: PropTypes.bool,
}),
false: PropTypes.shape({
resultScore: PropTypes.number,
userResponded: PropTypes.bool,
}),
}),
}).isRequired,
styles: PropTypes.object,
}
static defaultProps = {
itemId: void 0,
}
getUserResponse() {
const {value} = this.props.scoredData
if (!value) return void 0
if (value.true && value.true.userResponded) return true
if (value.false && value.false.userResponded) return false
return null
}
getCorrectAnswer() {
const {value} = this.props.scoredData
if (!value) return void 0
const trueScore = value.true && value.true.resultScore
const falseScore = value.false && value.false.resultScore
if (typeof trueScore !== 'undefined') {
return trueScore > 0
} else if (typeof falseScore !== 'undefined') {
return falseScore <= 0 // if we're > 0 we want this to return false
}
// unknown answer!
return void 0
}
getCorrectAnswerLabel() {
const {interactionData, scoredData} = this.props
const {value} = scoredData
if (!value) return null
if (value.true && value.true.resultScore > 0) {
return interactionData[TRUE_CHOICE]
} else if (value.false && value.false.resultScore > 0) {
return interactionData[FALSE_CHOICE]
}
return null
}
renderUngradedChoice(name, label, checked) {
return (
<RadioInput checked={checked} value={checked.toString()} readOnly name={name} label={label} />
)
}
renderChoice(choiceType, correctAnswer, userResponse) {
const {interactionData} = this.props
const isChecked = choiceType === userResponse
const label = interactionData[choiceType ? TRUE_CHOICE : FALSE_CHOICE]
if (typeof correctAnswer === 'undefined' || !isChecked) {
return this.renderUngradedChoice(name, label, !!isChecked)
}
let status
if (choiceType === correctAnswer) {
status = 'correct'
} else {
status = 'incorrect'
}
const correctAnswerLabel = this.getCorrectAnswerLabel()
const name = `interaction_${this.props.itemId}_${choiceType}`
return (
<FeedbackWrapper
correctAnswer={correctAnswerLabel}
hiddenCorrectAnswerText={t('Correct answer: ')}
hiddenIncorrectAnswerText={t('Incorrect answer: ')}
status={status}
userResponse={label}
>
<RadioInput checked value="true" readOnly name={name} label={label} />
</FeedbackWrapper>
)
}
render() {
const userResponse = this.getUserResponse()
const correctAnswer = this.getCorrectAnswer()
const correctnessKnown = typeof this.props.scoredData.correct !== 'undefined'
const responseHidden = typeof userResponse === 'undefined'
return (
<ItemBodyWrapper itemBody={this.props.itemBody}>
<div className="fs-mask">
<div css={this.props.styles.choiceWrapper}>
{this.renderChoice(true, correctAnswer, userResponse)}
</div>
<div css={this.props.styles.choiceWrapper}>
{this.renderChoice(false, correctAnswer, userResponse)}
</div>
{userResponse == null && (
<NoResponse
css={this.props.styles.noResponseWrapper}
correctAnswerLabel={this.getCorrectAnswerLabel(correctAnswer)}
responseHidden={responseHidden}
status={userResponse === null && correctnessKnown ? 'incorrect' : 'unknown'}
/>
)}
</div>
</ItemBodyWrapper>
)
}
}