Skip to content

Commit e460db2

Browse files
authored
Course mastery status
2 parents fc07a74 + 9f963c6 commit e460db2

File tree

3 files changed

+149
-55
lines changed

3 files changed

+149
-55
lines changed

index.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ <h1>Virtual Checker</h1>
6565
</div>
6666
</div>
6767
<div id="checker">
68-
<button square data-toggle-segment-completion tooltip="Segment Completion"><i class="bi bi-info-square"></i><i
68+
<button square data-toggle-segment-completion tooltip="Course & Segment Completion"><i class="bi bi-info-square"></i><i
6969
class="bi bi-info-square-fill"></i></button>
7070
<button square data-toggle-layout tooltip="Switch Layout"><i class="bi bi-app"></i><i
7171
class="bi bi-layout-sidebar-reverse"></i></button>
@@ -107,7 +107,18 @@ <h3>Announcement</h3>
107107
</div>
108108
</div>
109109
</div>
110-
<h6 data-segment-due hidden></h6>
110+
<div id="segments-completed" class="input-group" hidden>
111+
<i class="incomplete bi bi-question-octagon"></i>
112+
<h3 class="incomplete">Course Not Completed</h3>
113+
<p class="incomplete">You have not answered all questions in all segments in this course.</p>
114+
<i class="complete bi bi-check2-all"></i>
115+
<h3 class="complete">Course Completed</h3>
116+
<p class="complete">You have answered all questions in all segments in this course.</p>
117+
<i class="bi bi-patch-check mastery"></i>
118+
<h3 class="mastery">Course Completed, Mastery Achieved</h3>
119+
<p class="mastery">You have answered all questions in all segments in this course correctly.</p>
120+
<ul></ul>
121+
</div>
111122
<div id="segment-completed" class="input-group" hidden>
112123
<i class="incomplete bi bi-question-octagon"></i>
113124
<h3 class="incomplete">Segment Not Completed</h3>
@@ -120,6 +131,7 @@ <h3 class="mastery">Segment Completed, Mastery Achieved</h3>
120131
<p class="mastery">You have answered all questions in this segment correctly.</p>
121132
<ul></ul>
122133
</div>
134+
<h6 data-segment-due hidden></h6>
123135
<h6 data-question-title hidden></h6>
124136
<div class="description minimal" data-question-description hidden></div>
125137
<div class="input-group hiddenOnLoad">

src/checker/checker.js

Lines changed: 111 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -631,21 +631,48 @@ try {
631631
questions.removeEventListener("change", updateQuestion);
632632
questions.addEventListener("change", updateQuestion);
633633
await updateQuestion();
634+
const count = 200;
635+
const textColor = getComputedStyle(document.body).getPropertyValue('--text-color').trim();
636+
var defaults = {
637+
origin: {
638+
y: 1
639+
},
640+
shapes: [
641+
confetti.shapeFromText({ text: '➕' }),
642+
confetti.shapeFromText({ text: '➖' }),
643+
confetti.shapeFromText({ text: '✖️' }),
644+
confetti.shapeFromText({ text: '➗' }),
645+
confetti.shapeFromText({ text: '0️⃣' }),
646+
confetti.shapeFromText({ text: '1️⃣' }),
647+
confetti.shapeFromText({ text: '2️⃣' }),
648+
confetti.shapeFromText({ text: '3️⃣' }),
649+
confetti.shapeFromText({ text: '4️⃣' }),
650+
confetti.shapeFromText({ text: '5️⃣' }),
651+
confetti.shapeFromText({ text: '6️⃣' }),
652+
confetti.shapeFromText({ text: '7️⃣' }),
653+
confetti.shapeFromText({ text: '8️⃣' }),
654+
confetti.shapeFromText({ text: '9️⃣' }),
655+
confetti.shapeFromText({ text: '🔢' }),
656+
confetti.shapeFromText({ text: '📐' }),
657+
confetti.shapeFromText({ text: '📏' }),
658+
confetti.shapeFromText({ text: '📊' }),
659+
confetti.shapeFromText({ text: '📈' }),
660+
confetti.shapeFromText({ text: '📉' }),
661+
confetti.shapeFromText({ text: '🔣' }),
662+
confetti.shapeFromText({ text: '✅' }),
663+
confetti.shapeFromText({ text: '☑️' }),
664+
confetti.shapeFromText({ text: '✔️' }),
665+
],
666+
};
634667
document.getElementById("segment-completed").setAttribute('hidden', '');
635668
document.getElementById("segment-completed").querySelector('ul').innerHTML = '';
636669
document.getElementById("segment-completed").classList.remove('incomplete');
637670
document.getElementById("segment-completed").classList.remove('complete');
638671
document.getElementById("segment-completed").classList.remove('mastery');
639672
if (questions.querySelectorAll('option').length > 0) {
640-
if (questionStatuses.every(question => question.status)) {
641-
document.getElementById("segment-completed").classList.add('complete');
642-
document.getElementById("segment-completed").removeAttribute('hidden');
643-
} else {
644-
document.getElementById("segment-completed").classList.add('incomplete');
645-
}
646673
questionStatuses.forEach(question => {
647674
const questionId = questionsArray.find(q => String(q.id) === String(question.question));
648-
const questionText = `${questionId.number} - ${question.nonscored ? 'Non-scored' : (question.status || 'Not Completed')}`;
675+
const questionText = `${JSON.parse(selectedSegment.question_ids).find(q => String(q.id) === String(question.question))?.name || questionId.number} - ${question.nonscored ? 'Non-scored' : (question.status || 'Not Completed')}`;
649676
const li = document.createElement('li');
650677
if (question.status === 'Correct') {
651678
li.innerHTML = `<i class="bi bi-check-lg"></i> ${questionText}`;
@@ -659,39 +686,7 @@ try {
659686
}
660687
if ((questions.querySelectorAll('option').length > 0) && questionStatuses.every(question => (question.status === 'Correct') || question.nonscored)) {
661688
document.getElementById("segment-completed").classList.add('mastery');
662-
const count = 200;
663-
const textColor = getComputedStyle(document.body).getPropertyValue('--text-color').trim();
664-
var defaults = {
665-
origin: {
666-
y: 1
667-
},
668-
shapes: [
669-
confetti.shapeFromText({ text: '➕' }),
670-
confetti.shapeFromText({ text: '➖' }),
671-
confetti.shapeFromText({ text: '✖️' }),
672-
confetti.shapeFromText({ text: '➗' }),
673-
confetti.shapeFromText({ text: '0️⃣' }),
674-
confetti.shapeFromText({ text: '1️⃣' }),
675-
confetti.shapeFromText({ text: '2️⃣' }),
676-
confetti.shapeFromText({ text: '3️⃣' }),
677-
confetti.shapeFromText({ text: '4️⃣' }),
678-
confetti.shapeFromText({ text: '5️⃣' }),
679-
confetti.shapeFromText({ text: '6️⃣' }),
680-
confetti.shapeFromText({ text: '7️⃣' }),
681-
confetti.shapeFromText({ text: '8️⃣' }),
682-
confetti.shapeFromText({ text: '9️⃣' }),
683-
confetti.shapeFromText({ text: '🔢' }),
684-
confetti.shapeFromText({ text: '📐' }),
685-
confetti.shapeFromText({ text: '📏' }),
686-
confetti.shapeFromText({ text: '📊' }),
687-
confetti.shapeFromText({ text: '📈' }),
688-
confetti.shapeFromText({ text: '📉' }),
689-
confetti.shapeFromText({ text: '🔣' }),
690-
confetti.shapeFromText({ text: '✅' }),
691-
confetti.shapeFromText({ text: '☑️' }),
692-
confetti.shapeFromText({ text: '✔️' }),
693-
],
694-
};
689+
document.getElementById("segment-completed").removeAttribute('hidden');
695690
uniqueSymbols.forEach(symbol => {
696691
defaults.shapes.push(confetti.shapeFromText({ text: symbol, color: textColor }));
697692
});
@@ -729,6 +724,76 @@ try {
729724
scalar: 1.5,
730725
});
731726
}, 100);
727+
} else if (questionStatuses.every(question => question.status)) {
728+
document.getElementById("segment-completed").classList.add('complete');
729+
document.getElementById("segment-completed").removeAttribute('hidden');
730+
} else {
731+
document.getElementById("segment-completed").classList.add('incomplete');
732+
}
733+
document.getElementById("segments-completed").setAttribute('hidden', '');
734+
document.getElementById("segments-completed").querySelector('ul').innerHTML = '';
735+
document.getElementById("segments-completed").classList.remove('incomplete');
736+
document.getElementById("segments-completed").classList.remove('complete');
737+
document.getElementById("segments-completed").classList.remove('mastery');
738+
if (segmentsArray && segmentsArray.length > 0) {
739+
var anyQuestionsInCourse = false;
740+
const masterySegments = [];
741+
const completedSegments = [];
742+
segmentsArray.forEach(segment => {
743+
const questionIds = JSON.parse(segment.question_ids || '[]');
744+
const segmentQuestions = questionIds.map(qi => questionsArray.find(q => String(q.id) === String(qi.id))).filter(q => q && !questionsArray.find(q2 => String(q2.stem) === String(q.id)));
745+
const totalQuestions = segmentQuestions.length;
746+
if (totalQuestions > 0) anyQuestionsInCourse = true;
747+
var correctCount = 0;
748+
var attemptedCount = 0;
749+
segmentQuestions.forEach(q => {
750+
const questionHistory = history.filter(r => String(r.segment) === String(segment.id) && String(r.question_id) === String(q.id));
751+
if (q.nonscored) {
752+
correctCount += 1;
753+
if (questionHistory.length > 0) attemptedCount += 1;
754+
} else {
755+
if (questionHistory.find(r => r.status === 'Correct')) {
756+
correctCount += 1;
757+
attemptedCount += 1;
758+
} else if (questionHistory.length > 0) {
759+
attemptedCount += 1;
760+
}
761+
}
762+
});
763+
if (totalQuestions > 0) {
764+
masterySegments.push(correctCount === totalQuestions);
765+
completedSegments.push(attemptedCount === totalQuestions);
766+
}
767+
console.log(segment, totalQuestions, correctCount, attemptedCount)
768+
var statusLabel = 'Not Started';
769+
var icon = '<i class="bi bi-hourglass"></i>';
770+
if (totalQuestions === 0) {
771+
statusLabel = 'No Questions';
772+
icon = '<i class="bi bi-dash-circle"></i>';
773+
} else if (correctCount === totalQuestions) {
774+
statusLabel = 'Mastery';
775+
icon = '<i class="bi bi-patch-check"></i>';
776+
} else if (attemptedCount === totalQuestions) {
777+
statusLabel = 'Completed';
778+
icon = '<i class="bi bi-check2-all"></i>';
779+
} else if (attemptedCount > 0) {
780+
statusLabel = 'In Progress';
781+
icon = '<i class="bi bi-hourglass-split"></i>';
782+
}
783+
const li = document.createElement('li');
784+
li.classList.add(statusLabel.replace(/\s+/g, '-').toLowerCase());
785+
li.innerHTML = `${icon} <b>${segment.number} - ${segment.name}:</b>&nbsp;${statusLabel}<span style="float: right; font-weight: 600;">${attemptedCount}/${totalQuestions} Answered • ${correctCount}/${totalQuestions} Correct (${(totalQuestions > 0) ? Math.round((correctCount / totalQuestions) * 100) : 0}%)</span>`;
786+
document.getElementById("segments-completed").querySelector('ul').append(li);
787+
});
788+
if (anyQuestionsInCourse && (masterySegments.length > 0) && masterySegments.every(Boolean)) {
789+
document.getElementById("segments-completed").classList.add('mastery');
790+
document.getElementById("segments-completed").removeAttribute('hidden');
791+
} else if (anyQuestionsInCourse && (completedSegments.length > 0) && completedSegments.every(Boolean)) {
792+
document.getElementById("segments-completed").classList.add('complete');
793+
document.getElementById("segments-completed").removeAttribute('hidden');
794+
} else {
795+
document.getElementById("segments-completed").classList.add('incomplete');
796+
}
732797
}
733798
ui.setUnsavedChanges(false);
734799
ui.reloadUnsavedInputs();
@@ -1070,7 +1135,7 @@ try {
10701135
if (r.flagged) button.classList.add('flagged');
10711136
var response = `<b>Status:</b> ${r.status.includes('Unknown') ? r.status.split('Unknown, ')[1] : r.status}${(r.reason) ? `</p>\n<p><b>Response:</b> ${r.reason}<br>` : ''}</p><button data-flag-response><i class="bi bi-flag-fill"></i> ${r.flagged ? 'Unflag Response' : 'Flag for Review'}</button>`;
10721137
var segmentNumber = segmentsArray.find(s => (String(s.id) === String(r.segment)) && (courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))) ? (String(s.course) === String(courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))).id)) : true)) ? (segmentsArray.find(s => (String(s.id) === String(r.segment)) && (courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))) ? (String(s.course) === String(courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))).id)) : true)).number || r.segment) : (segmentsArray.find(s => (courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))) ? (String(s.course) === String(courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1)))).id)) : false) && JSON.parse(s.question_ids || [])?.find(q => String(q.id) === String(r.question_id)))?.number || null);
1073-
var questionNumber = questionsArray.find(question => String(question.id) === String(r.question_id)).number;
1138+
var questionNumber = JSON.parse(segmentsArray.find(s => String(s.id) === String(r.segment))?.question_ids || '[]').find(q => String(q.id) === String(r.question_id))?.name || questionsArray.find(question => String(question.id) === String(r.question_id)).number;
10741139
switch (r.mode) {
10751140
case 'latex':
10761141
button.innerHTML = `${(String(r.seatCode) !== String(storage.get("code"))) ? `<p><b>${courses.find(c => JSON.parse(c.periods).includes(Number(String(r.seatCode).slice(0, 1))))?.name}</b></p>\n` : ''}<p><b>${segmentNumber ? `Segment ${segmentNumber}` : 'Deleted Segment'} Question #${questionNumber}.</b> ${unixToTimeString(r.timestamp)} (${r.seatCode})</p>\n${convertLatexToMarkup(r.response)}\n<p class="hint">(Equation may not display properly)</p>\n<p>${response}`;
@@ -1423,11 +1488,14 @@ try {
14231488
const checker = document.getElementById('checker');
14241489
if (!checker) return;
14251490
const segmentCompleted = document.getElementById('segment-completed');
1426-
if (!segmentCompleted) return;
1427-
if (segmentCompleted.hasAttribute('hidden')) {
1491+
const segmentsCompleted = document.getElementById('segments-completed');
1492+
if (!segmentCompleted || !segmentsCompleted) return;
1493+
if (segmentCompleted.hasAttribute('hidden') || segmentsCompleted.hasAttribute('hidden')) {
14281494
segmentCompleted.removeAttribute('hidden');
1495+
segmentsCompleted.removeAttribute('hidden');
14291496
} else {
14301497
segmentCompleted.setAttribute('hidden', '');
1498+
segmentsCompleted.setAttribute('hidden', '');
14311499
}
14321500
}
14331501

src/design.css

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,44 +1481,58 @@ hidden,
14811481
cursor: pointer;
14821482
}
14831483

1484-
#segment-completed {
1484+
#segment-completed,
1485+
#segments-completed {
14851486
background: var(--surface-color);
14861487
padding: 15px 20px 20px 20px;
14871488
border-radius: 10px;
14881489
border-left: 3px solid mediumseagreen;
14891490
border-right: 3px solid mediumseagreen;
1490-
margin-top: 10px;
14911491
}
14921492

1493-
#segment-completed i {
1493+
#segment-completed.incomplete,
1494+
#segments-completed.incomplete {
1495+
border-left: 3px solid indianred;
1496+
border-right: 3px solid indianred;
1497+
}
1498+
1499+
#segment-completed i,
1500+
#segments-completed i {
14941501
font-size: 25px;
14951502
}
14961503

1497-
#segment-completed ul i {
1504+
#segment-completed ul i,
1505+
#segments-completed ul i {
14981506
font-size: 15px;
14991507
}
15001508

1501-
#segment-completed:not(.incomplete) > *:not(ul).incomplete {
1509+
#segment-completed:not(.incomplete) > *:not(ul).incomplete,
1510+
#segments-completed:not(.incomplete) > *:not(ul).incomplete {
15021511
display: none;
15031512
}
15041513

1505-
#segment-completed.incomplete > *:not(ul):not(.incomplete) {
1514+
#segment-completed.incomplete > *:not(ul):not(.incomplete),
1515+
#segments-completed.incomplete > *:not(ul):not(.incomplete) {
15061516
display: none;
15071517
}
15081518

1509-
#segment-completed:not(.complete) > *:not(ul).complete {
1519+
#segment-completed:not(.complete) > *:not(ul).complete,
1520+
#segments-completed:not(.complete) > *:not(ul).complete {
15101521
display: none;
15111522
}
15121523

1513-
#segment-completed.complete > *:not(ul):not(.complete) {
1524+
#segment-completed.complete > *:not(ul):not(.complete),
1525+
#segments-completed.complete > *:not(ul):not(.complete) {
15141526
display: none;
15151527
}
15161528

1517-
#segment-completed:not(.mastery) > *:not(ul).mastery {
1529+
#segment-completed:not(.mastery) > *:not(ul).mastery,
1530+
#segments-completed:not(.mastery) > *:not(ul).mastery {
15181531
display: none;
15191532
}
15201533

1521-
#segment-completed.mastery > *:not(ul):not(.mastery) {
1534+
#segment-completed.mastery > *:not(ul):not(.mastery),
1535+
#segments-completed.mastery > *:not(ul):not(.mastery) {
15221536
display: none;
15231537
}
15241538

0 commit comments

Comments
 (0)