From 19d06d60be661c268da0721d2c4075ab8068895c Mon Sep 17 00:00:00 2001 From: Andrew Shultz Date: Thu, 3 Nov 2022 09:26:42 -0400 Subject: [PATCH] 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. --- .../outline-tab/OutlineTab.test.jsx | 34 ++++++++++++++++++- src/course-home/outline-tab/messages.js | 12 ++++++- .../widgets/ProctoringInfoPanel.jsx | 32 ++++++++++++----- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/course-home/outline-tab/OutlineTab.test.jsx b/src/course-home/outline-tab/OutlineTab.test.jsx index 41335e33c2..c9e8aa6876 100644 --- a/src/course-home/outline-tab/OutlineTab.test.jsx +++ b/src/course-home/outline-tab/OutlineTab.test.jsx @@ -1017,6 +1017,22 @@ describe('Outline Tab', () => { }); it('displays expiration warning', async () => { + const expirationDate = new Date(); + // This message will render if the expiration date is within 28 days; set the date 10 days in future + expirationDate.setTime(expirationDate.getTime() + 864800000); + axiosMock.onGet(proctoringInfoUrl).reply(200, { + onboarding_status: 'verified', + onboarding_link: 'test', + expiration_date: expirationDate.toString(), + onboarding_release_date: onboardingReleaseDate.toISOString(), + }); + await fetchAndRender(); + await screen.findByText('This course contains proctored exams'); + 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(); + expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument(); + }); + + it('displays expiration warning for other course', async () => { const expirationDate = new Date(); // This message will render if the expiration date is within 28 days; set the date 10 days in future expirationDate.setTime(expirationDate.getTime() + 864800000); @@ -1028,7 +1044,23 @@ describe('Outline Tab', () => { }); await fetchAndRender(); await screen.findByText('This course contains proctored exams'); - 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(); + 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(); + expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument(); + }); + + it('displays expired', async () => { + const expirationDate = new Date(); + // This message appears after expiration, set the date 10 days in the past + expirationDate.setTime(expirationDate.getTime() - 864800000); + axiosMock.onGet(proctoringInfoUrl).reply(200, { + onboarding_status: 'verified', + onboarding_link: 'test', + expiration_date: expirationDate.toString(), + onboarding_release_date: onboardingReleaseDate.toISOString(), + }); + await fetchAndRender(); + await screen.findByText('This course contains proctored exams'); + expect(screen.queryByText('Your onboarding status has expired. Please complete onboarding again to continue taking proctored exams.')).toBeInTheDocument(); expect(screen.queryByText('Onboarding profile review can take 2+ business days.')).toBeInTheDocument(); }); diff --git a/src/course-home/outline-tab/messages.js b/src/course-home/outline-tab/messages.js index 48c56a1310..8d3204594f 100644 --- a/src/course-home/outline-tab/messages.js +++ b/src/course-home/outline-tab/messages.js @@ -231,6 +231,11 @@ const messages = defineMessages({ defaultMessage: 'Expiring Soon', description: 'A label to indicate that proctortrack onboarding exam will expire soon', }, + expiredProctoringStatus: { + id: 'learning.proctoringPanel.status.expired', + defaultMessage: 'Expired', + description: 'A label to indicate that proctortrack onboarding exam has expired', + }, proctoringCurrentStatus: { id: 'learning.proctoringPanel.status', defaultMessage: 'Current Onboarding Status:', @@ -278,9 +283,14 @@ const messages = defineMessages({ }, expiringSoonProctoringMessage: { id: 'learning.proctoringPanel.message.expiringSoon', - 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.', + 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.', description: 'The text that recommend an action when the status of the proctortrack onboarding exam is (expiring soon)', }, + expiredProctoringMessage: { + id: 'learning.proctoringPanel.message.expired', + defaultMessage: 'Your onboarding status has expired. Please complete onboarding again to continue taking proctored exams.', + description: 'The text that recommend an action when the status of the proctortrack onboarding exam is (expired)', + }, proctoringPanelGeneralInfo: { id: 'learning.proctoringPanel.generalInfo', defaultMessage: 'You must complete the onboarding process prior to taking any proctored exam. ', diff --git a/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx b/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx index 0ee5d70e46..37d90bfe07 100644 --- a/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx +++ b/src/course-home/outline-tab/widgets/ProctoringInfoPanel.jsx @@ -35,6 +35,7 @@ function ProctoringInfoPanel({ intl }) { error: 'error', otherCourseApproved: 'otherCourseApproved', expiringSoon: 'expiringSoon', + expired: 'expired', }; function getReadableStatusClass(examStatus) { @@ -54,9 +55,14 @@ function ProctoringInfoPanel({ intl }) { return readableClass; } - function isNotYetSubmitted(examStatus) { - const NO_SHOW_STATES = ['submitted', 'second_review_required', 'verified']; - return !NO_SHOW_STATES.includes(examStatus); + function isCurrentlySubmitted(examStatus) { + const SUBMITTED_STATES = ['submitted', 'second_review_required']; + return SUBMITTED_STATES.includes(examStatus); + } + + function isSubmissionRequired(examStatus) { + const OK_STATES = [readableStatuses.submitted, readableStatuses.verified]; + return !OK_STATES.includes(examStatus); } function isNotYetReleased(examReleaseDate) { @@ -77,11 +83,19 @@ function ProctoringInfoPanel({ intl }) { return borderClass; } + function isExpired(dateString) { + // Returns true if the expiration date has passed + const today = new Date(); + const expirationDateObject = new Date(dateString); + return today >= expirationDateObject.getTime(); + } + function isExpiringSoon(dateString) { // Returns true if the expiration date is within 28 days + const twentyeightDays = 28 * 24 * 60 * 60 * 1000; const today = new Date(); const expirationDateObject = new Date(dateString); - return today > expirationDateObject.getTime() - 2419200000; + return today > expirationDateObject.getTime() - twentyeightDays; } useEffect(() => { @@ -96,7 +110,9 @@ function ProctoringInfoPanel({ intl }) { setStatus(response.onboarding_status); setLink(response.onboarding_link); const expirationDate = response.expiration_date; - if (expirationDate && isExpiringSoon(expirationDate)) { + if (expirationDate && isExpired(expirationDate)) { + setReadableStatus(getReadableStatusClass('expired')); + } else if (expirationDate && isExpiringSoon(expirationDate)) { setReadableStatus(getReadableStatusClass('expiringSoon')); } else { setReadableStatus(getReadableStatusClass(response.onboarding_status)); @@ -175,17 +191,17 @@ function ProctoringInfoPanel({ intl }) { {![readableStatuses.verified, readableStatuses.otherCourseApproved].includes(readableStatus) && ( <>

- {isNotYetSubmitted(status) && ( + {!isCurrentlySubmitted(status) && ( intl.formatMessage(messages.proctoringPanelGeneralInfo) )} - {!isNotYetSubmitted(status) && ( + {isCurrentlySubmitted(status) && ( intl.formatMessage(messages.proctoringPanelGeneralInfoSubmitted) )}

{intl.formatMessage(messages.proctoringPanelGeneralTime)}

)} - {isNotYetSubmitted(status) && ( + {isSubmissionRequired(readableStatus) && ( onboardingExamButton )}