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.
This commit is contained in:
Andrew Shultz
2022-11-03 09:26:42 -04:00
committed by Adolfo R. Brandes
parent 108fb314f5
commit a701ea5e15
3 changed files with 70 additions and 12 deletions

View File

@@ -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();
});

View File

@@ -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. ',

View File

@@ -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 isExpiringSoon(dateString) {
// Returns true if the expiration date is within 28 days
function isExpired(dateString) {
// Returns true if the expiration date has passed
const today = new Date();
const expirationDateObject = new Date(dateString);
return today > expirationDateObject.getTime() - 2419200000;
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() - 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) && (
<>
<p>
{isNotYetSubmitted(status) && (
{!isCurrentlySubmitted(status) && (
intl.formatMessage(messages.proctoringPanelGeneralInfo)
)}
{!isNotYetSubmitted(status) && (
{isCurrentlySubmitted(status) && (
intl.formatMessage(messages.proctoringPanelGeneralInfoSubmitted)
)}
</p>
<p>{intl.formatMessage(messages.proctoringPanelGeneralTime)}</p>
</>
)}
{isNotYetSubmitted(status) && (
{isSubmissionRequired(readableStatus) && (
onboardingExamButton
)}
<Button variant="outline-primary" block href="https://support.edx.org/hc/en-us/sections/115004169247-Taking-Timed-and-Proctored-Exams">