From 38de6a33c18fc9190e4e5ad9e13b560fc2cf88d9 Mon Sep 17 00:00:00 2001
From: Alison Langston <46360176+alangsto@users.noreply.github.com>
Date: Tue, 17 Dec 2024 12:12:20 -0500
Subject: [PATCH] feat: add upgrade screen at end of trial (#76)
---
.../__snapshots__/index.test.jsx.snap | 2 +-
src/components/Disclosure/index.jsx | 20 +-
src/components/Disclosure/index.test.jsx | 17 +-
src/components/Sidebar/index.jsx | 16 +-
src/components/Sidebar/index.test.jsx | 17 +
.../UpgradeButton/UpgradeButton.scss | 3 +
src/components/UpgradeButton/index.jsx | 40 +
src/components/UpgradeButton/index.test.jsx | 42 +
src/components/UpgradePanel/UpgradePanel.scss | 21 +
.../UpsellBullets/UpsellBullets.jsx | 109 +++
.../UpgradePanel/UpsellBullets/index.jsx | 30 +
.../__snapshots__/index.test.jsx.snap | 717 ++++++++++++++++++
src/components/UpgradePanel/index.jsx | 23 +
src/components/UpgradePanel/index.test.jsx | 35 +
src/hooks/use-course-upgrade.js | 10 +-
src/hooks/use-course-upgrade.test.jsx | 87 ++-
src/widgets/Xpert.jsx | 11 -
17 files changed, 1141 insertions(+), 59 deletions(-)
create mode 100644 src/components/UpgradeButton/UpgradeButton.scss
create mode 100644 src/components/UpgradeButton/index.jsx
create mode 100644 src/components/UpgradeButton/index.test.jsx
create mode 100644 src/components/UpgradePanel/UpgradePanel.scss
create mode 100644 src/components/UpgradePanel/UpsellBullets/UpsellBullets.jsx
create mode 100644 src/components/UpgradePanel/UpsellBullets/index.jsx
create mode 100644 src/components/UpgradePanel/__snapshots__/index.test.jsx.snap
create mode 100644 src/components/UpgradePanel/index.jsx
create mode 100644 src/components/UpgradePanel/index.test.jsx
diff --git a/src/components/Disclosure/__snapshots__/index.test.jsx.snap b/src/components/Disclosure/__snapshots__/index.test.jsx.snap
index ee89f66e..3a33458c 100644
--- a/src/components/Disclosure/__snapshots__/index.test.jsx.snap
+++ b/src/components/Disclosure/__snapshots__/index.test.jsx.snap
@@ -119,7 +119,7 @@ exports[` When trial upgrade being shown should match snapsho
diff --git a/src/components/Disclosure/index.jsx b/src/components/Disclosure/index.jsx
index c617627a..99f3d48b 100644
--- a/src/components/Disclosure/index.jsx
+++ b/src/components/Disclosure/index.jsx
@@ -1,20 +1,20 @@
import PropTypes from 'prop-types';
import React from 'react';
-import { Hyperlink, Icon, Button } from '@openedx/paragon';
+import { Hyperlink, Icon } from '@openedx/paragon';
import { QuestionAnswerOutline, LightbulbCircle, AutoAwesome } from '@openedx/paragon/icons';
import { ensureConfig, getConfig } from '@edx/frontend-platform/config';
-import { useCourseUpgrade, useTrackEvent } from '../../hooks';
+
+import UpgradeButton from '../UpgradeButton';
+import { useCourseUpgrade } from '../../hooks';
import './Disclosure.scss';
ensureConfig(['PRIVACY_POLICY_URL']);
const Disclosure = ({ children }) => {
- const { upgradeable, upgradeUrl, auditTrialLengthDays } = useCourseUpgrade();
- const { track } = useTrackEvent();
+ const { upgradeable, auditTrialLengthDays } = useCourseUpgrade();
- const handleClick = () => track('edx.ui.lms.learning_assistant.disclosure_upgrade_click');
const freeDays = auditTrialLengthDays === 1 ? '1 day' : `${auditTrialLengthDays} days`;
return (
@@ -49,15 +49,7 @@ const Disclosure = ({ children }) => {
Free for {freeDays}, then upgrade course for full access to Xpert features.
-
+
) : null}
diff --git a/src/components/Disclosure/index.test.jsx b/src/components/Disclosure/index.test.jsx
index f40b4380..eda9a5a7 100644
--- a/src/components/Disclosure/index.test.jsx
+++ b/src/components/Disclosure/index.test.jsx
@@ -1,7 +1,7 @@
import React from 'react';
-import { fireEvent, screen } from '@testing-library/react';
+import { screen } from '@testing-library/react';
import { render } from '../../utils/utils.test';
-import { useCourseUpgrade, useTrackEvent } from '../../hooks';
+import { useCourseUpgrade } from '../../hooks';
import TrialDisclosure from '.';
@@ -53,15 +53,12 @@ describe('', () => {
});
describe('When trial upgrade being shown', () => {
- const mockedTrackEvent = jest.fn();
-
beforeEach(() => {
useCourseUpgrade.mockReturnValue({
upgradeable: true,
upgradeUrl: mockedUpgradeUrl,
auditTrialLengthDays: mockedAuditTrialDays,
});
- useTrackEvent.mockReturnValue({ track: mockedTrackEvent });
({ container } = render(Children));
});
@@ -78,16 +75,6 @@ describe('', () => {
expect(upgradeCta).toHaveAttribute('href', mockedUpgradeUrl);
});
- it('should call the track event on click', () => {
- const upgradeCta = screen.queryByTestId('upgrade-cta');
-
- expect(mockedTrackEvent).not.toHaveBeenCalled();
-
- fireEvent.click(upgradeCta);
-
- expect(mockedTrackEvent).toHaveBeenCalledWith('edx.ui.lms.learning_assistant.disclosure_upgrade_click');
- });
-
it('should match snapshot', () => {
expect(container).toMatchSnapshot();
});
diff --git a/src/components/Sidebar/index.jsx b/src/components/Sidebar/index.jsx
index bb590182..d9bc6497 100644
--- a/src/components/Sidebar/index.jsx
+++ b/src/components/Sidebar/index.jsx
@@ -7,11 +7,13 @@ import {
} from '@openedx/paragon';
import { Close } from '@openedx/paragon/icons';
+import { useCourseUpgrade } from '../../hooks';
import showSurvey from '../../utils/surveyMonkey';
import APIError from '../APIError';
import ChatBox from '../ChatBox';
import Disclosure from '../Disclosure';
+import UpgradePanel from '../UpgradePanel';
import MessageForm from '../MessageForm';
import { ReactComponent as XpertLogo } from '../../assets/xpert-logo.svg';
import './Sidebar.scss';
@@ -27,6 +29,9 @@ const Sidebar = ({
disclosureAcknowledged,
messageList,
} = useSelector(state => state.learningAssistant);
+
+ const { upgradeable, auditTrialExpired } = useCourseUpgrade();
+
const chatboxContainerRef = useRef(null);
// this use effect is intended to scroll to the bottom of the chat window, in the case
@@ -97,6 +102,15 @@ const Sidebar = ({
);
+ const getPanel = () => {
+ const showUpgrade = upgradeable && auditTrialExpired;
+
+ if (showUpgrade) {
+ return ;
+ }
+ return (disclosureAcknowledged ? (getSidebar()) : ({getMessageForm()}));
+ };
+
return (
isOpen && (
- {disclosureAcknowledged ? (getSidebar()) : ({getMessageForm()})}
+ {getPanel()}
)
);
diff --git a/src/components/Sidebar/index.test.jsx b/src/components/Sidebar/index.test.jsx
index 210daf40..5f40a144 100644
--- a/src/components/Sidebar/index.test.jsx
+++ b/src/components/Sidebar/index.test.jsx
@@ -5,6 +5,7 @@ import { usePromptExperimentDecision } from '../../experiments';
import { render as renderComponent } from '../../utils/utils.test';
import { initialState } from '../../data/slice';
import showSurvey from '../../utils/surveyMonkey';
+import { useCourseUpgrade, useTrackEvent } from '../../hooks';
import Sidebar from '.';
@@ -33,6 +34,11 @@ jest.mock('../../experiments', () => ({
usePromptExperimentDecision: jest.fn(),
}));
+jest.mock('../../hooks', () => ({
+ useCourseUpgrade: jest.fn(),
+ useTrackEvent: jest.fn(),
+}));
+
const defaultProps = {
courseId: 'some-course-id',
isOpen: true,
@@ -63,6 +69,8 @@ const render = async (props = {}, sliceState = {}) => {
describe('', () => {
beforeEach(() => {
jest.resetAllMocks();
+ useCourseUpgrade.mockReturnValue({ upgradeable: false });
+ useTrackEvent.mockReturnValue({ track: jest.fn() });
usePromptExperimentDecision.mockReturnValue([]);
});
@@ -81,6 +89,15 @@ describe('', () => {
render(undefined, { disclosureAcknowledged: true });
expect(screen.queryByTestId('sidebar-xpert')).toBeInTheDocument();
});
+
+ it('should not render xpert if audit trial is expired', () => {
+ useCourseUpgrade.mockReturnValue({
+ upgradeable: true,
+ auditTrialExpired: true,
+ });
+ render();
+ expect(screen.queryByTestId('sidebar-xpert')).not.toBeInTheDocument();
+ });
});
describe('when it\'s not open', () => {
diff --git a/src/components/UpgradeButton/UpgradeButton.scss b/src/components/UpgradeButton/UpgradeButton.scss
new file mode 100644
index 00000000..8d39f4cb
--- /dev/null
+++ b/src/components/UpgradeButton/UpgradeButton.scss
@@ -0,0 +1,3 @@
+.trial-upgrade {
+ border-radius: 99rem;
+}
diff --git a/src/components/UpgradeButton/index.jsx b/src/components/UpgradeButton/index.jsx
new file mode 100644
index 00000000..e80a81aa
--- /dev/null
+++ b/src/components/UpgradeButton/index.jsx
@@ -0,0 +1,40 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import { Button, Icon } from '@openedx/paragon';
+import { LockOpen } from '@openedx/paragon/icons';
+import { useCourseUpgrade, useTrackEvent } from '../../hooks';
+
+import './UpgradeButton.scss';
+
+const UpgradeButton = ({ includeLockIcon, trackingEventName }) => {
+ const { upgradeUrl } = useCourseUpgrade();
+ const { track } = useTrackEvent();
+
+ const handleClick = () => track(trackingEventName);
+
+ return (
+
+ );
+};
+
+UpgradeButton.propTypes = {
+ includeLockIcon: PropTypes.bool,
+ trackingEventName: PropTypes.string.isRequired,
+};
+
+UpgradeButton.defaultProps = {
+ includeLockIcon: false,
+};
+
+export default UpgradeButton;
diff --git a/src/components/UpgradeButton/index.test.jsx b/src/components/UpgradeButton/index.test.jsx
new file mode 100644
index 00000000..951e6e75
--- /dev/null
+++ b/src/components/UpgradeButton/index.test.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { fireEvent, screen } from '@testing-library/react';
+import { render } from '../../utils/utils.test';
+import { useCourseUpgrade, useTrackEvent } from '../../hooks';
+
+import UpgradeButton from '.';
+
+jest.mock('../../hooks', () => ({
+ useCourseUpgrade: jest.fn(),
+ useTrackEvent: jest.fn(),
+}));
+
+describe('UpgradeButton', () => {
+ beforeEach(() => {
+ useCourseUpgrade.mockReturnValue({ upgradeUrl: 'www.test.com' });
+ useTrackEvent.mockReturnValue({ track: jest.fn() });
+ });
+
+ it('should render UpgradeButton', () => {
+ render();
+ expect(screen.queryByText('Upgrade now')).toBeInTheDocument();
+ expect(screen.queryByTestId('upgrade-cta')).toHaveAttribute('href', 'www.test.com');
+ expect(screen.queryByTestId('lock-icon')).not.toBeInTheDocument();
+ });
+
+ it('should call track event on click', () => {
+ const mockedTrackEvent = jest.fn();
+ useTrackEvent.mockReturnValue({ track: mockedTrackEvent });
+
+ render();
+
+ const upgradeCta = screen.queryByTestId('upgrade-cta');
+ expect(mockedTrackEvent).not.toHaveBeenCalled();
+ fireEvent.click(upgradeCta);
+ expect(mockedTrackEvent).toHaveBeenCalledWith('test.tracking');
+ });
+
+ it('should render lock icon', () => {
+ render();
+ expect(screen.queryByTestId('lock-icon')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/UpgradePanel/UpgradePanel.scss b/src/components/UpgradePanel/UpgradePanel.scss
new file mode 100644
index 00000000..1d576223
--- /dev/null
+++ b/src/components/UpgradePanel/UpgradePanel.scss
@@ -0,0 +1,21 @@
+@use '../../utils/variables';
+
+.upgrade-panel {
+ height: 100%;
+
+ overflow-y: auto;
+ background-color: variables.$dark-green;
+
+ h2 {
+ font-size: 1.375rem;
+ }
+
+ .xpert-value-prop-check {
+ color: variables.$accent-yellow;
+ }
+
+ .xpert-value-prop {
+ margin-bottom: 1rem;
+ font-size: 0.875rem;
+ }
+}
diff --git a/src/components/UpgradePanel/UpsellBullets/UpsellBullets.jsx b/src/components/UpgradePanel/UpsellBullets/UpsellBullets.jsx
new file mode 100644
index 00000000..00b3e3f6
--- /dev/null
+++ b/src/components/UpgradePanel/UpsellBullets/UpsellBullets.jsx
@@ -0,0 +1,109 @@
+import React from 'react';
+import { Check } from '@openedx/paragon/icons';
+import { Icon, Stack } from '@openedx/paragon';
+import { FormattedMessage } from '@edx/frontend-platform/i18n';
+import { getConfig } from '@edx/frontend-platform';
+
+const CheckmarkBullet = () => (
+
+);
+
+export const VerifiedCertBullet = () => {
+ const verifiedCertLink = (
+
+
+
+ );
+ return (
+
+
+
+
+
+
+ );
+};
+
+export const UnlockGradedBullet = () => {
+ const gradedAssignmentsInBoldText = (
+
+
+
+ );
+ return (
+
+
+
+
+
+
+ );
+};
+
+export const FullAccessBullet = () => {
+ const fullAccessInBoldText = (
+
+
+
+ );
+ return (
+
+
+
+
+
+
+ );
+};
+
+export const XpertAccessBullet = () => {
+ const xpertLearningAssistantInBoldText = (
+
+
+
+ );
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/UpgradePanel/UpsellBullets/index.jsx b/src/components/UpgradePanel/UpsellBullets/index.jsx
new file mode 100644
index 00000000..08b8fcf6
--- /dev/null
+++ b/src/components/UpgradePanel/UpsellBullets/index.jsx
@@ -0,0 +1,30 @@
+import PropTypes from 'prop-types';
+import {
+ VerifiedCertBullet,
+ UnlockGradedBullet,
+ FullAccessBullet,
+ XpertAccessBullet,
+} from './UpsellBullets';
+
+const UpsellContent = ({ isFBE }) => (
+
+
+
+ {isFBE && (
+ <>
+
+
+ >
+ )}
+
+);
+
+UpsellContent.defaultProps = {
+ isFBE: false,
+};
+
+UpsellContent.propTypes = {
+ isFBE: PropTypes.bool,
+};
+
+export default UpsellContent;
diff --git a/src/components/UpgradePanel/__snapshots__/index.test.jsx.snap b/src/components/UpgradePanel/__snapshots__/index.test.jsx.snap
new file mode 100644
index 00000000..94026f48
--- /dev/null
+++ b/src/components/UpgradePanel/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,717 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`UpgradePanel displays correct bullet points if FBE 1`] = `
+{
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+ Upgrade this course
+
+
+
+
+
+
+
+ Gain full access to
+
+ Xpert Learning Assistant
+
+
+
+
+
+
+
+
+
+ Unlock your access to all course activities, including
+
+ graded assignments
+
+
+
+
+
+
+
+
+
+ Full access
+
+ to course content and materials, even after the course ends
+
+
+
+
+
+
+
+ Upgrade now
+
+
+
+ ,
+ "container":
+
+
+ Upgrade this course
+
+
+
+
+
+
+
+ Gain full access to
+
+ Xpert Learning Assistant
+
+
+
+
+
+
+
+
+
+ Unlock your access to all course activities, including
+
+ graded assignments
+
+
+
+
+
+
+
+
+
+ Full access
+
+ to course content and materials, even after the course ends
+
+
+
+
+
+
+
+ Upgrade now
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "store": {
+ "dispatch": [Function],
+ "getState": [Function],
+ "replaceReducer": [Function],
+ "subscribe": [Function],
+ Symbol(Symbol.observable): [Function],
+ },
+ "unmount": [Function],
+}
+`;
+
+exports[`UpgradePanel displays correct bullet points if not FBE 1`] = `
+{
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+ Upgrade this course
+
+
+
+
+
+
+
+ Gain full access to
+
+ Xpert Learning Assistant
+
+
+
+
+
+
+
+
+
+ Upgrade now
+
+
+
+ ,
+ "container":
+
+
+ Upgrade this course
+
+
+
+
+
+
+
+ Gain full access to
+
+ Xpert Learning Assistant
+
+
+
+
+
+
+
+
+
+ Upgrade now
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "store": {
+ "dispatch": [Function],
+ "getState": [Function],
+ "replaceReducer": [Function],
+ "subscribe": [Function],
+ Symbol(Symbol.observable): [Function],
+ },
+ "unmount": [Function],
+}
+`;
diff --git a/src/components/UpgradePanel/index.jsx b/src/components/UpgradePanel/index.jsx
new file mode 100644
index 00000000..3280f2db
--- /dev/null
+++ b/src/components/UpgradePanel/index.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+
+import { useCourseUpgrade } from '../../hooks';
+import UpsellContent from './UpsellBullets';
+import UpgradeButton from '../UpgradeButton';
+
+import './UpgradePanel.scss';
+
+const UpgradePanel = () => {
+ const { isFBE } = useCourseUpgrade();
+
+ return (
+
+
+ Upgrade this course
+
+
+
+
+ );
+};
+
+export default UpgradePanel;
diff --git a/src/components/UpgradePanel/index.test.jsx b/src/components/UpgradePanel/index.test.jsx
new file mode 100644
index 00000000..86d211f2
--- /dev/null
+++ b/src/components/UpgradePanel/index.test.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { render } from '../../utils/utils.test';
+import { useCourseUpgrade, useTrackEvent } from '../../hooks';
+
+import UpgradePanel from '.';
+
+jest.mock('../../hooks', () => ({
+ useCourseUpgrade: jest.fn(),
+ useTrackEvent: jest.fn(),
+}));
+
+describe('UpgradePanel', () => {
+ beforeEach(() => {
+ useCourseUpgrade.mockReturnValue({ upgradeUrl: 'www.test.com' });
+ useTrackEvent.mockReturnValue({ track: jest.fn() });
+ });
+
+ it('displays correct bullet points if not FBE', () => {
+ useCourseUpgrade.mockReturnValue({
+ upgradeUrl: 'www.test.com',
+ isFBE: false,
+ });
+
+ expect(render()).toMatchSnapshot();
+ });
+
+ it('displays correct bullet points if FBE', () => {
+ useCourseUpgrade.mockReturnValue({
+ upgradeUrl: 'www.test.com',
+ isFBE: true,
+ });
+
+ expect(render()).toMatchSnapshot();
+ });
+});
diff --git a/src/hooks/use-course-upgrade.js b/src/hooks/use-course-upgrade.js
index 41abfa99..9373d151 100644
--- a/src/hooks/use-course-upgrade.js
+++ b/src/hooks/use-course-upgrade.js
@@ -30,7 +30,11 @@ const millisecondsInOneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milli
*/
export default function useCourseUpgrade() {
const { courseId, isUpgradeEligible } = useContext(CourseInfoContext);
- const { offer } = useModel('coursewareMeta', courseId);
+ const {
+ offer,
+ accessExpiration,
+ datesBannerInfo,
+ } = useModel('coursewareMeta', courseId);
const { verifiedMode } = useModel('courseHomeMeta', courseId);
const {
auditTrialLengthDays,
@@ -46,12 +50,13 @@ export default function useCourseUpgrade() {
if (auditTrial?.expirationDate) {
const auditTrialExpirationDate = new Date(auditTrial.expirationDate);
-
auditTrialDaysRemaining = Math.ceil((auditTrialExpirationDate - Date.now()) / millisecondsInOneDay);
auditTrialExpired = auditTrialDaysRemaining < 0;
}
+ const isFBE = !!accessExpiration && !!datesBannerInfo?.contentTypeGatingEnabled;
+
return {
upgradeable: true,
auditTrialLengthDays,
@@ -59,5 +64,6 @@ export default function useCourseUpgrade() {
auditTrialExpired,
auditTrial,
upgradeUrl,
+ isFBE,
};
}
diff --git a/src/hooks/use-course-upgrade.test.jsx b/src/hooks/use-course-upgrade.test.jsx
index 92895fda..c68cad3a 100644
--- a/src/hooks/use-course-upgrade.test.jsx
+++ b/src/hooks/use-course-upgrade.test.jsx
@@ -18,12 +18,12 @@ const contextWrapper = ({ courseInfo }) => function Wrapper({ children }) { // e
};
const renderHook = ({
- courseInfo, offer = {}, verifiedMode = {}, state = { learningAssistant: {} },
+ courseInfo, coursewareMeta = { offer: {} }, courseHomeMeta = { verifiedMode: {} }, state = { learningAssistant: {} },
}) => {
useModel.mockImplementation((model) => {
switch (model) {
- case 'coursewareMeta': return { offer };
- case 'courseHomeMeta': return { verifiedMode };
+ case 'coursewareMeta': return coursewareMeta;
+ case 'courseHomeMeta': return courseHomeMeta;
default: {
throw new Error('Model not mocked');
}
@@ -63,12 +63,15 @@ describe('useCourseUpgrade()', () => {
auditTrialExpired: false,
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: mockedUpgradeUrl,
+ isFBE: false,
};
const { result: resultOffer } = renderHook({
courseInfo: { isUpgradeEligible: true },
- offer: {
- upgradeUrl: mockedUpgradeUrl,
+ coursewareMeta: {
+ offer: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
},
state: {
learningAssistant: {
@@ -81,8 +84,10 @@ describe('useCourseUpgrade()', () => {
const { result: resultVerified } = renderHook({
courseInfo: { isUpgradeEligible: true },
- verifiedMode: {
- upgradeUrl: mockedUpgradeUrl,
+ courseHomeMeta: {
+ verifiedMode: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
},
state: {
learningAssistant: {
@@ -97,11 +102,15 @@ describe('useCourseUpgrade()', () => {
it('should return trial info if enabled and not expired', () => {
const { result } = renderHook({
courseInfo: { isUpgradeEligible: true },
- offer: {
- upgradeUrl: mockedUpgradeUrl,
+ coursewareMeta: {
+ offer: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
},
- verifiedMode: {
- upgradeUrl: mockedUpgradeUrl,
+ courseHomeMeta: {
+ verifiedMode: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
},
state: {
learningAssistant: {
@@ -122,17 +131,64 @@ describe('useCourseUpgrade()', () => {
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: 'https://upgrade.edx/course/test',
upgradeable: true,
+ isFBE: false,
});
});
it('should return trial info if expired', () => {
const { result } = renderHook({
courseInfo: { isUpgradeEligible: true },
- offer: {
- upgradeUrl: mockedUpgradeUrl,
+ coursewareMeta: {
+ offer: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
+ },
+ courseHomeMeta: {
+ verifiedMode: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
+ },
+ state: {
+ learningAssistant: {
+ auditTrialLengthDays: mockedAuditTrialLengthDays,
+ auditTrial: {
+ expirationDate: '2024-01-05 09:00:00',
+ },
+ },
+ },
+ });
+
+ expect(result.current).toEqual({
+ auditTrial: {
+ expirationDate: '2024-01-05 09:00:00',
+ },
+ auditTrialDaysRemaining: -5,
+ auditTrialExpired: true,
+ auditTrialLengthDays: mockedAuditTrialLengthDays,
+ upgradeUrl: 'https://upgrade.edx/course/test',
+ upgradeable: true,
+ isFBE: false,
+ });
+ });
+
+ it('should return isFBE true if feature based enrollment', () => {
+ const { result } = renderHook({
+ courseInfo: { isUpgradeEligible: true },
+ coursewareMeta: {
+ offer: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
+ accessExpiration: {
+ upgradeDeadline: '2024-01-07 09:00:00',
+ },
+ datesBannerInfo: {
+ contentTypeGatingEnabled: true,
+ },
},
- verifiedMode: {
- upgradeUrl: mockedUpgradeUrl,
+ courseHomeMeta: {
+ verifiedMode: {
+ upgradeUrl: mockedUpgradeUrl,
+ },
},
state: {
learningAssistant: {
@@ -153,6 +209,7 @@ describe('useCourseUpgrade()', () => {
auditTrialLengthDays: mockedAuditTrialLengthDays,
upgradeUrl: 'https://upgrade.edx/course/test',
upgradeable: true,
+ isFBE: true,
});
});
});
diff --git a/src/widgets/Xpert.jsx b/src/widgets/Xpert.jsx
index 48cc8283..2a5b32d3 100644
--- a/src/widgets/Xpert.jsx
+++ b/src/widgets/Xpert.jsx
@@ -23,7 +23,6 @@ const Xpert = ({
const {
isEnabled,
sidebarIsOpen,
- auditTrial,
} = useSelector(state => state.learningAssistant);
const setSidebarIsOpen = (isOpen) => {
@@ -34,16 +33,6 @@ const Xpert = ({
dispatch(getLearningAssistantChatSummary(courseId));
}, [dispatch, courseId]);
- // NOTE: This value can be used later on if/when we pass the enrollment mode to this component
- const isAuditTrialNotExpired = () => { // eslint-disable-line no-unused-vars
- const auditTrialExpirationDate = new Date(auditTrial.expirationDate);
-
- if ((Date.now() - auditTrialExpirationDate) > 0) {
- return true;
- }
- return false;
- };
-
return isEnabled ? (