Skip to content

Commit 19d06d6

Browse files
authored
fix: display onboarding expired after expiration (#997)
Currently expiring soon is displayed 28 days before expiration and forever afterwards. Adds an actual expired state for after. Also clarifies the expring soon message which assumed other course, that was not necessarily true. Also updates the take action lines when you do not have valid onboarding to make sure they appear for everything not currently valid or in process, and updates the submitted process lines to not appear for expired statuses.
1 parent df91fef commit 19d06d6

3 files changed

Lines changed: 68 additions & 10 deletions

File tree

src/course-home/outline-tab/OutlineTab.test.jsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,22 @@ describe('Outline Tab', () => {
10171017
});
10181018

10191019
it('displays expiration warning', async () => {
1020+
const expirationDate = new Date();
1021+
// This message will render if the expiration date is within 28 days; set the date 10 days in future
1022+
expirationDate.setTime(expirationDate.getTime() + 864800000);
1023+
axiosMock.onGet(proctoringInfoUrl).reply(200, {
1024+
onboarding_status: 'verified',
1025+
onboarding_link: 'test',
1026+
expiration_date: expirationDate.toString(),
1027+
onboarding_release_date: onboardingReleaseDate.toISOString(),
1028+
});
1029+
await fetchAndRender();
1030+
await screen.findByText('This course contains proctored exams');
1031+
expect(screen.queryByText('Your onboarding profile has been approved. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.')).toBeInTheDocument();
1032+
expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument();
1033+
});
1034+
1035+
it('displays expiration warning for other course', async () => {
10201036
const expirationDate = new Date();
10211037
// This message will render if the expiration date is within 28 days; set the date 10 days in future
10221038
expirationDate.setTime(expirationDate.getTime() + 864800000);
@@ -1028,7 +1044,23 @@ describe('Outline Tab', () => {
10281044
});
10291045
await fetchAndRender();
10301046
await screen.findByText('This course contains proctored exams');
1031-
expect(screen.queryByText('Your onboarding profile has been approved in another course. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.')).toBeInTheDocument();
1047+
expect(screen.queryByText('Your onboarding profile has been approved. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.')).toBeInTheDocument();
1048+
expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument();
1049+
});
1050+
1051+
it('displays expired', async () => {
1052+
const expirationDate = new Date();
1053+
// This message appears after expiration, set the date 10 days in the past
1054+
expirationDate.setTime(expirationDate.getTime() - 864800000);
1055+
axiosMock.onGet(proctoringInfoUrl).reply(200, {
1056+
onboarding_status: 'verified',
1057+
onboarding_link: 'test',
1058+
expiration_date: expirationDate.toString(),
1059+
onboarding_release_date: onboardingReleaseDate.toISOString(),
1060+
});
1061+
await fetchAndRender();
1062+
await screen.findByText('This course contains proctored exams');
1063+
expect(screen.queryByText('Your onboarding status has expired. Please complete onboarding again to continue taking proctored exams.')).toBeInTheDocument();
10321064
expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument();
10331065
});
10341066

src/course-home/outline-tab/messages.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ const messages = defineMessages({
231231
defaultMessage: 'Expiring Soon',
232232
description: 'A label to indicate that proctortrack onboarding exam will expire soon',
233233
},
234+
expiredProctoringStatus: {
235+
id: 'learning.proctoringPanel.status.expired',
236+
defaultMessage: 'Expired',
237+
description: 'A label to indicate that proctortrack onboarding exam has expired',
238+
},
234239
proctoringCurrentStatus: {
235240
id: 'learning.proctoringPanel.status',
236241
defaultMessage: 'Current Onboarding Status:',
@@ -278,9 +283,14 @@ const messages = defineMessages({
278283
},
279284
expiringSoonProctoringMessage: {
280285
id: 'learning.proctoringPanel.message.expiringSoon',
281-
defaultMessage: 'Your onboarding profile has been approved in another course. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.',
286+
defaultMessage: 'Your onboarding profile has been approved. However, your onboarding status is expiring soon. Please complete onboarding again to ensure that you will be able to continue taking proctored exams.',
282287
description: 'The text that recommend an action when the status of the proctortrack onboarding exam is (expiring soon)',
283288
},
289+
expiredProctoringMessage: {
290+
id: 'learning.proctoringPanel.message.expired',
291+
defaultMessage: 'Your onboarding status has expired. Please complete onboarding again to continue taking proctored exams.',
292+
description: 'The text that recommend an action when the status of the proctortrack onboarding exam is (expired)',
293+
},
284294
proctoringPanelGeneralInfo: {
285295
id: 'learning.proctoringPanel.generalInfo',
286296
defaultMessage: 'You must complete the onboarding process prior to taking any proctored exam. ',

src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function ProctoringInfoPanel({ intl }) {
3535
error: 'error',
3636
otherCourseApproved: 'otherCourseApproved',
3737
expiringSoon: 'expiringSoon',
38+
expired: 'expired',
3839
};
3940

4041
function getReadableStatusClass(examStatus) {
@@ -54,9 +55,14 @@ function ProctoringInfoPanel({ intl }) {
5455
return readableClass;
5556
}
5657

57-
function isNotYetSubmitted(examStatus) {
58-
const NO_SHOW_STATES = ['submitted', 'second_review_required', 'verified'];
59-
return !NO_SHOW_STATES.includes(examStatus);
58+
function isCurrentlySubmitted(examStatus) {
59+
const SUBMITTED_STATES = ['submitted', 'second_review_required'];
60+
return SUBMITTED_STATES.includes(examStatus);
61+
}
62+
63+
function isSubmissionRequired(examStatus) {
64+
const OK_STATES = [readableStatuses.submitted, readableStatuses.verified];
65+
return !OK_STATES.includes(examStatus);
6066
}
6167

6268
function isNotYetReleased(examReleaseDate) {
@@ -77,11 +83,19 @@ function ProctoringInfoPanel({ intl }) {
7783
return borderClass;
7884
}
7985

86+
function isExpired(dateString) {
87+
// Returns true if the expiration date has passed
88+
const today = new Date();
89+
const expirationDateObject = new Date(dateString);
90+
return today >= expirationDateObject.getTime();
91+
}
92+
8093
function isExpiringSoon(dateString) {
8194
// Returns true if the expiration date is within 28 days
95+
const twentyeightDays = 28 * 24 * 60 * 60 * 1000;
8296
const today = new Date();
8397
const expirationDateObject = new Date(dateString);
84-
return today > expirationDateObject.getTime() - 2419200000;
98+
return today > expirationDateObject.getTime() - twentyeightDays;
8599
}
86100

87101
useEffect(() => {
@@ -96,7 +110,9 @@ function ProctoringInfoPanel({ intl }) {
96110
setStatus(response.onboarding_status);
97111
setLink(response.onboarding_link);
98112
const expirationDate = response.expiration_date;
99-
if (expirationDate && isExpiringSoon(expirationDate)) {
113+
if (expirationDate && isExpired(expirationDate)) {
114+
setReadableStatus(getReadableStatusClass('expired'));
115+
} else if (expirationDate && isExpiringSoon(expirationDate)) {
100116
setReadableStatus(getReadableStatusClass('expiringSoon'));
101117
} else {
102118
setReadableStatus(getReadableStatusClass(response.onboarding_status));
@@ -175,17 +191,17 @@ function ProctoringInfoPanel({ intl }) {
175191
{![readableStatuses.verified, readableStatuses.otherCourseApproved].includes(readableStatus) && (
176192
<>
177193
<p>
178-
{isNotYetSubmitted(status) && (
194+
{!isCurrentlySubmitted(status) && (
179195
intl.formatMessage(messages.proctoringPanelGeneralInfo)
180196
)}
181-
{!isNotYetSubmitted(status) && (
197+
{isCurrentlySubmitted(status) && (
182198
intl.formatMessage(messages.proctoringPanelGeneralInfoSubmitted)
183199
)}
184200
</p>
185201
<p>{intl.formatMessage(messages.proctoringPanelGeneralTime)}</p>
186202
</>
187203
)}
188-
{isNotYetSubmitted(status) && (
204+
{isSubmissionRequired(readableStatus) && (
189205
onboardingExamButton
190206
)}
191207
<Button variant="outline-primary" block href="https://support.edx.org/hc/en-us/sections/115004169247-Taking-Timed-and-Proctored-Exams">

0 commit comments

Comments
 (0)