@instructure/quiz-taking
Version:
173 lines (151 loc) • 5.54 kB
JavaScript
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import ImmutablePropTypes from 'react-immutable-proptypes'
import extractTextFromHtml from '@instructure/quiz-interactions/util/extractTextFromHtml'
import {substituteVars} from '@instructure/quiz-interactions/components/formula/common/util'
import t from '@instructure/quiz-i18n/format-message'
import {generateDisplayPositions} from '@instructure/quiz-core/common/util/generateDisplayPositions'
import {Stimulus} from '@instructure/quiz-core/common/components/layout/sidebar/Stimulus/index'
import {Sidebar} from '@instructure/quiz-core/common/components/layout/sidebar/Sidebar/index'
import {onPhone} from '@instructure/quiz-core/common/util/windowChecks'
import SidebarItem from './SidebarItem'
import {SIDEBAR_ITEM_REF, FORMULA_SLUG} from '@instructure/quiz-common/constants'
import {withI18nSupport} from '@instructure/quiz-common/with-i18n-support'
export class TakingSidebar extends withI18nSupport(Component) {
static propTypes = {
allowBacktracking: PropTypes.bool.isRequired,
quizTitle: PropTypes.string.isRequired,
setFocusTitleAndInstructions: PropTypes.func.isRequired,
goToItem: PropTypes.func.isRequired,
isOneQuestionAtATime: PropTypes.bool.isRequired,
pinnedItems: ImmutablePropTypes.listOf(
PropTypes.shape({
sessionItemId: PropTypes.string.isRequired,
position: PropTypes.number.isRequired,
}),
).isRequired,
role: PropTypes.string,
screenreaderNotification: PropTypes.func.isRequired,
scrollToItem: PropTypes.func.isRequired,
sessionItems: ImmutablePropTypes.list.isRequired,
sessionNotLoaded: PropTypes.bool.isRequired,
sidebarOpen: PropTypes.bool,
toggleSidebar: PropTypes.func.isRequired,
locale: PropTypes.string,
}
static defaultProps = {
role: 'navigation',
sidebarOpen: false,
locale: null,
}
static contextTypes = {
locale: PropTypes.string,
}
generateItemKey(id) {
return `${SIDEBAR_ITEM_REF}_${id}`
}
setRef(key) {
return node => {
this[key] = node
}
}
scrollToItem = position => itemId => {
if (this.props.isOneQuestionAtATime) this.scrollToItemOqaat(position, itemId)
else this.props.scrollToItem(itemId)
if (onPhone() && this.props.sidebarOpen) this.props.toggleSidebar()
}
scrollToItemOqaat = (position, itemId) => {
const itemMessage = t('Current question changed to question {position, number}', {
position: position || 1,
})
const message = position
? itemMessage
: `${t('Navigated to quiz title and instructions.')} ${itemMessage}`
this.props.setFocusTitleAndInstructions(!position)
this.props.goToItem(position || 1)
if (!position) {
setTimeout(() => {
this.props.scrollToItem(itemId)
this.props.screenreaderNotification(message)
}, 100)
} else {
this.props.screenreaderNotification(message)
}
}
getItemBody(item, locale) {
let itemBody = item.getItemBody()
if (item.getInteractionType().slug === FORMULA_SLUG) {
const variables = item.toJS().interactionData.variables
itemBody = substituteVars(itemBody, variables, locale)
}
return extractTextFromHtml(itemBody || '')
}
renderSidebarItem = (sessionItem, _displayPosition) => {
const item = sessionItem.getItem()
const key = this.generateItemKey(item.id)
const {sidebarOpen} = this.props
return (
<SidebarItem
inStimulus={sessionItem.isStimulus}
itemBody={this.getItemBody(item, this.locale)}
itemId={item.id}
itemName={item.getInteractionType().name}
key={key}
pointsPossible={sessionItem.pointsPossible}
position={sessionItem.questionNumber}
actualPosition={sessionItem.position}
quizEntryId={sessionItem.id}
ref={this.generateItemKey(item.id)}
scrollToItem={this.scrollToItem(sessionItem.bolaPosition || sessionItem.position)}
sessionItem={sessionItem}
sidebarOpen={sidebarOpen}
/>
)
}
renderSidebarItems() {
const {sessionItems} = this.props
return generateDisplayPositions(sessionItems).map(si => {
const sessionItem = si.record
const {sidebarOpen} = this.props
if (sessionItem.isStimulus) {
const key = this.generateItemKey(si.record.id)
return (
<Stimulus
displayPosition={si.displayPosition}
itemId={sessionItem.id}
key={key}
ref={this.setRef(key)}
renderSidebarItem={this.renderSidebarItem}
scrollToItem={this.scrollToItem(sessionItem.bolaPosition || sessionItem.position)}
sidebarOpen={sidebarOpen}
stimulusParent={sessionItem}
/>
)
}
return <div key={sessionItem.id}>{this.renderSidebarItem(sessionItem)}</div>
})
}
render() {
if (
this.props.sessionNotLoaded ||
(this.props.isOneQuestionAtATime && !this.props.allowBacktracking)
) {
return null
}
return (
<Sidebar
taking
role={this.props.role}
title={this.props.quizTitle}
pinnedItems={this.props.pinnedItems}
scrollToItem={this.scrollToItem}
sidebarOpen={this.props.sidebarOpen}
toggleSidebar={this.props.toggleSidebar}
screenreaderNotification={this.props.screenreaderNotification}
>
{this.renderSidebarItems()}
</Sidebar>
)
}
}
export default TakingSidebar