Skip to content

Commit

Permalink
feat: remove clear button from chat ui (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto authored Nov 15, 2024
1 parent 43c87e1 commit 55e4b80
Show file tree
Hide file tree
Showing 5 changed files with 1 addition and 150 deletions.
35 changes: 1 addition & 34 deletions src/components/Sidebar/index.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import React, { useRef, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import {
Button,
Icon,
IconButton,
} from '@openedx/paragon';
import { Close } from '@openedx/paragon/icons';

import { clearMessages } from '../../data/thunks';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY } from '../../data/optimizely';
import showSurvey from '../../utils/surveyMonkey';

import APIError from '../APIError';
import ChatBox from '../ChatBox';
import Disclosure from '../Disclosure';
import MessageForm from '../MessageForm';
import './Sidebar.scss';
import { usePromptExperimentDecision } from '../../experiments';

const Sidebar = ({
courseId,
Expand All @@ -32,14 +27,6 @@ const Sidebar = ({
messageList,
} = useSelector(state => state.learningAssistant);
const chatboxContainerRef = useRef(null);
const dispatch = useDispatch();

const [decision] = usePromptExperimentDecision();
const { enabled: enabledExperiment, variationKey } = decision || {};
const experimentPayload = enabledExperiment ? {
experiment_name: OPTIMIZELY_PROMPT_EXPERIMENT_KEY,
variation_key: variationKey,
} : {};

// this use effect is intended to scroll to the bottom of the chat window, in the case
// that a message is larger than the chat window height.
Expand Down Expand Up @@ -83,14 +70,6 @@ const Sidebar = ({
}
};

const handleClearMessages = () => {
dispatch(clearMessages());
sendTrackEvent('edx.ui.lms.learning_assistant.clear', {
course_id: courseId,
...experimentPayload,
});
};

const getMessageForm = () => (
<MessageForm courseId={courseId} shouldAutofocus unitId={unitId} />
);
Expand Down Expand Up @@ -120,18 +99,6 @@ const Sidebar = ({
)
}
{getMessageForm()}
<div className="d-flex justify-content-start">
<Button
className="clear mx-2 mb-2 border-0"
onClick={handleClearMessages}
aria-label="clear"
variant="primary"
type="button"
data-testid="sidebar-clear-btn"
>
Clear
</Button>
</div>
</div>
);

Expand Down
41 changes: 0 additions & 41 deletions src/components/Sidebar/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react';
import { screen, act } from '@testing-library/react';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';

import { usePromptExperimentDecision } from '../../experiments';
import { render as renderComponent } from '../../utils/utils.test';
import { initialState } from '../../data/slice';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY, OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS } from '../../data/optimizely';
import showSurvey from '../../utils/surveyMonkey';

import Sidebar from '.';
Expand Down Expand Up @@ -35,11 +33,6 @@ jest.mock('../../experiments', () => ({
usePromptExperimentDecision: jest.fn(),
}));

const clearMessagesAction = 'clear-messages-action';
jest.mock('../../data/thunks', () => ({
clearMessages: () => 'clear-messages-action',
}));

const defaultProps = {
courseId: 'some-course-id',
isOpen: true,
Expand Down Expand Up @@ -88,17 +81,6 @@ describe('<Sidebar />', () => {
render(undefined, { disclosureAcknowledged: true });
expect(screen.queryByTestId('sidebar-xpert')).toBeInTheDocument();
});

it('should dispatch clearMessages() and call sendTrackEvent() with the expected props on clear', () => {
render(undefined, { disclosureAcknowledged: true });

act(() => {
screen.queryByTestId('sidebar-clear-btn').click();
});

expect(mockDispatch).toHaveBeenCalledWith(clearMessagesAction);
expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.learning_assistant.clear', { course_id: defaultProps.courseId });
});
});

describe('when it\'s not open', () => {
Expand Down Expand Up @@ -133,28 +115,5 @@ describe('<Sidebar />', () => {

expect(showSurvey).toHaveBeenCalled();
});

it('should dispatch clearMessages() and call sendTrackEvent() with the expected props on clear', () => {
usePromptExperimentDecision.mockReturnValue([{
enabled: true,
variationKey: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
}]);

render(undefined, {
...defaultState,
disclosureAcknowledged: true,
});

act(() => {
screen.queryByTestId('sidebar-clear-btn').click();
});

expect(mockDispatch).toHaveBeenCalledWith(clearMessagesAction);
expect(sendTrackEvent).toHaveBeenCalledWith('edx.ui.lms.learning_assistant.clear', {
course_id: defaultProps.courseId,
experiment_name: OPTIMIZELY_PROMPT_EXPERIMENT_KEY,
variation_key: OPTIMIZELY_PROMPT_EXPERIMENT_VARIATION_KEYS.UPDATED_PROMPT,
});
});
});
});
6 changes: 0 additions & 6 deletions src/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ export const learningAssistantSlice = createSlice({
setMessageList: (state, { payload }) => {
state.messageList = payload.messageList;
},
resetMessages: (state) => {
state.currentMessage = '';
state.messageList = [];
state.apiError = false;
},
setApiError: (state) => {
state.apiError = true;
},
Expand All @@ -56,7 +51,6 @@ export const {
setCurrentMessage,
clearCurrentMessage,
setMessageList,
resetMessages,
setApiError,
setApiIsLoading,
resetApiError,
Expand Down
8 changes: 0 additions & 8 deletions src/data/thunks.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { fetchChatResponse, fetchLearningAssistantMessageHistory, fetchLearningA
import {
setCurrentMessage,
clearCurrentMessage,
resetMessages,
setMessageList,
setApiError,
setApiIsLoading,
Expand Down Expand Up @@ -74,13 +73,6 @@ export function getChatResponse(courseId, unitId, promptExperimentVariationKey =
};
}

export function clearMessages() {
return (dispatch) => {
dispatch(resetMessages());
dispatch(resetApiError());
};
}

export function getLearningAssistantMessageHistory(courseId) {
return async (dispatch) => {
dispatch(setApiIsLoading(true));
Expand Down
61 changes: 0 additions & 61 deletions src/widgets/Xpert.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const assertSidebarElementsNotInDOM = () => {

expect(screen.queryByRole('button', { name: 'submit' })).not.toBeInTheDocument();
expect(screen.queryByTestId('close-button')).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'clear' })).not.toBeInTheDocument();
};

beforeEach(() => {
Expand Down Expand Up @@ -115,7 +114,6 @@ test('clicking the call to action opens the sidebar', async () => {
expect(screen.getByRole('textbox')).toBeVisible();
expect(screen.getByRole('button', { name: 'submit' })).toBeVisible();
expect(screen.getByTestId('close-button')).toBeVisible();
expect(screen.getByRole('button', { name: 'clear' })).toBeVisible();

// assert that text input has focus
expect(screen.getByRole('textbox')).toHaveFocus();
Expand All @@ -135,7 +133,6 @@ test('clicking the toggle button opens the sidebar', async () => {
expect(screen.getByRole('textbox')).toBeVisible();
expect(screen.getByRole('button', { name: 'submit' })).toBeVisible();
expect(screen.getByTestId('close-button')).toBeVisible();
expect(screen.getByRole('button', { name: 'clear' })).toBeVisible();

// assert that text input has focus
expect(screen.getByRole('textbox')).toHaveFocus();
Expand Down Expand Up @@ -190,34 +187,6 @@ test('response text appears as message in the sidebar', async () => {
await screen.findByText(responseMessage.content);
expect(screen.getByText(responseMessage.content)).toBeInTheDocument();
});
test('clicking the clear button clears messages in the sidebar', async () => {
const user = userEvent.setup();
const userMessage = 'Hello, Xpert!';

// re-mock the fetchChatResponse API function so that we can assert that the
// responseMessage appears in the DOM and then is successfully cleared
const responseMessage = createRandomResponseForTesting();
jest.spyOn(api, 'fetchChatResponse').mockImplementation(() => responseMessage);

render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: initialState });

// wait for button to appear
await screen.findByTestId('toggle-button');

await user.click(screen.queryByTestId('toggle-button'));

// type the user message
const input = screen.getByRole('textbox');
await user.type(input, userMessage);
await user.click(screen.getByRole('button', { name: 'submit' }));

await screen.findByText(responseMessage.content);

await user.click(screen.getByRole('button', { name: 'clear' }));

expect(screen.queryByText(userMessage)).not.toBeInTheDocument();
expect(screen.queryByText(responseMessage.content)).not.toBeInTheDocument();
});
test('clicking the close button closes the sidebar', async () => {
const user = userEvent.setup();
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: initialState });
Expand Down Expand Up @@ -307,35 +276,6 @@ test('error message should disappear when dismissed', async () => {
await user.click(screen.getByText('Dismiss'));
expect(screen.queryByText('Please try again by sending another question.')).not.toBeInTheDocument();
});
test('error message should disappear when messages cleared', async () => {
const user = userEvent.setup();

const errorState = {
learningAssistant: {
currentMessage: '',
messageList: [],
apiIsLoading: false,
apiError: true,
// TEMPORARY: This is simply to ensure that the tests pass by hiding the disclosure.
// I will remove this and write tests in a future pull request.
disclosureAcknowledged: true,
sidebarIsOpen: false,
},
};
render(<Xpert courseId={courseId} contentToolsEnabled={false} unitId={unitId} />, { preloadedState: errorState });

// wait for button to appear
await screen.findByTestId('toggle-button');

await user.click(screen.queryByTestId('toggle-button'));

// assert that error message exists
expect(screen.queryByText('Please try again by sending another question.')).toBeInTheDocument();

// clear messages, assert that error message disappears
await user.click(screen.getByText('Clear'));
expect(screen.queryByText('Please try again by sending another question.')).not.toBeInTheDocument();
});
test('popup modal should open chat', async () => {
const user = userEvent.setup();
window.localStorage.clear();
Expand All @@ -357,7 +297,6 @@ test('popup modal should open chat', async () => {
expect(screen.getByRole('textbox')).toBeVisible();
expect(screen.getByRole('button', { name: 'submit' })).toBeVisible();
expect(screen.getByTestId('close-button')).toBeVisible();
expect(screen.getByRole('button', { name: 'clear' })).toBeVisible();
});
test('popup modal should close and display CTA', async () => {
const user = userEvent.setup();
Expand Down

0 comments on commit 55e4b80

Please sign in to comment.