UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

212 lines (194 loc) • 6.66 kB
/** @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> ``` **/ @withStyleOverrides(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> ) } }