diff --git a/src/components/ToggleXpertButton/index.jsx b/src/components/ToggleXpertButton/index.jsx index da1d95d..455affb 100644 --- a/src/components/ToggleXpertButton/index.jsx +++ b/src/components/ToggleXpertButton/index.jsx @@ -7,7 +7,8 @@ import { Button, Icon, IconButton, - ProductTour, + ModalCloseButton, + ModalPopup, } from '@edx/paragon'; import { Close } from '@edx/paragon/icons'; @@ -20,7 +21,9 @@ const ToggleXpert = ({ courseId, contentToolsEnabled, }) => { - const [hasDismissed, setHasDismissed] = useState(false); + const [hasDismissedCTA, setHasDismissedCTA] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(true); + const [target, setTarget] = useState(null); const { userId } = getAuthenticatedUser(); const handleClick = (event) => { @@ -35,6 +38,8 @@ const ToggleXpert = ({ }, ); } + setIsModalOpen(false); + localStorage.setItem('completedLearningAssistantTour', 'true'); setIsOpen(!isOpen); }; @@ -42,16 +47,16 @@ const ToggleXpert = ({ // prevent default and propagation to prevent sidebar from opening event.preventDefault(); event.stopPropagation(); - setHasDismissed(true); + setHasDismissedCTA(true); localStorage.setItem('dismissedLearningAssistantCallToAction', 'true'); sendTrackEvent('edx.ui.lms.learning_assistant.dismiss_action_message', { course_id: courseId, }); }; - const handleProductTourEnd = () => { - setIsOpen(true); + const handleModalClose = () => { localStorage.setItem('completedLearningAssistantTour', 'true'); + setIsModalOpen(false); sendTrackEvent( 'edx.ui.lms.learning_assistant.launch', { @@ -62,31 +67,53 @@ const ToggleXpert = ({ ); }; - const learningAssistantTour = { - tourId: 'learningAssistantTour', - endButtonText: 'Check it out', - onEnd: () => { handleProductTourEnd(); }, - enabled: !localStorage.getItem('completedLearningAssistantTour'), - checkpoints: [ - { - placement: 'left', - target: '#cta-button', - body: 'Xpert is a new part of your learning experience. ' - + 'You can ask questions and get tutoring help during your course.', - }, - ], - }; + const shouldDisplayCTA = ( + (!localStorage.getItem('dismissedLearningAssistantCallToAction') && !hasDismissedCTA) + && (localStorage.getItem('completedLearningAssistantTour') || !isModalOpen) + ); return ( (!isOpen && ( <> - -
+ +
+

+ Xpert is a new part of your learning experience.
+ You can ask questions and get tutoring help during your course. +

+
+ Close + +
+
+
+
+
- {(!localStorage.getItem('dismissedLearningAssistantCallToAction') && !hasDismissed) && ( + { shouldDisplayCTA && (
diff --git a/src/components/ToggleXpertButton/index.scss b/src/components/ToggleXpertButton/index.scss index db38359..2452514 100644 --- a/src/components/ToggleXpertButton/index.scss +++ b/src/components/ToggleXpertButton/index.scss @@ -48,3 +48,7 @@ .chat-content-tools-margin { margin-bottom: 2rem; } + +.learning-assistant-popup-modal { + width: 100%; +} diff --git a/src/widgets/Xpert.test.jsx b/src/widgets/Xpert.test.jsx index 6cf47d9..f1c730d 100644 --- a/src/widgets/Xpert.test.jsx +++ b/src/widgets/Xpert.test.jsx @@ -40,6 +40,9 @@ beforeEach(() => { const responseMessage = createRandomResponseForTesting(); jest.spyOn(api, 'default').mockResolvedValue(responseMessage); window.localStorage.clear(); + // Popup modal should be ignored for all tests unless explicitly enabled. This is because + // it makes all other elements non-clickable, so it is easier to test most test cases without the popup. + window.localStorage.setItem('completedLearningAssistantTour', 'true'); }); test('initial load displays correct elements', () => { @@ -298,3 +301,39 @@ test('error message should disappear when messages cleared', async () => { 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(); + + render(, { preloadedState: initialState }); + + // button to open chat should be in the DOM + expect(screen.queryByTestId('toggle-button')).toBeVisible(); + expect(screen.queryByTestId('modal-message')).toBeVisible(); + + // click check it out + await user.click(screen.queryByTestId('check-button')); + + // assert that UI elements present in the sidebar are visible + expect(screen.getByRole('heading', { name: 'Hi, I\'m Xpert!' })).toBeVisible(); + 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(); + window.localStorage.clear(); + + render(, { preloadedState: initialState }); + + // button to open chat should be in the DOM + expect(screen.queryByTestId('toggle-button')).toBeVisible(); + expect(screen.queryByTestId('modal-message')).toBeVisible(); + + // click close + await user.click(screen.queryByTestId('close-button')); + + assertSidebarElementsNotInDOM(); + expect(screen.queryByTestId('action-message')).toBeVisible(); +});