@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
126 lines (110 loc) • 3.72 kB
JavaScript
import React from 'react'
import {addValidator, each, rule, onSelf} from 'instructure-validations'
import {isScientificNotation} from '@instructure/quiz-scientific-notation'
import {Text} from '@instructure/ui-text'
import {FORMULA_SLUG} from '../../interaction_slugs'
import InteractionType from '../InteractionType'
import {formulaSyntaxError, variablesFromItemBody} from '../../util/formula'
import {numericMessage} from '../../util/validationHelpers'
import t from '@instructure/quiz-i18n/format-message'
const hasVariables = itemBody => {
if (variablesFromItemBody(itemBody).length === 0) {
return t('Question Stem must contain variables')
}
}
const formulaSyntax = (formula, options) => {
const variables = variablesFromItemBody(options.itemBody)
return formulaSyntaxError(variables, formula)
}
addValidator('hasVariables', hasVariables)
addValidator('formulaSyntax', formulaSyntax)
export const variableRules = variable => {
const minRule = rule('numeric', {message: numericMessage(t('Min'))})
const maxRule = rule('numeric', {
message: numericMessage(t('Maximum')),
min: variable.min,
minMessage: t('Must be larger than minimum value'),
})
const scientificNotationRule = rule('scientificNotation', {
message: t('Must be in scientific notation'),
})
// Don't allow just min or max in scientific notation: it's both, or neither
const min = isScientificNotation(variable.max) ? [scientificNotationRule, minRule] : [minRule]
const max = isScientificNotation(variable.min) ? [scientificNotationRule, maxRule] : [maxRule]
const precision = [
rule('numeric', {
decMessage: t('Minimum value must have at least the same number of decimals as precision'),
type: 'decimals',
value: variable.min,
}),
rule('numeric', {
decMessage: t('Maximum value must have at least the same number of decimals as precision'),
type: 'decimals',
value: variable.max,
}),
]
return {min, max, precision}
}
export default class FormulaInteractionType extends InteractionType {
constructor(obj) {
super()
super.initializeProps(obj)
}
slug = FORMULA_SLUG
translatedName = t('Formula')
getDefaultScoringData = intData => {
return {
value: {
answerCount: '200',
formula: '',
generatedSolutions: [],
variables: [],
// TODO: set this from the UI, rather than being stuck with the default
numeric: {
type: 'marginOfError',
marginType: 'absolute',
margin: '0',
},
},
}
}
getDefaultInteractionData = () => ({})
getDefaultUserResponse() {
return {value: ''}
}
getRenderedResponse = responseValue => {
return <Text color="primary">{responseValue}</Text>
}
static validations = (obj = {}) => {
const numeric =
obj.scoringData.value.numeric && obj.scoringData.value.numeric.type === 'marginOfError'
? {
margin: [rule('numeric', {message: numericMessage(t('Margin')), min: 0})],
}
: []
return {
itemBody: [
rule('presence', {message: t('Question Stem cannot be blank')}),
rule('hasVariables'),
],
scoringData: {
value: {
variables: [each(variableRules)],
formula: [
rule('presence', {message: t('Formula cannot be blank')}),
rule('formulaSyntax', {itemBody: obj.itemBody}),
],
numeric,
generatedSolutions: [
onSelf(
rule('listSize', {
min: 1,
minMessage: t('Must have at least one solution'),
}),
),
],
},
},
}
}
}