@nualang/nualang-ui-components 0.1.1333 → 0.1.1335
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Chat/BottomBar/BottomBar.js +1 -2
- package/dist/Editors/Bot/Bot.js +12 -1
- package/dist/Editors/Roleplay/Roleplay.js +12 -1
- package/dist/Forms/AppContact/AppContact.js +1 -0
- package/dist/Navigation/ResponsiveTabs/ResponsiveTabs.js +0 -20
- package/dist/Screens/Courses/ViewCourse/ViewCourse.js +4 -3
- package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +4 -3
- package/dist/Tables/Progress/ProgressTable.js +95 -23
- package/dist/Tables/Progress/utils.js +66 -3
- package/package.json +1 -1
|
@@ -145,9 +145,8 @@ export default function BottomBar({
|
|
|
145
145
|
placeholder: browserSupportsSpeechRecognition && handleRecord ? isSmallScreen ? t("bot_input_mobile_placeholder") : t("bot_input_placeholder") : placeholder,
|
|
146
146
|
inputProps: {
|
|
147
147
|
maxLength: isChallengeBot ? 600 : 200,
|
|
148
|
-
sx:
|
|
148
|
+
sx: () => ({
|
|
149
149
|
"&::placeholder": {
|
|
150
|
-
color: theme.palette.mode === "light" ? grey[200] : grey[800],
|
|
151
150
|
opacity: 1
|
|
152
151
|
}
|
|
153
152
|
})
|
package/dist/Editors/Bot/Bot.js
CHANGED
|
@@ -729,7 +729,18 @@ function Bot({
|
|
|
729
729
|
return !hidden ? /*#__PURE__*/_jsx(Tab, {
|
|
730
730
|
id: keyId,
|
|
731
731
|
label: label,
|
|
732
|
-
disabled: disabled
|
|
732
|
+
disabled: disabled,
|
|
733
|
+
sx: {
|
|
734
|
+
color: "#fff !important",
|
|
735
|
+
"&.Mui-selected": {
|
|
736
|
+
color: "#fff !important"
|
|
737
|
+
},
|
|
738
|
+
"&:hover": {
|
|
739
|
+
...(theme.palette.mode === "light" && {
|
|
740
|
+
backgroundColor: "rgba(144, 238, 144, 0.20) !important"
|
|
741
|
+
})
|
|
742
|
+
}
|
|
743
|
+
}
|
|
733
744
|
}, keyId) : null;
|
|
734
745
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
735
746
|
title: hidden ? t("show_menu") : t("hide_menu"),
|
|
@@ -758,7 +758,18 @@ function Roleplay({
|
|
|
758
758
|
}, i) => !hidden ? /*#__PURE__*/_jsx(Tab, {
|
|
759
759
|
id: i,
|
|
760
760
|
label: label,
|
|
761
|
-
disabled: disabled
|
|
761
|
+
disabled: disabled,
|
|
762
|
+
sx: {
|
|
763
|
+
color: "#fff !important",
|
|
764
|
+
"&.Mui-selected": {
|
|
765
|
+
color: "#fff !important"
|
|
766
|
+
},
|
|
767
|
+
"&:hover": {
|
|
768
|
+
...(theme.palette.mode === "light" && {
|
|
769
|
+
backgroundColor: "rgba(144, 238, 144, 0.20) !important"
|
|
770
|
+
})
|
|
771
|
+
}
|
|
772
|
+
}
|
|
762
773
|
}, i) : null), /*#__PURE__*/_jsx(Tooltip, {
|
|
763
774
|
title: hidden ? t("show_menu") : t("hide_menu"),
|
|
764
775
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
@@ -97,26 +97,6 @@ function ResponsiveTabs({
|
|
|
97
97
|
sx: {
|
|
98
98
|
"@media print": {
|
|
99
99
|
display: "none"
|
|
100
|
-
},
|
|
101
|
-
"& .MuiTab-root": {
|
|
102
|
-
transition: theme.transitions.create(["background-color", "color"], {
|
|
103
|
-
duration: theme.transitions.duration.shorter
|
|
104
|
-
}),
|
|
105
|
-
"&:hover": {
|
|
106
|
-
backgroundColor: theme.palette.action.hover
|
|
107
|
-
},
|
|
108
|
-
"&.Mui-selected": {
|
|
109
|
-
color: theme.palette.primary.main,
|
|
110
|
-
"&:hover": {
|
|
111
|
-
backgroundColor: theme.palette.primary.light + "20"
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
"&.Mui-focusVisible": {
|
|
115
|
-
backgroundColor: theme.palette.action.focus
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
"& .MuiTabs-indicator": {
|
|
119
|
-
height: 3
|
|
120
100
|
}
|
|
121
101
|
},
|
|
122
102
|
children: tabs.map(({
|
|
@@ -1023,16 +1023,17 @@ export default function ViewCourse({
|
|
|
1023
1023
|
const {
|
|
1024
1024
|
classes
|
|
1025
1025
|
} = useStyles();
|
|
1026
|
+
const safeCourse = course || {};
|
|
1026
1027
|
return /*#__PURE__*/_jsxs("div", {
|
|
1027
1028
|
className: classes.root,
|
|
1028
|
-
children: [isLoading && Object.keys(
|
|
1029
|
+
children: [isLoading && Object.keys(safeCourse).length === 0 && /*#__PURE__*/_jsx(_Fragment, {
|
|
1029
1030
|
children: /*#__PURE__*/_jsx(Course, {
|
|
1030
1031
|
t: t,
|
|
1031
1032
|
isLoading: isLoading,
|
|
1032
1033
|
isStudent: isStudent,
|
|
1033
1034
|
...otherProps
|
|
1034
1035
|
})
|
|
1035
|
-
}), !isLoading && course && Object.keys(
|
|
1036
|
+
}), !isLoading && course && Object.keys(safeCourse).length && /*#__PURE__*/_jsx(_Fragment, {
|
|
1036
1037
|
children: /*#__PURE__*/_jsx(Course, {
|
|
1037
1038
|
t: t,
|
|
1038
1039
|
isLoading: isLoading,
|
|
@@ -1043,7 +1044,7 @@ export default function ViewCourse({
|
|
|
1043
1044
|
isStudent: isStudent,
|
|
1044
1045
|
...otherProps
|
|
1045
1046
|
})
|
|
1046
|
-
}), !isLoading && Object.keys(
|
|
1047
|
+
}), !isLoading && Object.keys(safeCourse).length === 0 && /*#__PURE__*/_jsx(CourseNotFound, {
|
|
1047
1048
|
t: t,
|
|
1048
1049
|
placeholderImageUrl: placeholderImageUrl,
|
|
1049
1050
|
handleSearch: handleSearch
|
|
@@ -1323,16 +1323,17 @@ export default function ViewTopic({
|
|
|
1323
1323
|
const {
|
|
1324
1324
|
classes
|
|
1325
1325
|
} = useStyles();
|
|
1326
|
+
const safeTopic = topic || {};
|
|
1326
1327
|
return /*#__PURE__*/_jsxs("div", {
|
|
1327
1328
|
className: classes.root,
|
|
1328
|
-
children: [isLoading && Object.keys(
|
|
1329
|
+
children: [isLoading && Object.keys(safeTopic).length === 0 && /*#__PURE__*/_jsx(_Fragment, {
|
|
1329
1330
|
children: /*#__PURE__*/_jsx(Topic, {
|
|
1330
1331
|
t: t,
|
|
1331
1332
|
isLoading: isLoading,
|
|
1332
1333
|
courseSettings: courseSettings,
|
|
1333
1334
|
...otherProps
|
|
1334
1335
|
})
|
|
1335
|
-
}), !isLoading && topic && Object.keys(
|
|
1336
|
+
}), !isLoading && topic && Object.keys(safeTopic).length && /*#__PURE__*/_jsx(_Fragment, {
|
|
1336
1337
|
children: /*#__PURE__*/_jsx(Topic, {
|
|
1337
1338
|
t: t,
|
|
1338
1339
|
isLoading: isLoading,
|
|
@@ -1358,7 +1359,7 @@ export default function ViewTopic({
|
|
|
1358
1359
|
isClassroomCreator: isClassroomCreator,
|
|
1359
1360
|
...otherProps
|
|
1360
1361
|
})
|
|
1361
|
-
}), !isLoading && Object.keys(
|
|
1362
|
+
}), !isLoading && Object.keys(safeTopic).length === 0 && /*#__PURE__*/_jsx(TopicNotFound, {
|
|
1362
1363
|
t: t,
|
|
1363
1364
|
isLoading: isLoading,
|
|
1364
1365
|
handleViewCourse: handleViewCourse
|
|
@@ -8,7 +8,7 @@ import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
|
|
|
8
8
|
import Avatar from "@mui/material/Avatar";
|
|
9
9
|
import Box from "@mui/material/Box";
|
|
10
10
|
import Typography from "@mui/material/Typography";
|
|
11
|
-
import { TableSortLabel, Chip } from "@mui/material";
|
|
11
|
+
import { TableSortLabel, Chip, Grid } from "@mui/material";
|
|
12
12
|
import IconButton from "@mui/material/IconButton";
|
|
13
13
|
import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
|
|
14
14
|
import { green, lightGreen, red, grey, deepOrange, orange, yellow } from "@mui/material/colors";
|
|
@@ -17,7 +17,7 @@ import DefaultButton from "../../Misc/DefaultColourButton/DefaultColourButton";
|
|
|
17
17
|
import { formatMemberCourseCompletions, formatMemberAssignmentCompletions } from "./utils";
|
|
18
18
|
import DoneIcon from "@mui/icons-material/Done";
|
|
19
19
|
import CloseIcon from "@mui/icons-material/Close";
|
|
20
|
-
import RemoveIcon from
|
|
20
|
+
import RemoveIcon from "@mui/icons-material/Remove";
|
|
21
21
|
import HtmlTooltipComponent from "../../Misc/HtmlTooltipComponent/HtmlTooltipComponent";
|
|
22
22
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
23
|
const {
|
|
@@ -123,7 +123,8 @@ function DataCell({
|
|
|
123
123
|
backgroundColor,
|
|
124
124
|
memberActivityLink,
|
|
125
125
|
type,
|
|
126
|
-
index
|
|
126
|
+
index,
|
|
127
|
+
submittedLate = false
|
|
127
128
|
}) {
|
|
128
129
|
const completedTotal = `${completed} of ${total}`;
|
|
129
130
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
@@ -147,7 +148,7 @@ function DataCell({
|
|
|
147
148
|
backgroundColor: backgroundColor || theme.palette.divider,
|
|
148
149
|
color: theme.palette.common.white
|
|
149
150
|
}),
|
|
150
|
-
children: /*#__PURE__*/
|
|
151
|
+
children: /*#__PURE__*/_jsxs(HtmlTooltip, {
|
|
151
152
|
tabIndex: `${index + 1}`,
|
|
152
153
|
open: tooltipOpen,
|
|
153
154
|
disableHoverListener: !type,
|
|
@@ -182,7 +183,7 @@ function DataCell({
|
|
|
182
183
|
})]
|
|
183
184
|
}),
|
|
184
185
|
enterDelay: 1000,
|
|
185
|
-
children: /*#__PURE__*/_jsx(Typography, {
|
|
186
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
186
187
|
variant: "subtitle1",
|
|
187
188
|
component: "div",
|
|
188
189
|
sx: theme => ({
|
|
@@ -192,21 +193,50 @@ function DataCell({
|
|
|
192
193
|
textDecoration: "none"
|
|
193
194
|
}),
|
|
194
195
|
children: data
|
|
195
|
-
})
|
|
196
|
+
}), submittedLate && /*#__PURE__*/_jsx(Chip, {
|
|
197
|
+
variant: "outlined",
|
|
198
|
+
sx: theme => ({
|
|
199
|
+
color: theme.palette.common.black,
|
|
200
|
+
fontWeight: "bold"
|
|
201
|
+
}),
|
|
202
|
+
size: "small",
|
|
203
|
+
label: t("late_submission")
|
|
204
|
+
})]
|
|
196
205
|
})
|
|
197
206
|
});
|
|
198
207
|
}
|
|
199
208
|
function ExerciseCell({
|
|
200
209
|
icon,
|
|
201
|
-
backgroundColor
|
|
210
|
+
backgroundColor,
|
|
211
|
+
submittedLate = false,
|
|
212
|
+
daysLate = null,
|
|
213
|
+
t
|
|
202
214
|
}) {
|
|
203
|
-
return /*#__PURE__*/
|
|
215
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
204
216
|
component: "td",
|
|
205
217
|
sx: theme => ({
|
|
206
218
|
backgroundColor: backgroundColor || theme.palette.divider,
|
|
207
219
|
color: theme.palette.common.black
|
|
208
220
|
}),
|
|
209
|
-
children:
|
|
221
|
+
children: [/*#__PURE__*/_jsx(Grid, {
|
|
222
|
+
container: true
|
|
223
|
+
}), /*#__PURE__*/_jsx(Grid, {
|
|
224
|
+
size: 12,
|
|
225
|
+
children: icon
|
|
226
|
+
}), submittedLate && /*#__PURE__*/_jsx(Grid, {
|
|
227
|
+
size: 12,
|
|
228
|
+
children: /*#__PURE__*/_jsx(Chip, {
|
|
229
|
+
variant: "outlined",
|
|
230
|
+
sx: theme => ({
|
|
231
|
+
color: theme.palette.common.black,
|
|
232
|
+
fontWeight: "bold"
|
|
233
|
+
}),
|
|
234
|
+
size: "small",
|
|
235
|
+
label: t("days_late", {
|
|
236
|
+
count: daysLate
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
})]
|
|
210
240
|
});
|
|
211
241
|
}
|
|
212
242
|
function DataCellContainer({
|
|
@@ -216,7 +246,9 @@ function DataCellContainer({
|
|
|
216
246
|
error,
|
|
217
247
|
data,
|
|
218
248
|
memberActivityLink,
|
|
219
|
-
index
|
|
249
|
+
index,
|
|
250
|
+
submittedLate = false,
|
|
251
|
+
daysLate = null
|
|
220
252
|
}) {
|
|
221
253
|
if (isLoading) {
|
|
222
254
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -245,7 +277,9 @@ function DataCellContainer({
|
|
|
245
277
|
total: data && data.total ? data.total : 0,
|
|
246
278
|
type: data && data.type ? data.type : "percent",
|
|
247
279
|
memberActivityLink: memberActivityLink,
|
|
248
|
-
index: index
|
|
280
|
+
index: index,
|
|
281
|
+
submittedLate: submittedLate,
|
|
282
|
+
daysLate: daysLate
|
|
249
283
|
});
|
|
250
284
|
} else if (data.percentage === -1 || data.total === 0 && data.type === "correct") {
|
|
251
285
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -256,7 +290,9 @@ function DataCellContainer({
|
|
|
256
290
|
total: 0,
|
|
257
291
|
type: data && data.type ? data.type : "percent",
|
|
258
292
|
memberActivityLink: memberActivityLink,
|
|
259
|
-
index: index
|
|
293
|
+
index: index,
|
|
294
|
+
submittedLate: submittedLate,
|
|
295
|
+
daysLate: daysLate
|
|
260
296
|
});
|
|
261
297
|
} else if (data.percentage >= 80) {
|
|
262
298
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -267,7 +303,9 @@ function DataCellContainer({
|
|
|
267
303
|
total: data.total,
|
|
268
304
|
type: data && data.type ? data.type : "percent",
|
|
269
305
|
memberActivityLink: memberActivityLink,
|
|
270
|
-
index: index
|
|
306
|
+
index: index,
|
|
307
|
+
submittedLate: submittedLate,
|
|
308
|
+
daysLate: daysLate
|
|
271
309
|
});
|
|
272
310
|
} else if (data.percentage >= 60) {
|
|
273
311
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -278,7 +316,9 @@ function DataCellContainer({
|
|
|
278
316
|
total: data.total,
|
|
279
317
|
type: data && data.type ? data.type : "percent",
|
|
280
318
|
memberActivityLink: memberActivityLink,
|
|
281
|
-
index: index
|
|
319
|
+
index: index,
|
|
320
|
+
submittedLate: submittedLate,
|
|
321
|
+
daysLate: daysLate
|
|
282
322
|
});
|
|
283
323
|
} else if (data.percentage >= 40) {
|
|
284
324
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -289,7 +329,9 @@ function DataCellContainer({
|
|
|
289
329
|
total: data.total,
|
|
290
330
|
type: data && data.type ? data.type : "percent",
|
|
291
331
|
memberActivityLink: memberActivityLink,
|
|
292
|
-
index: index
|
|
332
|
+
index: index,
|
|
333
|
+
submittedLate: submittedLate,
|
|
334
|
+
daysLate: daysLate
|
|
293
335
|
});
|
|
294
336
|
} else if (data.percentage >= 20) {
|
|
295
337
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -300,7 +342,9 @@ function DataCellContainer({
|
|
|
300
342
|
total: data.total,
|
|
301
343
|
type: data && data.type ? data.type : "percent",
|
|
302
344
|
memberActivityLink: memberActivityLink,
|
|
303
|
-
index: index
|
|
345
|
+
index: index,
|
|
346
|
+
submittedLate: submittedLate,
|
|
347
|
+
daysLate: daysLate
|
|
304
348
|
});
|
|
305
349
|
} else if (data.percentage >= 0) {
|
|
306
350
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -311,7 +355,9 @@ function DataCellContainer({
|
|
|
311
355
|
total: data.total,
|
|
312
356
|
type: data && data.type ? data.type : "percent",
|
|
313
357
|
memberActivityLink: memberActivityLink,
|
|
314
|
-
index: index
|
|
358
|
+
index: index,
|
|
359
|
+
submittedLate: submittedLate,
|
|
360
|
+
daysLate: daysLate
|
|
315
361
|
});
|
|
316
362
|
}
|
|
317
363
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
@@ -322,7 +368,9 @@ function DataCellContainer({
|
|
|
322
368
|
total: data.total,
|
|
323
369
|
type: data && data.type ? data.type : "percent",
|
|
324
370
|
memberActivityLink: memberActivityLink,
|
|
325
|
-
index: index
|
|
371
|
+
index: index,
|
|
372
|
+
submittedLate: submittedLate,
|
|
373
|
+
daysLate: daysLate
|
|
326
374
|
});
|
|
327
375
|
}
|
|
328
376
|
function AssignmentCellData({
|
|
@@ -336,6 +384,12 @@ function AssignmentCellData({
|
|
|
336
384
|
index
|
|
337
385
|
}) {
|
|
338
386
|
let cellData = null;
|
|
387
|
+
let submittedLate = false;
|
|
388
|
+
let daysLate = null;
|
|
389
|
+
if (data?.submittedLate.isLate === true) {
|
|
390
|
+
submittedLate = true;
|
|
391
|
+
daysLate = data.submittedLate.daysLate;
|
|
392
|
+
}
|
|
339
393
|
if (data) {
|
|
340
394
|
if (filter === "percentage_complete" && data.percentComplete) {
|
|
341
395
|
cellData = data.percentComplete;
|
|
@@ -355,7 +409,9 @@ function AssignmentCellData({
|
|
|
355
409
|
error: error,
|
|
356
410
|
memberActivityLink: memberActivityLink,
|
|
357
411
|
index: index,
|
|
358
|
-
isNotAssigned: isNotAssigned
|
|
412
|
+
isNotAssigned: isNotAssigned,
|
|
413
|
+
submittedLate: submittedLate,
|
|
414
|
+
daysLate: daysLate
|
|
359
415
|
});
|
|
360
416
|
}
|
|
361
417
|
function CourseCellData({
|
|
@@ -430,6 +486,12 @@ function TopicCellData({
|
|
|
430
486
|
index
|
|
431
487
|
}) {
|
|
432
488
|
let cellData = null;
|
|
489
|
+
let submittedLate = false;
|
|
490
|
+
let daysLate = null;
|
|
491
|
+
if (data?.submittedLate.isLate === true) {
|
|
492
|
+
submittedLate = true;
|
|
493
|
+
daysLate = data.submittedLate.daysLate;
|
|
494
|
+
}
|
|
433
495
|
if (data) {
|
|
434
496
|
if (filter === "percentage_complete" && data.percentComplete) {
|
|
435
497
|
cellData = data.percentComplete;
|
|
@@ -448,7 +510,9 @@ function TopicCellData({
|
|
|
448
510
|
isLoading: isLoading,
|
|
449
511
|
error: error,
|
|
450
512
|
memberActivityLink: memberActivityLink,
|
|
451
|
-
index: index
|
|
513
|
+
index: index,
|
|
514
|
+
submittedLate: submittedLate,
|
|
515
|
+
daysLate: daysLate
|
|
452
516
|
});
|
|
453
517
|
}
|
|
454
518
|
function ExerciseCellData({
|
|
@@ -471,6 +535,12 @@ function ExerciseCellData({
|
|
|
471
535
|
let type = null;
|
|
472
536
|
let color;
|
|
473
537
|
let memberActivityLink = null;
|
|
538
|
+
let submittedLate = false;
|
|
539
|
+
let daysLate = null;
|
|
540
|
+
if (data?.submittedLate.isLate === true) {
|
|
541
|
+
submittedLate = true;
|
|
542
|
+
daysLate = data.submittedLate.daysLate;
|
|
543
|
+
}
|
|
474
544
|
if (isLoading) {
|
|
475
545
|
return /*#__PURE__*/_jsx(DataCell, {
|
|
476
546
|
t: t,
|
|
@@ -544,7 +614,9 @@ function ExerciseCellData({
|
|
|
544
614
|
type: type,
|
|
545
615
|
backgroundColor: color ?? (type === "completed" ? green[400] : red[400]),
|
|
546
616
|
memberActivityLink: memberActivityLink,
|
|
547
|
-
index: index
|
|
617
|
+
index: index,
|
|
618
|
+
submittedLate: submittedLate,
|
|
619
|
+
daysLate: daysLate
|
|
548
620
|
});
|
|
549
621
|
}
|
|
550
622
|
function RoleplayCellData({
|
|
@@ -627,8 +699,8 @@ function TableRow({
|
|
|
627
699
|
error,
|
|
628
700
|
isLoading
|
|
629
701
|
} = memberCourseCompletionsQuery;
|
|
630
|
-
const tableData = useMemo(() => memberCourseCompletionsQuery.isSuccess && Array.isArray(memberCourseCompletionsQuery.data.Items) && memberCourseCompletionsQuery.data.Items.length ? formatMemberCourseCompletions(courses, memberCourseCompletionsQuery.data.Items, reportType === "assignments" && selectedAssignment ? selectedAssignment?.exercises : null, isChallengeModeStudent) : [], [memberCourseCompletionsQuery.data, memberCourseCompletionsQuery.isSuccess, reportType, selectedAssignment, isChallengeModeStudent]);
|
|
631
|
-
const assignmentsTableData = useMemo(() => memberCourseCompletionsQuery.isSuccess && Array.isArray(memberCourseCompletionsQuery.data.Items) && memberCourseCompletionsQuery.data.Items.length && assignments && assignments.length ? formatMemberAssignmentCompletions(assignments, courses, memberCourseCompletionsQuery.data.Items, isChallengeModeStudent) : [], [memberCourseCompletionsQuery.data, memberCourseCompletionsQuery.isSuccess, assignments, isChallengeModeStudent]);
|
|
702
|
+
const tableData = useMemo(() => memberCourseCompletionsQuery.isSuccess && Array.isArray(memberCourseCompletionsQuery.data.Items) && memberCourseCompletionsQuery.data.Items.length ? formatMemberCourseCompletions(courses, memberCourseCompletionsQuery.data.Items, reportType === "assignments" && selectedAssignment ? selectedAssignment?.exercises : null, isChallengeModeStudent, selectedAssignment, reportType) : [], [memberCourseCompletionsQuery.data, memberCourseCompletionsQuery.isSuccess, courses, reportType, selectedAssignment, isChallengeModeStudent]);
|
|
703
|
+
const assignmentsTableData = useMemo(() => memberCourseCompletionsQuery.isSuccess && Array.isArray(memberCourseCompletionsQuery.data.Items) && memberCourseCompletionsQuery.data.Items.length && assignments && assignments.length ? formatMemberAssignmentCompletions(assignments, courses, memberCourseCompletionsQuery.data.Items, isChallengeModeStudent) : [], [memberCourseCompletionsQuery.data, memberCourseCompletionsQuery.isSuccess, courses, assignments, isChallengeModeStudent]);
|
|
632
704
|
let memberActivityLink = `/classrooms/${classroomId}/activity/member/${member.memberId}`;
|
|
633
705
|
if (currentView === "course") {
|
|
634
706
|
memberActivityLink = `${memberActivityLink}/${selectedCourse.courseId}`;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { calcCompletions, calcPercentageCompletion, getScoreValues } from "../../utils";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
// Helper function to calculate how many days late a submission is
|
|
4
|
+
const calculateDaysLate = (submissionTimestamp, dueDateMs) => {
|
|
5
|
+
const daysDifference = (submissionTimestamp - dueDateMs) / (1000 * 60 * 60 * 24);
|
|
6
|
+
if (daysDifference <= 0) return 0; // Not actually late
|
|
7
|
+
return Math.max(1, Math.ceil(daysDifference)); // Round up, minimum 1 day
|
|
8
|
+
};
|
|
9
|
+
export const formatMemberCourseCompletions = (courses = [], completions = [], assignmentExercises, isChallengeModeStudent = false, selectedAssignment = null, reportType = "course") => {
|
|
10
|
+
const dueDateMs = selectedAssignment?.dueDate ? new Date(selectedAssignment.dueDate).getTime() : null;
|
|
3
11
|
const initialStatsObject = courses.reduce((obj, v) => {
|
|
4
12
|
const scoreValues = getScoreValues("course", v.courseId, completions);
|
|
5
13
|
obj[v.courseId] = {
|
|
@@ -60,11 +68,26 @@ export const formatMemberCourseCompletions = (courses = [], completions = [], as
|
|
|
60
68
|
return topicObj;
|
|
61
69
|
}, {});
|
|
62
70
|
const formattedTopics = sectionVal.topics.reduce((topicObj, topicVal) => {
|
|
71
|
+
const topicCompletions = completions.filter(completion => completion.topicId === topicVal.topicId);
|
|
63
72
|
topicObj[topicVal.topicId] = {
|
|
64
73
|
percentComplete: topicVal.completion,
|
|
65
74
|
percentCorrect: topicVal.percentCorrect,
|
|
66
75
|
avgPronunciationScore: topicVal.avgPronunciationScore,
|
|
67
|
-
completions:
|
|
76
|
+
completions: topicCompletions,
|
|
77
|
+
...(selectedAssignment && reportType === "assignments" && {
|
|
78
|
+
submittedLate: (() => {
|
|
79
|
+
if (!dueDateMs) return {
|
|
80
|
+
isLate: false
|
|
81
|
+
};
|
|
82
|
+
const earliestCompletion = topicCompletions.reduce((earliest, c) => !earliest || c.createdAt < earliest.createdAt ? c : earliest, null);
|
|
83
|
+
return earliestCompletion && earliestCompletion.createdAt > dueDateMs ? {
|
|
84
|
+
isLate: true,
|
|
85
|
+
daysLate: calculateDaysLate(earliestCompletion.createdAt, dueDateMs)
|
|
86
|
+
} : {
|
|
87
|
+
isLate: false
|
|
88
|
+
};
|
|
89
|
+
})()
|
|
90
|
+
})
|
|
68
91
|
};
|
|
69
92
|
return topicObj;
|
|
70
93
|
}, initialTopicsObject);
|
|
@@ -72,11 +95,38 @@ export const formatMemberCourseCompletions = (courses = [], completions = [], as
|
|
|
72
95
|
percentComplete: sectionVal.completion,
|
|
73
96
|
percentCorrect: sectionVal.percentCorrect,
|
|
74
97
|
avgPronunciationScore: sectionVal.avgPronunciationScore,
|
|
75
|
-
topics: formattedTopics
|
|
98
|
+
topics: formattedTopics,
|
|
99
|
+
...(selectedAssignment && reportType === "assignments" && {
|
|
100
|
+
submittedLate: (() => {
|
|
101
|
+
const lateTopics = Object.values(formattedTopics).filter(t => t.submittedLate?.isLate);
|
|
102
|
+
if (lateTopics.length === 0) return {
|
|
103
|
+
isLate: false
|
|
104
|
+
};
|
|
105
|
+
const maxDaysLate = Math.max(...lateTopics.map(topic => topic.submittedLate.daysLate));
|
|
106
|
+
return {
|
|
107
|
+
isLate: true,
|
|
108
|
+
daysLate: maxDaysLate
|
|
109
|
+
};
|
|
110
|
+
})()
|
|
111
|
+
})
|
|
76
112
|
};
|
|
77
113
|
return sectionObj;
|
|
78
114
|
}, initialSectionsObject);
|
|
79
115
|
previousValue[currentValue.courseId].sections = formattedSections;
|
|
116
|
+
if (selectedAssignment && reportType === "assignments") {
|
|
117
|
+
const lateSections = Object.values(formattedSections).filter(s => s.submittedLate?.isLate);
|
|
118
|
+
if (lateSections.length === 0) {
|
|
119
|
+
previousValue[currentValue.courseId].submittedLate = {
|
|
120
|
+
isLate: false
|
|
121
|
+
};
|
|
122
|
+
} else {
|
|
123
|
+
const maxDaysLate = Math.max(...lateSections.map(section => section.submittedLate.daysLate));
|
|
124
|
+
previousValue[currentValue.courseId].submittedLate = {
|
|
125
|
+
isLate: true,
|
|
126
|
+
daysLate: maxDaysLate
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
80
130
|
return previousValue;
|
|
81
131
|
}, initialStatsObject);
|
|
82
132
|
return stats;
|
|
@@ -106,8 +156,21 @@ export const formatMemberAssignmentCompletions = (assignments = [], courses = []
|
|
|
106
156
|
total: 0,
|
|
107
157
|
sum: 0,
|
|
108
158
|
percentage: 0
|
|
159
|
+
},
|
|
160
|
+
submittedLate: {
|
|
161
|
+
isLate: false
|
|
109
162
|
}
|
|
110
163
|
};
|
|
164
|
+
if (assignment.dueDate) {
|
|
165
|
+
const dueDateMs = new Date(assignment.dueDate).getTime();
|
|
166
|
+
const lateCompletion = assignmentCompletions.find(completion => completion.createdAt > dueDateMs);
|
|
167
|
+
if (lateCompletion) {
|
|
168
|
+
accumulator.submittedLate = {
|
|
169
|
+
isLate: true,
|
|
170
|
+
daysLate: calculateDaysLate(lateCompletion.createdAt, dueDateMs)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
111
174
|
Object.values(assignmentCourseCompletions).forEach(course => {
|
|
112
175
|
if (course?.percentComplete) {
|
|
113
176
|
accumulator.percentComplete.completed += course.percentComplete.completed || 0;
|