UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

361 lines (360 loc) • 19.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); 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 _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = require("react"); var _propTypes = _interopRequireDefault(require("prop-types")); var _uiTable = require("@instructure/ui-table"); var _uiText = require("@instructure/ui-text"); var _uiSpinner = require("@instructure/ui-spinner"); var _uiCheckbox = require("@instructure/ui-checkbox"); var _uiA11yContent = require("@instructure/ui-a11y-content"); var _uiButtons = require("@instructure/ui-buttons"); var _emotion = require("@instructure/emotion"); var _uiView = require("@instructure/ui-view"); var _uiGrid = require("@instructure/ui-grid"); var _quizI18n = require("@instructure/quiz-i18n"); var _quizScientificNotation = require("@instructure/quiz-scientific-notation"); var _instUIMessages = require("../../../util/instUIMessages"); var util = _interopRequireWildcard(require("./util")); var _styles = _interopRequireDefault(require("./styles")); var _theme = _interopRequireDefault(require("./theme")); var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message")); var _quizNumberInput = require("@instructure/quiz-number-input"); var _quizCommon = require("@instructure/quiz-common"); var _uiAlerts = require("@instructure/ui-alerts"); var _dec, _class, _FormulaSection; /** @jsx jsx */ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _callSuper(_this, derived, args) { function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (e) { return false; } } derived = (0, _getPrototypeOf2["default"])(derived); return (0, _possibleConstructorReturn2["default"])(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], (0, _getPrototypeOf2["default"])(_this).constructor) : derived.apply(_this, args)); } var FormulaSection = exports["default"] = (_dec = (0, _quizCommon.withStyleOverrides)(_styles["default"], _theme["default"]), _dec(_class = (_FormulaSection = /*#__PURE__*/function (_Component) { function FormulaSection() { var _this2; (0, _classCallCheck2["default"])(this, FormulaSection); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this2 = _callSuper(this, FormulaSection, [].concat(args)); (0, _defineProperty2["default"])(_this2, "state", { marginOfErrorValue: null }); (0, _defineProperty2["default"])(_this2, "handleMarginOfErrorChange", function (event, value, normalizedValue) { _this2.setState({ marginOfErrorValue: value }); _this2.props.handleMarginOfErrorChange(event, value, normalizedValue); }); (0, _defineProperty2["default"])(_this2, "handleMarginOfErrorBlur", function () { _this2.setState({ marginOfErrorValue: null }); }); (0, _defineProperty2["default"])(_this2, "localizedScientificNotation", function (value) { var _ref = (value === null || value === void 0 ? void 0 : value.toString().split('*')) || [], _ref2 = (0, _slicedToArray2["default"])(_ref, 2), mantissa = _ref2[0], exponent = _ref2[1]; return "".concat(_this2.localizedValue(mantissa), "*").concat(exponent); }); (0, _defineProperty2["default"])(_this2, "localizedValue", function (value) { return value ? _quizI18n.Decimal.toLocaleString(value.toString(), _this2.props.locale) : null; }); (0, _defineProperty2["default"])(_this2, "renderRow", function (solution, idx) { var inputValues = _this2.variableNames.map(function (variableName) { var _solution$inputs$find; return (_solution$inputs$find = solution.inputs.find(function (v) { return v.name === variableName; })) === null || _solution$inputs$find === void 0 ? void 0 : _solution$inputs$find.value; }); var _this2$props$scoringD = _this2.props.scoringData.value.numeric, margin = _this2$props$scoringD.margin, marginType = _this2$props$scoringD.marginType; var parsedMargin = Number.parseFloat(margin); var marginString; if (margin === '' || parsedMargin === 0 || Number.isNaN(parsedMargin)) { marginString = null; } else if (marginType === 'absolute') { marginString = (0, _formatMessage["default"])(' +/- {margin}', { margin: _this2.formatNumStr(parsedMargin) }); } else { marginString = (0, _formatMessage["default"])(' +/- {margin}%', { margin: _this2.formatNumStr(parsedMargin) }); } return (0, _emotion.jsx)(_uiTable.Table.Row, { key: idx }, inputValues.map(function (value, index) { return ( // eslint-disable-next-line react/no-array-index-key (0, _emotion.jsx)(_uiTable.Table.Cell, { key: index }, _this2.formatNumStr(value)) ); }), (0, _emotion.jsx)(_uiTable.Table.Cell, null, _this2.formatNumStr(solution.output), (0, _emotion.jsx)("span", { css: _this2.props.styles.marginPlusMinus }, marginString))); }); return _this2; } (0, _inherits2["default"])(FormulaSection, _Component); return (0, _createClass2["default"])(FormulaSection, [{ key: "formatNumStr", value: function formatNumStr(value) { return (0, _quizScientificNotation.isScientificNotation)(value) ? this.localizedScientificNotation(value) : this.localizedValue(value); } }, { key: "variableNames", get: function get() { return this.props.scoringData.value.variables.map(function (variable) { return variable.name; }).sort(); } }, { key: "renderGeneratedSolutionsTable", value: function renderGeneratedSolutionsTable() { if (this.props.status === util.STATUS_RUNNING) { return (0, _emotion.jsx)("div", null, (0, _emotion.jsx)(_uiSpinner.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 (0, _emotion.jsx)("div", { role: "alert" }, (0, _emotion.jsx)(_uiAlerts.Alert, { hasShadow: false, variant: "warning" }, (0, _formatMessage["default"])('We were not able to find any solutions.'))); } if (this.props.status === util.STATUS_FAILED) { errorMessage = util.buildSolutionsGeneratedMessage(this.props.status, solutions.length); } else if (solutions.length === 0) { return null; } var idPrefix = 'generated-results-'; return (0, _emotion.jsx)("div", null, errorMessage && (0, _emotion.jsx)("div", { role: "alert" }, (0, _emotion.jsx)(_uiAlerts.Alert, { hasShadow: false, variant: "warning" }, errorMessage)), (0, _emotion.jsx)("div", { css: this.props.styles.tableWrapper }, (0, _emotion.jsx)(_uiTable.Table, { caption: (0, _formatMessage["default"])('Generated Results'), layout: "fixed" }, (0, _emotion.jsx)(_uiTable.Table.Head, null, (0, _emotion.jsx)(_uiTable.Table.Row, null, this.variableNames.map(function (variableName, idx) { return (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: idPrefix + idx, key: idx }, variableName); }), (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "generated-results-result" }, (0, _formatMessage["default"])('Result')))), (0, _emotion.jsx)(_uiTable.Table.Body, null, solutions.map(this.renderRow))))); } }, { key: "renderGeneratedSolutionsSection", value: function renderGeneratedSolutionsSection() { if (this.props.status === util.STATUS_CANCELED) { return null; } return (0, _emotion.jsx)("div", { css: this.props.styles.generatedSolutions }, this.props.status === util.STATUS_FORMULA_SETUP_INVALID ? (0, _emotion.jsx)(_uiAlerts.Alert, { liveRegionPoliteness: "polite", variant: "warning" }, (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() { var currentSolutionsNumber = String(Number.parseInt(this.props.scoringData.value.answerCount, 10) || 0); return (0, _emotion.jsx)(_quizNumberInput.NumberInput, { disabled: this.props.overrideEditableForRegrading, value: currentSolutionsNumber, onChange: this.props.handleAnswerCountChange, renderLabel: (0, _formatMessage["default"])('Number of solutions'), isRequired: true, messages: (0, _instUIMessages.toErrors)(this.props.generatedSolutionsErrors), min: "1", max: "200", showArrows: true, "data-automation": "sdk-number-of-solutions-input", "aria-valuetext": "".concat(currentSolutionsNumber, " ").concat((0, _formatMessage["default"])('Solutions possible')) }); } }, { key: "renderSolutionPrecisionInput", value: function renderSolutionPrecisionInput() { var currentDecimalPlaces = this.props.scoringData.value.answerPrecision || 0; return (0, _emotion.jsx)(_quizNumberInput.NumberInput, { decimalPrecision: 0, disabled: this.props.overrideEditableForRegrading, value: currentDecimalPlaces, onChange: this.props.handleAnswerPrecisionChange, renderLabel: (0, _formatMessage["default"])('Decimal places'), min: "0", max: "16", showArrows: true, "aria-valuetext": "".concat(currentDecimalPlaces, " ").concat((0, _formatMessage["default"])('Decimal places')) }); } }, { key: "renderScientificNotationCheckbox", value: function renderScientificNotationCheckbox() { return (0, _emotion.jsx)(_uiCheckbox.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 (0, _emotion.jsx)(_quizCommon.SimpleSelect, { onChange: this.props.handleMarginOfErrorTypeChange, value: this.props.scoringData.value.numeric.marginType, renderLabel: (0, _formatMessage["default"])('Margin type'), "data-automation": "sdk-formula-margin-of-error-type" }, (0, _emotion.jsx)(_quizCommon.SimpleSelect.Option, { id: "formula-section-select-option-absolute", value: "absolute" }, (0, _formatMessage["default"])('Absolute')), (0, _emotion.jsx)(_quizCommon.SimpleSelect.Option, { id: "formula-section-select-option-percent", value: "percent" }, (0, _formatMessage["default"])('Percent'))); } }, { key: "renderMarginOfErrorInput", value: function renderMarginOfErrorInput() { var value = this.state.marginOfErrorValue; if (value === null) { value = Number.parseFloat(this.props.scoringData.value.numeric.margin); } return (0, _emotion.jsx)(_quizNumberInput.NumberInput, { value: value, onChange: this.handleMarginOfErrorChange, onBlur: this.handleMarginOfErrorBlur, renderLabel: (0, _formatMessage["default"])('+/- margin of error'), min: "0", "data-automation": "sdk-formula-margin-of-error-value", showArrows: true, "aria-valuetext": "".concat(value, " ").concat((0, _formatMessage["default"])('+/- margin of error')) }); } }, { key: "renderGenerateSolutionsButton", value: function renderGenerateSolutionsButton() { return (0, _emotion.jsx)(_uiButtons.Button, { type: "submit", disabled: this.props.overrideEditableForRegrading, color: "primary", onClick: this.props.handleGenerateSolutions, "data-automation": "sdk-generate-button" }, (0, _emotion.jsx)(_uiA11yContent.PresentationContent, null, (0, _formatMessage["default"])('Generate')), (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage["default"])('Generate Solutions'))); } }, { key: "render", value: function render() { return (0, _emotion.jsx)("div", null, (0, _emotion.jsx)("div", { css: this.props.styles.sectionHeading }, (0, _emotion.jsx)(_uiText.Text, { size: "large" }, (0, _formatMessage["default"])('Formula Definition'))), (0, _emotion.jsx)("div", { css: this.props.styles.instructions }, (0, _emotion.jsx)(_uiText.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")'))), (0, _emotion.jsx)(_quizCommon.TextArea, { disabled: this.props.overrideEditableForRegrading, value: this.props.scoringData.value.formula, onChange: this.props.handleFormulaChange, messages: this.formulaErrors(), label: (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage["default"])('Formula')), autoGrow: this.context.disableTextAreaAutoGrow ? false : null, "data-automation": "sdk-formula-definition-text-area" }), (0, _emotion.jsx)("div", null, (0, _emotion.jsx)("div", { css: this.props.styles.sectionHeading }, (0, _emotion.jsx)(_uiText.Text, { size: "large" }, (0, _formatMessage["default"])('Generate Possible Solutions'))), (0, _emotion.jsx)("div", { css: this.props.styles.instructions }, (0, _emotion.jsx)(_uiText.Text, { color: "primary" }, (0, _formatMessage["default"])('Finally, build as many variable-solution combinations as you need for your quiz.'))), (0, _emotion.jsx)("div", { css: this.props.styles.generateSolutionsInput }, (0, _emotion.jsx)(_uiGrid.Grid, { vAlign: "top", startAt: "medium" }, (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, this.renderNumberOfGeneratedSolutionsInput()), (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, this.renderSolutionPrecisionInput()), (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, (0, _emotion.jsx)(_uiView.View, { as: "div", margin: "medium 0 0 0", padding: "xx-small 0 0 0" }, this.renderScientificNotationCheckbox()))), !this.props.scoringData.value.scientificNotation && (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, this.renderMarginOfErrorTypeSelect()), (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, this.renderMarginOfErrorInput())), (0, _emotion.jsx)(_uiGrid.Grid.Row, null, (0, _emotion.jsx)(_uiGrid.Grid.Col, { width: 4 }, this.renderGenerateSolutionsButton())))), this.renderGeneratedSolutionsSection())); } }]); }(_react.Component), (0, _defineProperty2["default"])(_FormulaSection, "displayName", 'FormulaSection'), (0, _defineProperty2["default"])(_FormulaSection, "componentId", "Quizzes".concat(_FormulaSection.displayName)), (0, _defineProperty2["default"])(_FormulaSection, "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, styles: _propTypes["default"].object }), (0, _defineProperty2["default"])(_FormulaSection, "defaultProps", { formulaErrors: void 0, generatedSolutionsErrors: void 0 }), (0, _defineProperty2["default"])(_FormulaSection, "contextTypes", { disableTextAreaAutoGrow: _propTypes["default"].bool }), _FormulaSection)) || _class);