Skip to content

Commit

Permalink
feat: update gating for chat component (#1550)
Browse files Browse the repository at this point in the history
* feat: update gating for chat component

* fix: add gating for access expiration

* chore: upgrade learning assistant version
  • Loading branch information
alangsto authored Dec 9, 2024
1 parent cd56ffa commit dafdcad
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 10 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/browserslist-config": "1.2.0",
"@edx/frontend-component-header": "^5.8.0",
"@edx/frontend-lib-learning-assistant": "^2.6.0",
"@edx/frontend-lib-learning-assistant": "^2.9.0",
"@edx/frontend-lib-special-exams": "^3.1.3",
"@edx/frontend-platform": "^8.0.0",
"@edx/openedx-atlas": "^0.6.0",
Expand Down
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export const VERIFIED_MODES = [
'paid-bootcamp',
] as const satisfies readonly string[];

export const AUDIT_MODES = [
'audit',
'honor',
'unpaid-executive-education',
'unpaid-bootcamp',
] as const satisfies readonly string[];

export const WIDGETS = {
DISCUSSIONS: 'DISCUSSIONS',
NOTIFICATIONS: 'NOTIFICATIONS',
Expand Down
35 changes: 30 additions & 5 deletions src/courseware/course/chat/Chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { Xpert } from '@edx/frontend-lib-learning-assistant';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl } from '@edx/frontend-platform/i18n';

import { VERIFIED_MODES } from '@src/constants';
import { AUDIT_MODES, VERIFIED_MODES } from '@src/constants';
import { useModel } from '../../../generic/model-store';

const Chat = ({
Expand All @@ -21,40 +22,64 @@ const Chat = ({
} = useSelector(state => state.specialExams);
const course = useModel('coursewareMeta', courseId);

const {
accessExpiration,
start,
end,
} = course;

const hasVerifiedEnrollment = (
enrollmentMode !== null
&& enrollmentMode !== undefined
&& VERIFIED_MODES.includes(enrollmentMode)
);

// audit learners should only have access if the ENABLE_XPERT_AUDIT setting is true
const hasAuditEnrollmentAndAccess = (
enrollmentMode !== null
&& enrollmentMode !== undefined
&& AUDIT_MODES.includes(enrollmentMode)
&& getConfig().ENABLE_XPERT_AUDIT
);

const validDates = () => {
const date = new Date();
const utcDate = date.toISOString();

const startDate = course.start || utcDate;
const endDate = course.end || utcDate;
const startDate = start || utcDate;
const endDate = end || utcDate;
const accessExpirationDate = accessExpiration && accessExpiration.expirationDate
? accessExpiration.expirationDate : utcDate;

return (
startDate <= utcDate
&& utcDate <= endDate
&& (hasAuditEnrollmentAndAccess ? utcDate <= accessExpirationDate : true)
);
};

const shouldDisplayChat = (
enabled
&& (hasVerifiedEnrollment || isStaff) // display only to verified learners or staff
&& (hasVerifiedEnrollment || isStaff || hasAuditEnrollmentAndAccess)
&& validDates()
// it is necessary to check both whether the user is in an exam, and whether or not they are viewing an exam
// this will prevent the learner from interacting with the tool at any point of the exam flow, even at the
// entrance interstitial.
&& !(activeAttempt?.attempt_id || exam?.id)
);

const isUpgradeEligible = !hasVerifiedEnrollment && !isStaff;

return (
<>
{/* Use a portal to ensure that component overlay does not compete with learning MFE styles. */}
{shouldDisplayChat && (createPortal(
<Xpert courseId={courseId} contentToolsEnabled={contentToolsEnabled} unitId={unitId} />,
<Xpert
courseId={courseId}
contentToolsEnabled={contentToolsEnabled}
unitId={unitId}
isUpgradeEligible={isUpgradeEligible}
/>,
document.body,
))}
</>
Expand Down
58 changes: 58 additions & 0 deletions src/courseware/course/chat/Chat.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { BrowserRouter } from 'react-router-dom';
import React from 'react';
import { Factory } from 'rosie';

import { getConfig } from '@edx/frontend-platform';

import {
initializeMockApp,
initializeTestStore,
Expand All @@ -28,6 +30,10 @@ jest.mock('@edx/frontend-lib-learning-assistant', () => {
};
});

jest.mock('@edx/frontend-platform', () => ({
getConfig: jest.fn().mockReturnValue({ ENABLE_XPERT_AUDIT: false }),
}));

initializeMockApp();

const courseId = 'course-v1:edX+DemoX+Demo_Course';
Expand Down Expand Up @@ -225,4 +231,56 @@ describe('Chat', () => {
const chat = screen.queryByTestId(mockXpertTestId);
expect(chat).toBeInTheDocument();
});

it('displays component for audit learner if explicitly enabled', async () => {
getConfig.mockImplementation(() => ({ ENABLE_XPERT_AUDIT: true }));

store = await initializeTestStore({
courseMetadata: Factory.build('courseMetadata', {
access_expiration: { expiration_date: '' },
}),
});

render(
<BrowserRouter>
<Chat
enrollmentMode="audit"
isStaff={false}
enabled
courseId={courseId}
contentToolsEnabled={false}
/>
</BrowserRouter>,
{ store },
);

const chat = screen.queryByTestId(mockXpertTestId);
expect(chat).toBeInTheDocument();
});

it('does not display component for audit learner if access deadline has passed', async () => {
getConfig.mockImplementation(() => ({ ENABLE_XPERT_AUDIT: true }));

store = await initializeTestStore({
courseMetadata: Factory.build('courseMetadata', {
access_expiration: { expiration_date: '2014-02-03T05:00:00Z' },
}),
});

render(
<BrowserRouter>
<Chat
enrollmentMode="audit"
isStaff={false}
enabled
courseId={courseId}
contentToolsEnabled={false}
/>
</BrowserRouter>,
{ store },
);

const chat = screen.queryByTestId(mockXpertTestId);
expect(chat).not.toBeInTheDocument();
});
});
1 change: 1 addition & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ initialize({
CHAT_RESPONSE_URL: process.env.CHAT_RESPONSE_URL || null,
PRIVACY_POLICY_URL: process.env.PRIVACY_POLICY_URL || null,
SHOW_UNGRADED_ASSIGNMENT_PROGRESS: process.env.SHOW_UNGRADED_ASSIGNMENT_PROGRESS || false,
ENABLE_XPERT_AUDIT: process.env.ENABLE_XPERT_AUDIT || false,
}, 'LearnerAppConfig');
},
},
Expand Down

0 comments on commit dafdcad

Please sign in to comment.