Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: gate visibility of chat component by active attempt #1282

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/courseware/course/chat/Chat.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createPortal } from 'react-dom';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { Xpert } from '@edx/frontend-lib-learning-assistant';
Expand All @@ -13,6 +14,10 @@ const Chat = ({
unitId,
endDate,
}) => {
const {
activeAttempt, exam,
} = useSelector(state => state.specialExams);

const VERIFIED_MODES = [
'professional',
'verified',
Expand Down Expand Up @@ -41,6 +46,10 @@ const Chat = ({
enabled
&& (hasVerifiedEnrollment || isStaff) // display only to verified learners or staff
&& !endDatePassed()
// 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)
);

return (
Expand Down
76 changes: 45 additions & 31 deletions src/courseware/course/chat/Chat.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BrowserRouter } from 'react-router-dom';
import { configureStore } from '@reduxjs/toolkit';
import React from 'react';

import { reducer as learningAssistantReducer } from '@edx/frontend-lib-learning-assistant';

import { initializeMockApp, render, screen } from '../../../setupTest';
import {
initializeMockApp,
initializeTestStore,
render,
screen,
} from '../../../setupTest';

import Chat from './Chat';

Expand Down Expand Up @@ -39,6 +41,21 @@ const disabledModes = [null, undefined, 'xyz', 'audit', 'honor', 'unpaid-executi
const currentTime = new Date();

describe('Chat', () => {
let store;

beforeAll(async () => {
store = await initializeTestStore({
specialExams: {
activeAttempt: {
attempt_id: null,
},
exam: {
id: null,
},
},
});
});

// Generate test cases.
enabledTestCases = enabledModes.map((mode) => ({ enrollmentMode: mode, isVisible: true }));
disabledTestCases = disabledModes.map((mode) => ({ enrollmentMode: mode, isVisible: false }));
Expand All @@ -48,12 +65,6 @@ describe('Chat', () => {
it(
`visibility determined by ${test.enrollmentMode} enrollment mode when enabled and not isStaff`,
async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand Down Expand Up @@ -82,12 +93,6 @@ describe('Chat', () => {
testCases = enabledModes.concat(disabledModes).map((mode) => ({ enrollmentMode: mode, isVisible: true }));
testCases.forEach(test => {
it('visibility determined by isStaff when enabled and any enrollment mode', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand Down Expand Up @@ -144,12 +149,6 @@ describe('Chat', () => {
`visibility determined by ${test.enabled} enabled when ${test.isStaff} isStaff
and ${test.enrollmentMode} enrollment mode`,
async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand All @@ -175,12 +174,6 @@ describe('Chat', () => {
});

it('if course end date has passed, component should not be visible', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
},
});

render(
<BrowserRouter>
<Chat
Expand All @@ -200,9 +193,30 @@ describe('Chat', () => {
});

it('if course has no end date, component should be visible', async () => {
const store = configureStore({
reducer: {
learningAssistant: learningAssistantReducer,
render(
<BrowserRouter>
<Chat
enrollmentMode="verified"
isStaff
enabled
courseId={courseId}
contentToolsEnabled={false}
endDate={null}
/>
</BrowserRouter>,
{ store },
);

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

it('if learner has active exam attempt, component should not be visible', async () => {
store = await initializeTestStore({
specialExams: {
activeAttempt: {
attempt_id: 1,
},
},
});

Expand Down
2 changes: 1 addition & 1 deletion src/store.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { reducer as learningAssistantReducer } from '@edx/frontend-lib-learning-assistant';
import { configureStore } from '@reduxjs/toolkit';
import { reducer as specialExamsReducer } from '@edx/frontend-lib-special-exams';
import { configureStore } from '@reduxjs/toolkit';
import { reducer as courseHomeReducer } from './course-home/data';
import { reducer as coursewareReducer } from './courseware/data/slice';
import { reducer as recommendationsReducer } from './courseware/course/course-exit/data/slice';
Expand Down
Loading