From 3a86b009114759e0b5cbc35df8e66b6f32ff371e Mon Sep 17 00:00:00 2001 From: Hamzah Ullah Date: Wed, 9 Nov 2022 12:54:06 -0500 Subject: [PATCH] feat: add basic validation on stepper title --- .../ContentHighlightsContext.jsx | 7 +- .../ContentHighlightStepper.jsx | 17 +++-- .../HighlightStepperTitle.jsx | 67 ++++++++++--------- .../tests/ContentHighlightStepper.test.jsx | 33 +++++++-- .../ContentHighlights/data/hooks.js | 12 +++- .../tests/ContentHighlightSetCard.test.jsx | 2 +- .../tests/ContentHighlightsDashboard.test.jsx | 2 +- .../tests/CurrentContentHighlights.test.jsx | 2 +- 8 files changed, 94 insertions(+), 48 deletions(-) diff --git a/src/components/ContentHighlights/ContentHighlightsContext.jsx b/src/components/ContentHighlights/ContentHighlightsContext.jsx index 57830e9dc7..3750088090 100644 --- a/src/components/ContentHighlights/ContentHighlightsContext.jsx +++ b/src/components/ContentHighlights/ContentHighlightsContext.jsx @@ -1,16 +1,19 @@ import React, { createContext, useMemo } from 'react'; import PropTypes from 'prop-types'; -import useStepperModalState from './data/hooks'; +import { useStepperModalState, useStepperDataState } from './data/hooks'; export const ContentHighlightsContext = createContext({}); const ContentHighlightsContextProvider = ({ children }) => { const { setIsModalOpen, isModalOpen } = useStepperModalState(); + const { setStepperData, stepperData } = useStepperDataState(); const value = useMemo(() => ({ setIsModalOpen, isModalOpen, - }), [setIsModalOpen, isModalOpen]); + setStepperData, + stepperData, + }), [setIsModalOpen, isModalOpen, setStepperData, stepperData]); return {children}; }; diff --git a/src/components/ContentHighlights/HighlightStepper/ContentHighlightStepper.jsx b/src/components/ContentHighlights/HighlightStepper/ContentHighlightStepper.jsx index d60c945a00..814eef8535 100644 --- a/src/components/ContentHighlights/HighlightStepper/ContentHighlightStepper.jsx +++ b/src/components/ContentHighlights/HighlightStepper/ContentHighlightStepper.jsx @@ -22,14 +22,14 @@ import { ContentHighlightsContext } from '../ContentHighlightsContext'; * @returns */ const ContentHighlightStepper = ({ isOpen }) => { - const { setIsModalOpen } = useContext(ContentHighlightsContext); + const { setIsModalOpen, stepperData, setStepperData } = useContext(ContentHighlightsContext); /* eslint-disable no-unused-vars */ const steps = ['Title', 'Select courses', 'Confirm and Publish', 'All Set']; const [currentStep, setCurrentStep] = useState(steps[0]); const [modalState, setModalState] = useState(isOpen); useEffect(() => { setModalState(isOpen); - }, [isOpen]); + }, [isOpen, stepperData]); const submitAndReset = () => { if (steps.indexOf(currentStep) === steps.length - 1) { /* TODO: submit data to api if confirmed */ @@ -37,6 +37,15 @@ const ContentHighlightStepper = ({ isOpen }) => { } setIsModalOpen(false); }; + const validateStepsAndContinue = () => { + if (currentStep === steps[0] && stepperData?.title) { + setCurrentStep(steps[1]); + } + }; + const clearDataAndClose = () => { + setStepperData({}); + setIsModalOpen(false); + }; return ( <> @@ -55,8 +64,8 @@ const ContentHighlightStepper = ({ isOpen }) => { {/* Eventually would need a check to see if the user has made any changes to the form before allowing them to close the modal without saving. Ln 58 onClick */} - - + + diff --git a/src/components/ContentHighlights/HighlightStepper/HighlightStepperTitle.jsx b/src/components/ContentHighlights/HighlightStepper/HighlightStepperTitle.jsx index 2c54ec0c0c..86878fb64b 100644 --- a/src/components/ContentHighlights/HighlightStepper/HighlightStepperTitle.jsx +++ b/src/components/ContentHighlights/HighlightStepper/HighlightStepperTitle.jsx @@ -1,39 +1,44 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Stack, Col, Form, Icon, Container, } from '@edx/paragon'; import { AddCircle } from '@edx/paragon/icons'; import { STEPPER_STEP_TEXT } from '../data/constants'; +import { ContentHighlightsContext } from '../ContentHighlightsContext'; -const HighlightStepperTitle = () => ( - - - - - - -

{STEPPER_STEP_TEXT.createTitle}

- -
-
-

- Create a unique title for your highlight collection. This title will - appear in your learner's portal together with the selected courses. -

-

- - Pro tip: We recommend naming your highlight collection to reflect skills - it aims to develop, or to draw the attention of specific groups it targets. - For example, "Recommended for Marketing" or "Develop Leadership Skills" - -

-
- - - - -
-
-); +const HighlightStepperTitle = () => { + const { stepperData, setStepperData } = useContext(ContentHighlightsContext); + const handleChange = (e) => setStepperData({ title: e.target.value }); + return ( + + + + + + +

{STEPPER_STEP_TEXT.createTitle}

+ +
+
+

+ Create a unique title for your highlight collection. This title will + appear in your learner's portal together with the selected courses. +

+

+ + Pro tip: We recommend naming your highlight collection to reflect skills + it aims to develop, or to draw the attention of specific groups it targets. + For example, "Recommended for Marketing" or "Develop Leadership Skills" + +

+
+ + + + +
+
+ ); +}; export default HighlightStepperTitle; diff --git a/src/components/ContentHighlights/HighlightStepper/tests/ContentHighlightStepper.test.jsx b/src/components/ContentHighlights/HighlightStepper/tests/ContentHighlightStepper.test.jsx index 1f93ff6ccf..47e7a6fe88 100644 --- a/src/components/ContentHighlights/HighlightStepper/tests/ContentHighlightStepper.test.jsx +++ b/src/components/ContentHighlights/HighlightStepper/tests/ContentHighlightStepper.test.jsx @@ -1,17 +1,24 @@ import { screen, render, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { Button } from '@edx/paragon'; -import React from 'react'; +import React, { useEffect } from 'react'; +import Proptypes from 'prop-types'; import ContentHighlightStepper from '../ContentHighlightStepper'; import { ContentHighlightsContext } from '../../ContentHighlightsContext'; -import useStepperModalState from '../../data/hooks'; +import { useStepperModalState, useStepperDataState } from '../../data/hooks'; import { STEPPER_STEP_TEXT } from '../../data/constants'; -const ContentHighlightStepperWrapper = () => { +const ContentHighlightStepperWrapper = ({ stepperTitle }) => { const { setIsModalOpen, isModalOpen } = useStepperModalState(); + const { setStepperData, stepperData } = useStepperDataState(); + useEffect(() => { + setStepperData({ title: stepperTitle }); + }, [setStepperData, stepperTitle]); const defaultValue = { setIsModalOpen, isModalOpen, + setStepperData, + stepperData, }; return ( @@ -21,6 +28,14 @@ const ContentHighlightStepperWrapper = () => { ); }; +ContentHighlightStepperWrapper.propTypes = { + stepperTitle: Proptypes.string, +}; + +ContentHighlightStepperWrapper.defaultProps = { + stepperTitle: '', +}; + describe('', () => { it('Displays the stepper', () => { render(); @@ -30,26 +45,34 @@ describe('', () => { expect(screen.getByText(STEPPER_STEP_TEXT.createTitle)).toBeInTheDocument(); }); it('Displays the stepper and test all back and next buttons', () => { - render(); + render(); + // open stepper --> title const stepper = screen.getByText('Click Me'); fireEvent.click(stepper); + // title --> select courses const nextButton1 = screen.getByText('Next'); fireEvent.click(nextButton1); + // select courses --> confirm courses const nextButton2 = screen.getByText('Next'); fireEvent.click(nextButton2); + // confirm courses --> confirm highlight const nextButton3 = screen.getByText('Next'); fireEvent.click(nextButton3); + // confirm highlight --> confirm courses const backButton1 = screen.getByText('Back'); fireEvent.click(backButton1); expect(screen.getByText(STEPPER_STEP_TEXT.confirmContent)).toBeInTheDocument(); + // confirm courses --> select courses const backButton2 = screen.getByText('Back'); fireEvent.click(backButton2); expect(screen.getByText(STEPPER_STEP_TEXT.selectCourses)).toBeInTheDocument(); + // select courses --> title const backButton3 = screen.getByText('Back'); fireEvent.click(backButton3); expect(screen.getByText(STEPPER_STEP_TEXT.createTitle)).toBeInTheDocument(); + // title --> closed stepper const backButton4 = screen.getByText('Back'); fireEvent.click(backButton4); expect(screen.getByText('Click Me')).toBeInTheDocument(); @@ -66,7 +89,7 @@ describe('', () => { expect(screen.getByText('Click Me')).toBeInTheDocument(); }); it('Displays the stepper and closes the stepper on confirm', () => { - render(); + render(); const stepper = screen.getByText('Click Me'); fireEvent.click(stepper); diff --git a/src/components/ContentHighlights/data/hooks.js b/src/components/ContentHighlights/data/hooks.js index a69050f0f1..e89ea93cdf 100644 --- a/src/components/ContentHighlights/data/hooks.js +++ b/src/components/ContentHighlights/data/hooks.js @@ -1,11 +1,17 @@ import { useState } from 'react'; -const useStepperModalState = () => { +export const useStepperModalState = () => { const [isModalOpen, setIsModalOpen] = useState(false); - return { isModalOpen, setIsModalOpen, }; }; -export default useStepperModalState; + +export const useStepperDataState = () => { + const [stepperData, setStepperData] = useState({}); + return { + stepperData, + setStepperData, + }; +}; diff --git a/src/components/ContentHighlights/tests/ContentHighlightSetCard.test.jsx b/src/components/ContentHighlights/tests/ContentHighlightSetCard.test.jsx index 7a5939e168..7754889672 100644 --- a/src/components/ContentHighlights/tests/ContentHighlightSetCard.test.jsx +++ b/src/components/ContentHighlights/tests/ContentHighlightSetCard.test.jsx @@ -6,7 +6,7 @@ import thunk from 'redux-thunk'; import { renderWithRouter } from '@edx/frontend-enterprise-utils'; import ContentHighlightSetCard from '../ContentHighlightSetCard'; import { ContentHighlightsContext } from '../ContentHighlightsContext'; -import useStepperModalState from '../data/hooks'; +import { useStepperModalState } from '../data/hooks'; import ContentHighlightStepper from '../HighlightStepper/ContentHighlightStepper'; const mockStore = configureMockStore([thunk]); diff --git a/src/components/ContentHighlights/tests/ContentHighlightsDashboard.test.jsx b/src/components/ContentHighlights/tests/ContentHighlightsDashboard.test.jsx index 91baca1520..da58af104b 100644 --- a/src/components/ContentHighlights/tests/ContentHighlightsDashboard.test.jsx +++ b/src/components/ContentHighlights/tests/ContentHighlightsDashboard.test.jsx @@ -8,7 +8,7 @@ import { renderWithRouter } from '@edx/frontend-enterprise-utils'; import { TEST_COURSE_HIGHLIGHTS_DATA } from '../data/constants'; import ContentHighlightsDashboard from '../ContentHighlightsDashboard'; import { ContentHighlightsContext } from '../ContentHighlightsContext'; -import useStepperModalState from '../data/hooks'; +import { useStepperModalState } from '../data/hooks'; const mockStore = configureMockStore([thunk]); diff --git a/src/components/ContentHighlights/tests/CurrentContentHighlights.test.jsx b/src/components/ContentHighlights/tests/CurrentContentHighlights.test.jsx index f312f2691e..0dccd66934 100644 --- a/src/components/ContentHighlights/tests/CurrentContentHighlights.test.jsx +++ b/src/components/ContentHighlights/tests/CurrentContentHighlights.test.jsx @@ -6,7 +6,7 @@ import thunk from 'redux-thunk'; import { renderWithRouter } from '@edx/frontend-enterprise-utils'; import CurrentContentHighlights from '../CurrentContentHighlights'; import { ContentHighlightsContext } from '../ContentHighlightsContext'; -import useStepperModalState from '../data/hooks'; +import { useStepperModalState } from '../data/hooks'; const mockStore = configureMockStore([thunk]);