From 2a648d5a691f67bdcffb91816a90ad3f94c65528 Mon Sep 17 00:00:00 2001 From: Alie Langston Date: Tue, 29 Aug 2023 12:18:52 -0400 Subject: [PATCH] feat: update call to action message --- src/components/ToggleXpertButton/index.jsx | 51 +++++++++++++++++---- src/components/ToggleXpertButton/index.scss | 21 ++++++++- src/widgets/Xpert.test.jsx | 35 +++++++++----- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/src/components/ToggleXpertButton/index.jsx b/src/components/ToggleXpertButton/index.jsx index 9257a9c..144c07f 100644 --- a/src/components/ToggleXpertButton/index.jsx +++ b/src/components/ToggleXpertButton/index.jsx @@ -1,12 +1,15 @@ import PropTypes from 'prop-types'; -import { Button } from '@edx/paragon'; +import { useState } from 'react'; + import { sendTrackEvent } from '@edx/frontend-platform/analytics'; +import { Button, Icon, IconButton } from '@edx/paragon'; +import { Close } from '@edx/paragon/icons'; import { ReactComponent as XpertLogo } from '../../assets/xpert-logo.svg'; - import './index.scss'; const ToggleXpert = ({ isOpen, setIsOpen, courseId }) => { + const [hasDismissed, setHasDismissed] = useState(false); const handleClick = () => { // log event if the tool is opened if (!isOpen) { @@ -17,15 +20,43 @@ const ToggleXpert = ({ isOpen, setIsOpen, courseId }) => { setIsOpen(!isOpen); }; + const handleDismiss = (event) => { + // prevent default and propagation to prevent sidebar from opening + event.preventDefault(); + event.stopPropagation(); + setHasDismissed(true); + }; + return ( - +
+ {!hasDismissed && ( +
+ +
+ + Hi there! 👋 I'm Xpert, + an AI-powered assistant from edX who can help you with questions about this course. + +
+
+ )} + +
); }; diff --git a/src/components/ToggleXpertButton/index.scss b/src/components/ToggleXpertButton/index.scss index fec8323..b018873 100644 --- a/src/components/ToggleXpertButton/index.scss +++ b/src/components/ToggleXpertButton/index.scss @@ -1,11 +1,14 @@ @use '../../utils/variables'; .toggle { - background-color: variables.$dark-green; border-radius: 2rem; bottom: 1rem; height: 3rem; + &.button-icon { + background-color: variables.$dark-green; + } + &.open { right: 31%; } @@ -20,3 +23,19 @@ width: 100%; } } + +.action-message { + background-color: white; + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3), 0 1px 2px 0 rgba(0, 0, 0, 0.06); + color: black; + font-size: 14px; + width: 40%; + text-align: left; + border-radius: 1rem; +} + +.dismiss-button { + // override paragon width and height for dismiss button + width: 1.5rem !important; + height: 1.5rem !important; +} diff --git a/src/widgets/Xpert.test.jsx b/src/widgets/Xpert.test.jsx index 5f3d3ef..e51f1ab 100644 --- a/src/widgets/Xpert.test.jsx +++ b/src/widgets/Xpert.test.jsx @@ -44,17 +44,30 @@ test('initial load displays correct elements', () => { render(, { preloadedState: initialState }); // button to open chat should be in the DOM - expect(screen.getByRole('button')).toBeVisible(); + expect(screen.queryByTestId('toggle-button')).toBeVisible(); + expect(screen.queryByTestId('action-message')).toBeVisible(); // assert that UI elements in the sidebar are not in the DOM assertSidebarElementsNotInDOM(); }); +test('clicking the call to action dismiss button removes the message', async () => { + const user = userEvent.setup(); + render(, { preloadedState: initialState }); + + // button to open chat should be in the DOM + expect(screen.queryByTestId('toggle-button')).toBeVisible(); + expect(screen.queryByTestId('action-message')).toBeVisible(); + + await user.click(screen.getByRole('button', { name: 'dismiss' })); + expect(screen.queryByTestId('toggle-button')).toBeVisible(); + expect(screen.queryByTestId('action-message')).not.toBeInTheDocument(); +}); test('clicking the toggle button opens the sidebar', async () => { const user = userEvent.setup(); render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // assert that UI elements present in the sidebar are visible expect(screen.getByRole('heading', { name: 'Hi, I\'m Xpert!' })).toBeVisible(); @@ -69,7 +82,7 @@ test('submitted text appears as message in the sidebar', async () => { render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // type the user message const input = screen.getByRole('textbox'); @@ -97,7 +110,7 @@ test('loading message appears in the sidebar while the response loads', async () render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // type the user message await user.type(screen.getByRole('textbox'), userMessage); @@ -121,7 +134,7 @@ test('response text appears as message in the sidebar', async () => { render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // type the user message const input = screen.getByRole('textbox'); @@ -142,7 +155,7 @@ test('clicking the clear button clears messages in the sidebar', async () => { render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // type the user message const input = screen.getByRole('textbox'); @@ -160,7 +173,7 @@ test('clicking the close button closes the sidebar', async () => { const user = userEvent.setup(); render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); await user.click(screen.getByTestId('close-button')); // assert that UI elements in the sidebar are not in the DOM @@ -170,7 +183,7 @@ test('clicking the toggle button closes the sidebar', async () => { const user = userEvent.setup(); render(, { preloadedState: initialState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); await user.click(screen.getByTestId('toggle-button')); // assert that UI elements in the sidebar are not in the DOM @@ -193,7 +206,7 @@ test('error message should disappear upon succesful api call', async () => { }; render(, { preloadedState: errorState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // assert that error has focus expect(screen.queryByTestId('alert-heading')).toHaveFocus(); @@ -223,7 +236,7 @@ test('error message should disappear when dismissed', async () => { }; render(, { preloadedState: errorState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // assert that error message exists expect(screen.queryByText('Please try again by sending another question.')).toBeInTheDocument(); @@ -248,7 +261,7 @@ test('error message should disappear when messages cleared', async () => { }; render(, { preloadedState: errorState }); - await user.click(screen.getByRole('button')); + await user.click(screen.queryByTestId('toggle-button')); // assert that error message exists expect(screen.queryByText('Please try again by sending another question.')).toBeInTheDocument();