UNPKG

quiz-interactions

Version:

A React UI component Library for quiz interaction types.

371 lines (325 loc) 16.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _isNaN = _interopRequireDefault(require("lodash/isNaN")); var _uiElements = require("@instructure/ui-elements"); var _uiForms = require("@instructure/ui-forms"); var _quizNumberInput = _interopRequireDefault(require("@instructure/quiz-number-input")); var _uiA11y = require("@instructure/ui-a11y"); var _uiButtons = require("@instructure/ui-buttons"); var _uiThemeable = require("@instructure/ui-themeable"); var _uiLayout = require("@instructure/ui-layout"); var _quizI18n = require("@instructure/quiz-i18n"); var _quizScientificNotation = require("@instructure/quiz-scientific-notation"); var _instUIMessages = require("../../../util/instUIMessages"); var util = _interopRequireWildcard(require("./util")); var _theme = _interopRequireDefault(require("./theme")); var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message")); var _dec, _class, _class2, _temp; var styles = { componentId: 'fCxPy', template: function template(theme) { return "\n\n.fCxPy_fKmi{padding-bottom:".concat(theme.sectionHeadingPaddingBottom || 'inherit', ";padding-top:").concat(theme.sectionHeadingPaddingTop || 'inherit', "}\n\n.fCxPy_pJNU{padding-bottom:").concat(theme.instructionsPaddingBottom || 'inherit', "}\n\n.fCxPy_ftwL{padding-top:").concat(theme.generateSolutionsInputPaddingTop || 'inherit', "}\n\n.fCxPy_cWFj{padding:").concat(theme.generateButtonPaddingLeft || 'inherit', "}\n\n.fCxPy_dVha{padding-top:").concat(theme.generatedSolutionsPaddingTop || 'inherit', "}\n\n.fCxPy_fqEc{padding-left:").concat(theme.marginTextPadding || 'inherit', ";padding-right:").concat(theme.marginTextPadding || 'inherit', "}\n\n.fCxPy_cdqO{color:").concat(theme.marginPlusMinusColor || 'inherit', ";font-weight:").concat(theme.marginPlusMinusWeight || 'inherit', "}\n\n.fCxPy_rMrG{overflow:auto}\n\n.fCxPy_rMrG>table{max-width:none}\n\n.fCxPy_ekQP{position:-webkit-sticky;position:sticky;right:0}"); }, 'sectionHeading': 'fCxPy_fKmi', 'instructions': 'fCxPy_pJNU', 'generateSolutionsInput': 'fCxPy_ftwL', 'generateButtonWrapper': 'fCxPy_cWFj', 'generatedSolutions': 'fCxPy_dVha', 'marginText': 'fCxPy_fqEc', 'marginPlusMinus': 'fCxPy_cdqO', 'tableWrapper': 'fCxPy_rMrG', 'outputCol': 'fCxPy_ekQP' }; var FormulaSection = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_class = (_temp = _class2 = /*#__PURE__*/ function (_Component) { (0, _inherits2.default)(FormulaSection, _Component); function FormulaSection() { var _getPrototypeOf2; var _this; (0, _classCallCheck2.default)(this, FormulaSection); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(FormulaSection)).call.apply(_getPrototypeOf2, [this].concat(args))); _this.state = { marginOfErrorValue: null }; _this.handleMarginOfErrorChange = function (event, value, normalizedValue) { _this.setState({ marginOfErrorValue: value }); _this.props.handleMarginOfErrorChange(event, value, normalizedValue); }; _this.handleMarginOfErrorBlur = function () { _this.setState({ marginOfErrorValue: null }); }; _this.renderRow = function (solution, idx) { var inputValues = _this.variableNames.map(function (variableName) { return solution.inputs.find(function (v) { return v.name === variableName; }).value; }); var _this$props$scoringDa = _this.props.scoringData.value.numeric, margin = _this$props$scoringDa.margin, marginType = _this$props$scoringDa.marginType; var parsedMargin = parseFloat(margin); var marginString; if (margin === '' || parsedMargin === 0 || (0, _isNaN.default)(parsedMargin)) { marginString = null; } else if (marginType === 'absolute') { marginString = (0, _formatMessage.default)(' +/- {margin}', { margin: _this.formatNumStr(parsedMargin) }); } else { marginString = (0, _formatMessage.default)(' +/- {margin}%', { margin: _this.formatNumStr(parsedMargin) }); } return _react.default.createElement("tr", { key: idx }, inputValues.map(function (value, index) { return _react.default.createElement("td", { key: index }, _this.formatNumStr(value)); }), _react.default.createElement("td", { className: styles.outputCol }, _this.formatNumStr(solution.output), _react.default.createElement("span", { className: styles.marginPlusMinus }, marginString))); }; return _this; } (0, _createClass2.default)(FormulaSection, [{ key: "formatNumStr", value: function formatNumStr(value) { return (0, _quizScientificNotation.isScientificNotation)(value) ? value : _quizI18n.Decimal.toLocaleString(value.toString(), this.props.locale); } }, { key: "renderGeneratedSolutionsTable", value: function renderGeneratedSolutionsTable() { if (this.props.status === util.STATUS_RUNNING) { return _react.default.createElement("div", null, _react.default.createElement(_uiElements.Spinner, { renderTitle: (0, _formatMessage.default)('Running') })); } var solutions = this.props.scoringData.value.generatedSolutions; var errorMessage = null; if (this.props.status === util.STATUS_FAILED && solutions.length === 0) { return _react.default.createElement(_uiElements.Text, { color: "error" }, (0, _formatMessage.default)('We were not able to find any solutions.')); } else if (this.props.status === util.STATUS_FAILED) { errorMessage = (0, _formatMessage.default)("{ number, plural,\n one {We were only able to find 1 solution.}\n other {We were only able to find # solutions.}\n } ", { number: solutions.length }); } else if (solutions.length === 0) { return null; } return _react.default.createElement("div", null, _react.default.createElement(_uiElements.Text, { color: "primary" }, errorMessage), _react.default.createElement("div", { className: styles.tableWrapper }, _react.default.createElement(_uiElements.Table, { caption: _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Generated Results')), layout: "fixed" }, _react.default.createElement("thead", null, _react.default.createElement("tr", null, this.variableNames.map(function (variableName, idx) { return _react.default.createElement("th", { key: idx }, variableName); }), _react.default.createElement("th", { className: styles.outputCol }, (0, _formatMessage.default)('Result')))), _react.default.createElement("tbody", null, solutions.map(this.renderRow))))); } }, { key: "renderGeneratedSolutionsSection", value: function renderGeneratedSolutionsSection() { if (this.props.status === util.STATUS_CANCELED) { return null; } return _react.default.createElement("div", { className: styles.generatedSolutions }, this.props.status === util.STATUS_FORMULA_SETUP_INVALID ? _react.default.createElement(_uiElements.Text, { color: "error" }, (0, _formatMessage.default)('Error in formula setup. See above for details.')) : this.renderGeneratedSolutionsTable()); } }, { key: "formulaErrors", value: function formulaErrors() { if (this.props.status === util.STATUS_FORMULA_SETUP_INVALID) { return (0, _instUIMessages.toErrors)(this.props.formulaErrors || []); } } }, { key: "renderNumberOfGeneratedSolutionsInput", value: function renderNumberOfGeneratedSolutionsInput() { return _react.default.createElement(_quizNumberInput.default, { disabled: this.props.overrideEditableForRegrading, value: String(parseInt(this.props.scoringData.value.answerCount, 10) || 0), onChange: this.props.handleAnswerCountChange, label: (0, _formatMessage.default)('Number of solutions'), messages: (0, _instUIMessages.toErrors)(this.props.generatedSolutionsErrors), min: "1", max: "200", showArrows: true }); } }, { key: "renderSolutionPrecisionInput", value: function renderSolutionPrecisionInput() { return _react.default.createElement(_quizNumberInput.default, { disabled: this.props.overrideEditableForRegrading, decimalPrecision: 0, value: this.props.scoringData.value.answerPrecision || 0, onChange: this.props.handleAnswerPrecisionChange, label: (0, _formatMessage.default)('Decimal places'), min: "0", max: "16", showArrows: true }); } }, { key: "renderScientificNotationCheckbox", value: function renderScientificNotationCheckbox() { return _react.default.createElement(_uiForms.Checkbox, { checked: this.props.scoringData.value.scientificNotation || false, disabled: this.props.overrideEditableForRegrading, label: (0, _formatMessage.default)('Display as Scientific Notation'), onChange: this.props.handleScientificNotationChange, variant: "toggle" }); } }, { key: "renderMarginOfErrorTypeSelect", value: function renderMarginOfErrorTypeSelect() { return _react.default.createElement(_uiForms.Select, { onChange: this.props.handleMarginOfErrorTypeChange, selectedOption: this.props.scoringData.value.numeric.marginType, label: (0, _formatMessage.default)('Margin type'), "data-automation": "sdk-formula-margin-of-error-type" }, _react.default.createElement("option", { value: "absolute" }, (0, _formatMessage.default)('Absolute')), _react.default.createElement("option", { value: "percent" }, (0, _formatMessage.default)('Percent'))); } }, { key: "renderMarginOfErrorInput", value: function renderMarginOfErrorInput() { var value = this.state.marginOfErrorValue; if (value === null) { value = parseFloat(this.props.scoringData.value.numeric.margin); } return _react.default.createElement(_quizNumberInput.default, { value: value, onChange: this.handleMarginOfErrorChange, onBlur: this.handleMarginOfErrorBlur, label: (0, _formatMessage.default)('+/- margin of error'), min: "0", "data-automation": "sdk-formula-margin-of-error-value", showArrows: true }); } }, { key: "renderGenerateSolutionsButton", value: function renderGenerateSolutionsButton() { return _react.default.createElement(_uiButtons.Button, { disabled: this.props.overrideEditableForRegrading, variant: "primary", onClick: this.props.handleGenerateSolutions }, _react.default.createElement(_uiA11y.PresentationContent, null, (0, _formatMessage.default)('Generate')), _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Generate Solutions'))); } }, { key: "render", value: function render() { return _react.default.createElement("div", null, _react.default.createElement("div", { className: styles.sectionHeading }, _react.default.createElement(_uiElements.Text, { size: "large" }, (0, _formatMessage.default)('Formula Definition'))), _react.default.createElement("div", { className: styles.instructions }, _react.default.createElement(_uiElements.Text, { color: "primary" }, (0, _formatMessage.default)('Next, write the formula or formulas used to compute' + ' the correct answer. Use the same variable names listed above. (e.g., "5 + x")'))), _react.default.createElement(_uiForms.TextArea, { disabled: this.props.overrideEditableForRegrading, value: this.props.scoringData.value.formula, onChange: this.props.handleFormulaChange, messages: this.formulaErrors(), label: _react.default.createElement(_uiA11y.ScreenReaderContent, null, (0, _formatMessage.default)('Formula')), autoGrow: this.context.disableTextAreaAutoGrow ? false : null }), _react.default.createElement("div", null, _react.default.createElement("div", { className: styles.sectionHeading }, _react.default.createElement(_uiElements.Text, { size: "large" }, (0, _formatMessage.default)('Generate Possible Solutions'))), _react.default.createElement("div", { className: styles.instructions }, _react.default.createElement(_uiElements.Text, { color: "primary" }, (0, _formatMessage.default)('Finally, build as many variable-solution combinations as you need for your quiz.'))), _react.default.createElement("div", { className: styles.generateSolutionsInput }, _react.default.createElement(_uiLayout.Grid, { vAlign: "top", startAt: "medium" }, _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, this.renderNumberOfGeneratedSolutionsInput()), _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, this.renderSolutionPrecisionInput()), _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, _react.default.createElement(_uiLayout.View, { as: "div", margin: "medium 0 0 0", padding: "xx-small 0 0 0" }, this.renderScientificNotationCheckbox()))), !this.props.scoringData.value.scientificNotation && _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, this.renderMarginOfErrorTypeSelect()), _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, this.renderMarginOfErrorInput())), _react.default.createElement(_uiLayout.Grid.Row, null, _react.default.createElement(_uiLayout.Grid.Col, { width: 4 }, this.renderGenerateSolutionsButton())))), this.renderGeneratedSolutionsSection())); } }, { key: "variableNames", get: function get() { return this.props.scoringData.value.variables.map(function (variable) { return variable.name; }).sort(); } }]); FormulaSection.displayName = "FormulaSection"; return FormulaSection; }(_react.Component), _class2.propTypes = { formulaErrors: _propTypes.default.arrayOf(_propTypes.default.string), generatedSolutionsErrors: _propTypes.default.arrayOf(_propTypes.default.string), handleAnswerCountChange: _propTypes.default.func.isRequired, handleAnswerPrecisionChange: _propTypes.default.func.isRequired, handleFormulaChange: _propTypes.default.func.isRequired, handleGenerateSolutions: _propTypes.default.func.isRequired, handleMarginOfErrorChange: _propTypes.default.func.isRequired, handleMarginOfErrorTypeChange: _propTypes.default.func.isRequired, handleScientificNotationChange: _propTypes.default.func.isRequired, locale: _propTypes.default.string.isRequired, overrideEditableForRegrading: _propTypes.default.bool.isRequired, scoringData: _propTypes.default.object.isRequired, status: _propTypes.default.string.isRequired }, _class2.defaultProps = { formulaErrors: void 0, generatedSolutionsErrors: void 0 }, _class2.contextTypes = { disableTextAreaAutoGrow: _propTypes.default.bool }, _temp)) || _class); exports.default = FormulaSection;