@instructure/quiz-taking
Version:
328 lines (324 loc) • 16.1 kB
JavaScript
"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;