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: add basic validation on stepper title #893

Closed
wants to merge 2 commits into from
Closed
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
7 changes: 5 additions & 2 deletions src/components/ContentHighlights/ContentHighlightsContext.jsx
Original file line number Diff line number Diff line change
@@ -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 <ContentHighlightsContext.Provider value={value}>{children}</ContentHighlightsContext.Provider>;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,30 @@ 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 */
setCurrentStep(steps[0]);
}
setIsModalOpen(false);
};
const validateStepsAndContinue = () => {
if (currentStep === steps[0] && stepperData?.title) {
setCurrentStep(steps[1]);
}
};
const clearDataAndClose = () => {
setStepperData({});
setIsModalOpen(false);
};
return (
<>
<Stepper activeKey={currentStep}>
Expand All @@ -55,8 +64,8 @@ const ContentHighlightStepper = ({ isOpen }) => {
<Stepper.ActionRow.Spacer />
{/* 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 */}
<Button variant="tertiary" onClick={() => setIsModalOpen(false)}>Back</Button>
<Button variant="primary" onClick={() => setCurrentStep(steps[1])}>Next</Button>
<Button variant="tertiary" onClick={clearDataAndClose}>Back</Button>
<Button variant="primary" onClick={validateStepsAndContinue}>Next</Button>
</Stepper.ActionRow>

<Stepper.ActionRow eventKey="Select courses">
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = () => (
<Container size="md">
<Stack>
<Col>
<Stack className="mb-3" direction="horizontal">
<Icon src={AddCircle} />
<Col>
<h3 className="m-0">{STEPPER_STEP_TEXT.createTitle}</h3>
</Col>
</Stack>
<div className="mb-5">
<p>
Create a unique title for your highlight collection. This title will
appear in your learner&apos;s portal together with the selected courses.
</p>
<p>
<strong>
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, &quot;Recommended for Marketing&quot; or &quot;Develop Leadership Skills&quot;
</strong>
</p>
</div>
<Form.Group>
<Form.Control type="text" floatingLabel="Highlight collection name" />
</Form.Group>
</Col>
</Stack>
</Container>
);
const HighlightStepperTitle = () => {
const { stepperData, setStepperData } = useContext(ContentHighlightsContext);
const handleChange = (e) => setStepperData({ title: e.target.value });
return (
<Container size="md">
<Stack>
<Col>
<Stack className="mb-3" direction="horizontal">
<Icon src={AddCircle} />
<Col>
<h3 className="m-0">{STEPPER_STEP_TEXT.createTitle}</h3>
</Col>
</Stack>
<div className="mb-5">
<p>
Create a unique title for your highlight collection. This title will
appear in your learner&apos;s portal together with the selected courses.
</p>
<p>
<strong>
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, &quot;Recommended for Marketing&quot; or &quot;Develop Leadership Skills&quot;
</strong>
</p>
</div>
<Form.Group>
<Form.Control value={stepperData?.title} onChange={handleChange} type="text" floatingLabel="Highlight collection name" />
</Form.Group>
</Col>
</Stack>
</Container>
);
};

export default HighlightStepperTitle;
Original file line number Diff line number Diff line change
@@ -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 (
<ContentHighlightsContext.Provider value={defaultValue}>
Expand All @@ -21,6 +28,14 @@ const ContentHighlightStepperWrapper = () => {
);
};

ContentHighlightStepperWrapper.propTypes = {
stepperTitle: Proptypes.string,
};

ContentHighlightStepperWrapper.defaultProps = {
stepperTitle: '',
};

describe('<ContentHighlightStepper>', () => {
it('Displays the stepper', () => {
render(<ContentHighlightStepperWrapper />);
Expand All @@ -30,26 +45,34 @@ describe('<ContentHighlightStepper>', () => {
expect(screen.getByText(STEPPER_STEP_TEXT.createTitle)).toBeInTheDocument();
});
it('Displays the stepper and test all back and next buttons', () => {
render(<ContentHighlightStepperWrapper />);
render(<ContentHighlightStepperWrapper stepperTitle="test-title" />);

// 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();
Expand All @@ -66,7 +89,7 @@ describe('<ContentHighlightStepper>', () => {
expect(screen.getByText('Click Me')).toBeInTheDocument();
});
it('Displays the stepper and closes the stepper on confirm', () => {
render(<ContentHighlightStepperWrapper />);
render(<ContentHighlightStepperWrapper stepperTitle="test-title" />);

const stepper = screen.getByText('Click Me');
fireEvent.click(stepper);
Expand Down
12 changes: 9 additions & 3 deletions src/components/ContentHighlights/data/hooks.js
Original file line number Diff line number Diff line change
@@ -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,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down