diff --git a/src/skills-builder/data/actions.js b/src/skills-builder/data/actions.js index a77db82..b4df8c9 100644 --- a/src/skills-builder/data/actions.js +++ b/src/skills-builder/data/actions.js @@ -1,9 +1,26 @@ import { SET_GOAL, + SET_CURRENT_JOB_TITLE, + ADD_CAREER_INTEREST, + REMOVE_CAREER_INTEREEST, } from './constants'; -// eslint-disable-next-line import/prefer-default-export export const setGoal = (payload) => ({ type: SET_GOAL, payload, }); + +export const setCurrentJobTitle = (payload) => ({ + type: SET_CURRENT_JOB_TITLE, + payload, +}); + +export const addCareerInterest = (payload) => ({ + type: ADD_CAREER_INTEREST, + payload, +}); + +export const removeCareerInterest = (payload) => ({ + type: REMOVE_CAREER_INTEREEST, + payload, +}); diff --git a/src/skills-builder/data/constants.js b/src/skills-builder/data/constants.js index fcd3d81..5d801c6 100644 --- a/src/skills-builder/data/constants.js +++ b/src/skills-builder/data/constants.js @@ -1,2 +1,7 @@ -// eslint-disable-next-line import/prefer-default-export export const SET_GOAL = 'SET_GOAL'; +export const SET_CURRENT_JOB_TITLE = 'SET_CURRENT_JOB_TITLE'; +export const ADD_CAREER_INTEREST = 'ADD_CAREER_INTEREST'; +export const REMOVE_CAREER_INTEREEST = 'REMOVE_CAREER_INTEREEST'; + +export const STEP1 = 'select-your-preferences'; +export const STEP2 = 'review-your-results'; diff --git a/src/skills-builder/data/reducer.js b/src/skills-builder/data/reducer.js index 0db2ae5..6f6af67 100644 --- a/src/skills-builder/data/reducer.js +++ b/src/skills-builder/data/reducer.js @@ -1,5 +1,8 @@ import { SET_GOAL, + SET_CURRENT_JOB_TITLE, + ADD_CAREER_INTEREST, + REMOVE_CAREER_INTEREEST, } from './constants'; export function skillsReducer(state, action) { @@ -9,6 +12,21 @@ export function skillsReducer(state, action) { ...state, currentGoal: action.payload, }; + case SET_CURRENT_JOB_TITLE: + return { + ...state, + currentJobTitle: action.payload, + }; + case ADD_CAREER_INTEREST: + return { + ...state, + careerInterests: [...state.careerInterests, action.payload], + }; + case REMOVE_CAREER_INTEREEST: + return { + ...state, + careerInterests: state.careerInterests.filter(interest => interest !== action.payload), + }; default: return state; } @@ -16,6 +34,8 @@ export function skillsReducer(state, action) { export const skillsInitialState = { currentGoal: '', + currentJobTitle: '', + careerInterests: [], }; export default skillsReducer; diff --git a/src/skills-builder/data/test/reducer.test.js b/src/skills-builder/data/test/reducer.test.js index 4f537fe..0cfbb3c 100644 --- a/src/skills-builder/data/test/reducer.test.js +++ b/src/skills-builder/data/test/reducer.test.js @@ -1,20 +1,60 @@ -import { skillsReducer } from '../reducer'; +import { skillsReducer, skillsInitialState } from '../reducer'; import { SET_GOAL, + SET_CURRENT_JOB_TITLE, + ADD_CAREER_INTEREST, + REMOVE_CAREER_INTEREEST, } from '../constants'; describe('skillsReducer', () => { - const testState = { - currentGoal: '', - }; + const testState = skillsInitialState; + beforeEach(() => jest.resetModules()); it('does not remove present data when SET_GOAL action is dispatched', () => { - const newSkillsPayload = 'test-goal'; - const returnedState = skillsReducer(testState, { type: SET_GOAL, payload: newSkillsPayload }); + const newGoalPayload = 'test-goal'; + const returnedState = skillsReducer(testState, { type: SET_GOAL, payload: newGoalPayload }); const finalState = { ...testState, currentGoal: 'test-goal', }; expect(returnedState).toEqual(finalState); }); + + it('does not remove present data when SET_JOB_TITLE action is dispatched', () => { + const newJobTitlePayload = 'test-job-title'; + const returnedState = skillsReducer(testState, { type: SET_CURRENT_JOB_TITLE, payload: newJobTitlePayload }); + const finalState = { + ...testState, + currentJobTitle: 'test-job-title', + }; + expect(returnedState).toEqual(finalState); + }); + + it('adds a careerInterest when ADD_CAREER_INTEREST action is dispatched', () => { + const newCareerInterestPayload = 'test-career-interest'; + const returnedState = skillsReducer(testState, { type: ADD_CAREER_INTEREST, payload: newCareerInterestPayload }); + const finalState = { + ...testState, + careerInterests: [...testState.careerInterests, 'test-career-interest'], + }; + expect(returnedState).toEqual(finalState); + }); + + it('removes a careerInterest when REMOVE_CAREER_INTEREST action is dispatched', () => { + const newCareerInterestPayload = 'test-career-interest'; + const testStateWithInterest = { + ...testState, + careerInterests: [newCareerInterestPayload], + }; + const returnedState = skillsReducer( + testStateWithInterest, + { type: REMOVE_CAREER_INTEREEST, payload: newCareerInterestPayload }, + ); + const finalState = { + ...testStateWithInterest, + // override the 'careerInterests` field and remove 'test-career-interest' from the array + careerInterests: testStateWithInterest.careerInterests.filter(interest => interest !== newCareerInterestPayload), + }; + expect(returnedState).toEqual(finalState); + }); }); diff --git a/src/skills-builder/skills-builder-modal/SelectPreferences.jsx b/src/skills-builder/skills-builder-modal/SelectPreferences.jsx new file mode 100644 index 0000000..d51ccf5 --- /dev/null +++ b/src/skills-builder/skills-builder-modal/SelectPreferences.jsx @@ -0,0 +1,63 @@ +import React, { useContext } from 'react'; +import { + Button, +} from '@edx/paragon'; +import { + setGoal, + setCurrentJobTitle, + addCareerInterest, + removeCareerInterest, +} from '../data/actions'; +import { SkillsBuilderContext } from '../skills-builder-context'; +import { useAlgoliaSearch } from '../utils/hooks'; + +const SelectPreferences = () => { + // TODO: Temporarily disable the no-unused-vars check, we'll see these later + // eslint-disable-next-line no-unused-vars + const [algoliaClient, productSearchIndex, jobSearchIndex] = useAlgoliaSearch(); + const [{ currentGoal, currentJobTitle, careerInterests }, dispatch] = useContext(SkillsBuilderContext); + + return ( + <> +
+

Render Question 1

+ +

Goal: {currentGoal}

+
+ + {currentGoal && ( +
+

Render question 2

+ +

Current Job Title: {currentJobTitle}

+
+ )} + + {currentJobTitle && ( +
+

Render Question 3

+ +

+ Career Interests (click to remove): + {careerInterests.map(interest => ( + + ))} +

+
+ )} + + ); +}; + +export default SelectPreferences; diff --git a/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx b/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx index 13bf2eb..eaee071 100644 --- a/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx +++ b/src/skills-builder/skills-builder-modal/SkillsBuilderModal.jsx @@ -1,79 +1,93 @@ -import React, { useContext, useState } from 'react'; +import React, { useState, useContext } from 'react'; import { - ActionRow, Button, Container, - Form, + Stepper, ModalDialog, } from '@edx/paragon'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { useHistory } from 'react-router'; import { - setGoal, -} from '../data/actions'; + STEP1, + STEP2, +} from '../data/constants'; import messages from './messages'; + import { SkillsBuilderContext } from '../skills-builder-context'; import { SkillsBuilderHeader } from '../skills-builder-header'; +import SelectPreferences from './SelectPreferences'; +import ViewResults from './ViewResults'; import headerImage from '../images/headerImage.png'; -import { useAlgoliaSearch } from '../utils/hooks'; - const SkillsBuilderModal = () => { - const [state, dispatch] = useContext(SkillsBuilderContext); - const [learnerGoal, setLearnerGoal] = useState(''); - // TODO: Temporarily disable the no-unused-vars check, we'll see these later - // eslint-disable-next-line no-unused-vars - const [algoliaClient, productSearchIndex, jobSearchIndex] = useAlgoliaSearch(); + const [{ careerInterests }] = useContext(SkillsBuilderContext); + const [currentStep, setCurrentStep] = useState(STEP1); + + const history = useHistory(); const onCloseHandle = () => { - window.history.back(); + history.goBack(); }; return ( - - - - - - - - - - - -

Your current goal: {state.currentGoal}

-
- - setLearnerGoal(e.target.value)} - /> - - -
-
- - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); }; diff --git a/src/skills-builder/skills-builder-modal/ViewResults.jsx b/src/skills-builder/skills-builder-modal/ViewResults.jsx new file mode 100644 index 0000000..3477aeb --- /dev/null +++ b/src/skills-builder/skills-builder-modal/ViewResults.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const ViewResults = () => ( +

Results will render on this step

+); + +export default ViewResults; diff --git a/src/skills-builder/skills-builder-modal/messages.js b/src/skills-builder/skills-builder-modal/messages.js index a4f053e..6938a8c 100644 --- a/src/skills-builder/skills-builder-modal/messages.js +++ b/src/skills-builder/skills-builder-modal/messages.js @@ -12,6 +12,11 @@ const messages = defineMessages({ defaultMessage: 'Next Step', description: 'Button that sends the user to the next step in the skills builder.', }, + exitButton: { + id: 'exit.button', + defaultMessage: 'Exit', + description: 'Button that exits the Skills Builder.', + }, }); export default messages;