UNPKG

@instructure/quiz-taking

Version:

328 lines (324 loc) • 16.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.AttemptHistory = 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 _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 = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _gradingUtils = require("@instructure/grading-utils"); var _emotion = require("@instructure/emotion"); var _uiHeading = require("@instructure/ui-heading"); var _uiText = require("@instructure/ui-text"); var _uiLink = require("@instructure/ui-link"); var _uiA11yContent = require("@instructure/ui-a11y-content"); var _uiTable = require("@instructure/ui-table"); var _uiToggleDetails = require("@instructure/ui-toggle-details"); var _uiTooltip = require("@instructure/ui-tooltip"); var _uiFocusable = require("@instructure/ui-focusable"); var _uiView = require("@instructure/ui-view"); var _uiResponsive = require("@instructure/ui-responsive"); var _uiIcons = require("@instructure/ui-icons"); var _quizCore = require("@instructure/quiz-core"); var _styles = _interopRequireDefault(require("./styles")); var _theme = _interopRequireDefault(require("./theme")); var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message")); var _quizCommon = require("@instructure/quiz-common"); var _dec, _class, _AttemptHistory; /** @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 AttemptHistory = exports.AttemptHistory = (_dec = (0, _quizCommon.withStyleOverrides)(_styles["default"], _theme["default"]), _dec(_class = (_AttemptHistory = /*#__PURE__*/function (_withI18nSupport) { function AttemptHistory() { (0, _classCallCheck2["default"])(this, AttemptHistory); return _callSuper(this, AttemptHistory, arguments); } (0, _inherits2["default"])(AttemptHistory, _withI18nSupport); return (0, _createClass2["default"])(AttemptHistory, [{ key: "componentDidMount", value: // ============= // LIFECYCLE // ============= function componentDidMount() { if (this.props.attemptHistory) { this.fetchData(); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (this.props.attemptHistory && (!prevProps.attemptHistory || this.props.attemptHistory.some(function (attempt, index) { return attempt.quizSessionId !== prevProps.attemptHistory[index].quizSessionId; }))) { this.fetchData(); } } }, { key: "fetchData", value: function fetchData() { var _this$props = this.props, getQuizSessions = _this$props.getQuizSessions, quizId = _this$props.quizId, attemptHistory = _this$props.attemptHistory; var quizSessionIds = attemptHistory.map(function (attempt) { return attempt.quizSessionId; }).filter(Boolean); if (!quizSessionIds.length) return; getQuizSessions(quizId, { ids: quizSessionIds }); } }, { key: "scoreToKeepString", get: function get() { return { highest: (0, _formatMessage["default"])('Highest'), latest: (0, _formatMessage["default"])('Latest'), average: (0, _formatMessage["default"])('Average'), first: (0, _formatMessage["default"])('First') }[this.props.scoreToKeep]; } // ============= // Callbacks // ============= }, { key: "onAttemptClick", value: function onAttemptClick(quizSessionId) { var _this2 = this; return function () { _this2.props.onAttemptClick(quizSessionId); }; } // ============= // RENDERING // ============= }, { key: "renderAttemptLink", value: function renderAttemptLink(attempt, i) { var displayName = attempt.displayName, quizSessionId = attempt.quizSessionId; var attemptName = displayName || (0, _formatMessage["default"])('Attempt {n}', { n: i + 1 }); var fontStyles = this.props.selectedSessionId === quizSessionId ? this.props.styles.bold : this.props.styles.normal; if (this.props.onAttemptClick && quizSessionId) { return (0, _emotion.jsx)(_uiLink.Link, { onClick: this.onAttemptClick(quizSessionId) }, (0, _emotion.jsx)("span", { css: fontStyles }, attemptName)); } else { return attemptName; } } }, { key: "renderHiddenAttemptInfo", value: function renderHiddenAttemptInfo() { var _this3 = this; var text = (0, _formatMessage["default"])('Not displayed per instructor settings.'); return (0, _emotion.jsx)(_uiA11yContent.AccessibleContent, { alt: text }, (0, _emotion.jsx)(_uiTooltip.Tooltip, { renderTip: text, placement: "top", mountNode: this.getMountNode }, (0, _emotion.jsx)("span", null, (0, _emotion.jsx)(_uiFocusable.Focusable, null, function (_ref) { var focusVisible = _ref.focusVisible; return (0, _emotion.jsx)(_uiView.View, { as: "div", withFocusOutline: focusVisible }, (0, _emotion.jsx)("span", { css: _this3.props.styles.hiddenIcon, tabIndex: "0" }, (0, _emotion.jsx)(_uiIcons.IconOffLine, { size: "x-small" }))); })))); } }, { key: "getMountNode", value: function getMountNode() { return document.getElementById('main'); } }, { key: "renderAttemptHistory", value: function renderAttemptHistory() { var _this4 = this; return this.props.attemptHistory.map(function (attempt, i) { var points = null; var score = null; var letterGrade = null; if (attempt.score != null) { if (attempt.pointsPossible) { points = (0, _formatMessage["default"])('{score, number} of {total, number}', { score: attempt.score, total: attempt.pointsPossible }); if (attempt.percentage == null) { score = _this4.formatPercentMax2FractionDigits(attempt.score / attempt.pointsPossible); if (_this4.props.restrictQuantitativeData) { letterGrade = (0, _gradingUtils.scoreToLetterGrade)(attempt.score / attempt.pointsPossible * 100, _this4.props.gradingScheme); } } } else { points = _formatMessage["default"].number(attempt.score); } } if (attempt.percentage != null) { score = _this4.formatPercentMax2FractionDigits(attempt.percentage); if (_this4.props.restrictQuantitativeData) { letterGrade = (0, _gradingUtils.scoreToLetterGrade)(attempt.percentage * 100, _this4.props.gradingScheme); } } var fontStyles = _this4.props.selectedSessionId === attempt.quizSessionId ? _this4.props.styles.bold : _this4.props.styles.normal; return (0, _emotion.jsx)(_uiTable.Table.Row, { key: JSON.stringify(attempt) }, (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: fontStyles }, _this4.renderAttemptLink(attempt, i))), !_this4.props.restrictQuantitativeData && (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: fontStyles }, points || _this4.renderHiddenAttemptInfo())), !_this4.props.restrictQuantitativeData && (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: fontStyles }, score || _this4.renderHiddenAttemptInfo())), _this4.props.restrictQuantitativeData && (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: fontStyles }, letterGrade || _this4.renderHiddenAttemptInfo())), (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: fontStyles }, _this4.renderScoreBody(attempt)))); }); } }, { key: "renderScoreBody", value: function renderScoreBody(attempt) { if (typeof attempt.score != 'undefined' && attempt.authoritative && this.props.scoreToKeep !== 'average') { return (0, _formatMessage["default"])('({scoreType} score)', { scoreType: this.scoreToKeepString }); } } }, { key: "renderAverageScore", value: function renderAverageScore() { var averageScore = this.props.averageScore; if (averageScore == null) return null; var average = this.props.restrictQuantitativeData ? (0, _gradingUtils.scoreToLetterGrade)(averageScore * 100, this.props.gradingScheme) : this.formatPercentMax2FractionDigits(averageScore); return (0, _emotion.jsx)(_uiTable.Table.Row, null, (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: this.props.styles.bold }, (0, _formatMessage["default"])('Average Score'))), !this.props.restrictQuantitativeData && (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: this.props.styles.bold }, '--' /* eslint-disable-line react/jsx-no-literals */)), (0, _emotion.jsx)(_uiTable.Table.Cell, null, (0, _emotion.jsx)("span", { css: this.props.styles.bold }, average)), (0, _emotion.jsx)(_uiTable.Table.Cell, null)); } }, { key: "renderTable", value: function renderTable() { var _this5 = this; return (0, _emotion.jsx)("div", { css: this.props.styles.sectionWrapper }, (0, _emotion.jsx)(_uiToggleDetails.ToggleDetails, { defaultExpanded: true, summary: (0, _emotion.jsx)(_uiHeading.Heading, { level: "h2", color: "primary" }, (0, _formatMessage["default"])('Attempt History')) }, (0, _emotion.jsx)(_uiResponsive.Responsive, { query: { small: { maxWidth: '20rem' }, large: { minWidth: '21rem' } }, props: { small: { layout: 'stacked' }, large: { layout: 'auto' } } }, function (props) { return ( // Column header fallbacks are React Fragments because InstUI doesn't filter out falsy // values from the list of Children and the app crashes // Related ticket: https://instructure.atlassian.net/browse/INSTUI-4534 (0, _emotion.jsx)(_uiTable.Table, Object.assign({ caption: (0, _formatMessage["default"])('Attempt History') }, props), (0, _emotion.jsx)(_uiTable.Table.Head, null, (0, _emotion.jsx)(_uiTable.Table.Row, null, (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "attempt-history-results" }, (0, _formatMessage["default"])('Results')), !_this5.props.restrictQuantitativeData ? (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "attempt-history-points" }, (0, _formatMessage["default"])('Points')) : (0, _emotion.jsx)(_react["default"].Fragment, null), !_this5.props.restrictQuantitativeData ? (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "attempt-history-score" }, (0, _formatMessage["default"])('Score')) : (0, _emotion.jsx)(_react["default"].Fragment, null), _this5.props.restrictQuantitativeData ? (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "attempt-history-grade" }, (0, _formatMessage["default"])('Grade')) : (0, _emotion.jsx)(_react["default"].Fragment, null), (0, _emotion.jsx)(_uiTable.Table.ColHeader, { id: "attempt-history-score-to-keep" }, (0, _formatMessage["default"])('({scoreToKeep} score is kept)', { scoreToKeep: _this5.scoreToKeepString })))), (0, _emotion.jsx)(_uiTable.Table.Body, null, _this5.renderAttemptHistory(), _this5.renderAverageScore())) ); }))); } }, { key: "render", value: function render() { var attemptHistory = this.props.attemptHistory; if (!attemptHistory) return null; if (attemptHistory.length > 0) { return this.renderTable(); } else { return (0, _emotion.jsx)("div", { css: this.props.styles.page }, (0, _emotion.jsx)("span", { css: this.props.styles.emptyText }, (0, _emotion.jsx)(_uiText.Text, { color: "primary" }, (0, _formatMessage["default"])('No attempt information to display yet.')))); } } }]); }((0, _quizCommon.withI18nSupport)(_react.Component)), (0, _defineProperty2["default"])(_AttemptHistory, "displayName", 'AttemptHistory'), (0, _defineProperty2["default"])(_AttemptHistory, "componentId", "Quizzes".concat(_AttemptHistory.displayName)), (0, _defineProperty2["default"])(_AttemptHistory, "propTypes", { attemptHistory: _quizCore.CustomPropTypes.attemptHistory, averageScore: _quizCore.CustomPropTypes.numberInRange(0, 1), getQuizSessions: _propTypes["default"].func.isRequired, gradingScheme: _propTypes["default"].arrayOf(_propTypes["default"].shape({ name: _propTypes["default"].string, value: _propTypes["default"].number })), onAttemptClick: _propTypes["default"].func, quizId: _quizCore.CustomPropTypes.recordId, restrictQuantitativeData: _propTypes["default"].bool, scoreToKeep: _propTypes["default"].oneOf(['highest', 'latest', 'average', 'first']).isRequired, selectedSessionId: _propTypes["default"].string.isRequired, /* eslint-disable-next-line react/forbid-prop-types */ styles: _propTypes["default"].object }), (0, _defineProperty2["default"])(_AttemptHistory, "defaultProps", { attemptHistory: null, gradingScheme: [], onAttemptClick: function onAttemptClick() {}, restrictQuantitativeData: false }), _AttemptHistory)) || _class); var _default = exports["default"] = AttemptHistory;