@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
221 lines (204 loc) • 7.46 kB
JavaScript
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
import {Checkbox} from '@instructure/ui-checkbox'
import {TextInput} from '@instructure/quiz-common/components/TextInput/index'
import {FormFieldGroup} from '@instructure/quiz-common/components/FormFieldGroup/index'
import NumberInput from '@instructure/quiz-number-input/components/NumberInput/index'
import FileUploadInteractionType from '../../../records/interactions/file_upload'
import QuestionContainer from '../../common/edit/components/QuestionContainer'
import QuestionSettingsContainer from '../../common/edit/components/QuestionSettingsContainer'
import withEditTools from '../../../util/withEditTools'
import t from '@instructure/quiz-i18n/format-message'
import QuestionSettingsPanel from '../../common/edit/components/QuestionSettingsPanel'
import CalculatorOptionWithOqaatAlert from '../../common/edit/components/CalculatorOptionWithOqaatAlert'
/**
---
category: FileUpload
---
File Upload Edit component
```jsx_example
function Example (props) {
const exampleProps = {
itemBody: 'Give two examples of tortoises',
interactionData: {
restrictCount: true,
filesCount: '2'
},
overrideEditableForRegrading: false,
properties: {
restrictTypes: true,
allowedTypes: 'media/*'
}
}
return (
<FileUploadEdit {...exampleProps} {...props} />
)
}
<SettingsSwitcher locales={LOCALES}>
<EditStateProvider>
<Example />
</EditStateProvider>
</SettingsSwitcher>
```
**/
export default class FileUploadEdit extends Component {
static interactionType = FileUploadInteractionType
static propTypes = {
additionalOptions: PropTypes.array,
calculatorType: PropTypes.string,
changeItemState: PropTypes.func,
enableRichContentEditor: PropTypes.bool,
interactionData: PropTypes.shape({
restrictCount: PropTypes.bool.isRequired,
filesCount: PropTypes.string.isRequired,
}).isRequired,
itemBody: PropTypes.string.isRequired,
onModalClose: PropTypes.func,
onModalOpen: PropTypes.func,
oneQuestionAtATime: PropTypes.bool,
openImportModal: PropTypes.func,
overrideEditableForRegrading: PropTypes.bool,
properties: PropTypes.shape({
restrictTypes: PropTypes.bool.isRequired,
allowedTypes: PropTypes.string,
}).isRequired,
setOneQuestionAtATime: PropTypes.func,
...withEditTools.injectedProps,
showCalculatorOption: PropTypes.bool,
}
static defaultProps = {
additionalOptions: [],
calculatorType: 'none',
enableRichContentEditor: true,
oneQuestionAtATime: false,
overrideEditableForRegrading: false,
setOneQuestionAtATime: Function.prototype,
changeItemState: void 0,
onModalClose: void 0,
onModalOpen: void 0,
openImportModal: void 0,
showCalculatorOption: true,
}
handleCalculatorTypeChange = (e, value) => {
this.props.changeItemState({
calculatorType: value,
})
}
handleRestrictCountChange = () =>
this.props.changeItemState({
interactionData: {
...this.props.interactionData,
restrictCount: !this.props.interactionData.restrictCount,
},
})
handleFilesCountChange = (event, countString, normalizedCountString) =>
this.props.changeItemState({
interactionData: {
...this.props.interactionData,
filesCount: normalizedCountString,
},
})
handleRestrictTypesChange = event =>
this.props.changeItemState({
properties: {
...this.props.properties,
restrictTypes: event.target.checked,
},
})
handleAllowedTypesChange = event =>
this.props.changeItemState({
properties: {
...this.props.properties,
allowedTypes: event.target.value,
},
})
renderOptions() {
const {restrictTypes, allowedTypes} = this.props.properties
const {restrictCount, filesCount} = this.props.interactionData
const allowedTypesDescription = t('File extensions')
const filesCountDescription = t('Max number of files')
const description = <ScreenReaderContent>{t('File upload options')}</ScreenReaderContent>
const fieldGroup = (
<FormFieldGroup rowSpacing="small" description={description}>
{this.props.showCalculatorOption && (
<CalculatorOptionWithOqaatAlert
disabled={this.props.overrideEditableForRegrading}
calculatorValue={this.props.calculatorType}
onCalculatorTypeChange={this.handleCalculatorTypeChange}
oqaatChecked={this.props.oneQuestionAtATime}
onOqaatChange={this.props.setOneQuestionAtATime}
/>
)}
<Checkbox
disabled={this.props.overrideEditableForRegrading}
checked={restrictCount}
label={t('Limit File number')}
onChange={this.handleRestrictCountChange}
value="restrictCount"
data-automation="sdk-limit-file-number-checkbox"
/>
{restrictCount && (
<NumberInput
disabled={this.props.overrideEditableForRegrading}
renderLabel={<ScreenReaderContent>{filesCountDescription}</ScreenReaderContent>}
messages={this.props.getErrors('interactionData.filesCount')}
min={1}
onChange={this.handleFilesCountChange}
placeholder={filesCountDescription}
value={filesCount}
data-automation="sdk-limit-file-number-input"
/>
)}
<Checkbox
checked={restrictTypes}
disabled={this.props.overrideEditableForRegrading}
label={t('Restrict File Types')}
onChange={this.handleRestrictTypesChange}
value="restrictTypes"
data-automation="sdk-restrict-file-type-checkbox"
/>
{restrictTypes && (
<TextInput
interaction={this.props.overrideEditableForRegrading ? 'disabled' : 'enabled'}
renderLabel={<ScreenReaderContent>{allowedTypesDescription}</ScreenReaderContent>}
messages={[
...this.props.getErrors('properties.allowedTypes'),
{text: t('Enter file extensions separated by a comma'), type: 'hint'},
]}
onChange={this.handleAllowedTypesChange}
placeholder={allowedTypesDescription}
type="text"
value={allowedTypes}
data-automation="sdk-file-extensions-input"
/>
)}
</FormFieldGroup>
)
return (
<QuestionSettingsContainer additionalOptions={this.props.additionalOptions}>
<QuestionSettingsPanel label={t('Options')} defaultExpanded>
{fieldGroup}
</QuestionSettingsPanel>
</QuestionSettingsContainer>
)
}
render() {
return (
<div>
<QuestionContainer
disabled={this.props.overrideEditableForRegrading}
enableRichContentEditor={this.props.enableRichContentEditor}
itemBody={this.props.itemBody}
onDescriptionChange={this.props.onDescriptionChange}
onModalClose={this.props.onModalClose}
onModalOpen={this.props.onModalOpen}
openImportModal={this.props.openImportModal}
stemErrors={this.props.getErrors('itemBody')}
/>
{this.renderOptions()}
</div>
)
}
}