From 861b47b772ec31ffb17e69613199ef817ad78992 Mon Sep 17 00:00:00 2001 From: Jesper Hodge <19345795+jesperhodge@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:28:14 -0500 Subject: [PATCH] feat add olx solution support (#225) This adds support for the tag in OLX and maps it to the description in the settings options on the ShowAnswer card. https://2u-internal.atlassian.net/browse/TNL-10397 --- .gitignore | 3 + .../SettingsWidget/CardSection.jsx | 43 ++++++++ .../SettingsWidget/CardSection.test.jsx | 12 +++ .../SettingsWidget/SettingsOption.jsx | 60 ++++++------ .../SettingsWidget/SettingsOption.test.jsx | 17 +++- .../__snapshots__/CardSection.test.jsx.snap | 34 +++++++ .../SettingsOption.test.jsx.snap | 97 +++++++++++++------ .../EditProblemView/SettingsWidget/hooks.js | 14 ++- .../SettingsWidget/hooks.test.js | 9 +- .../EditProblemView/SettingsWidget/index.jsx | 6 +- .../SettingsWidget/messages.js | 10 ++ .../settingsComponents/ShowAnswerCard.jsx | 53 +++++++--- .../ShowAnswerCard.test.jsx | 16 +-- .../__snapshots__/HintsCard.test.jsx.snap | 3 + .../__snapshots__/MatlabCard.test.jsx.snap | 2 + .../__snapshots__/ResetCard.test.jsx.snap | 4 +- .../__snapshots__/ScoringCard.test.jsx.snap | 6 +- .../ShowAnswerCard.test.jsx.snap | 38 +++++++- .../__snapshots__/TimerCard.test.jsx.snap | 2 +- .../__snapshots__/TypeCard.test.jsx.snap | 2 +- .../ProblemEditor/data/OLXParser.js | 62 +++++++++--- .../ProblemEditor/data/OLXParser.test.js | 34 +++++-- .../ProblemEditor/data/ReactStateOLXParser.js | 22 +++++ .../data/ReactStateOLXParser.test.js | 6 +- .../data/mockData/olxTestData.js | 97 ++++++++++++------- src/editors/data/redux/problem/reducers.js | 1 + 26 files changed, 493 insertions(+), 160 deletions(-) create mode 100644 src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.jsx create mode 100644 src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/CardSection.test.jsx.snap diff --git a/.gitignore b/.gitignore index d10bc1963..ef085bb6d 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,6 @@ dist ### local overrides ### module.config.js + +### Code editors ### +.vscode \ No newline at end of file diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.jsx new file mode 100644 index 000000000..de0b37b10 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { Collapsible, Card } from '@edx/paragon'; +import { + bool, string, node, +} from 'prop-types'; + +const CardSection = ({ + children, none, isCardCollapsibleOpen, summary, +}) => { + const show = isCardCollapsibleOpen || summary; + if (!show) { return null; } + + return ( + + + + {summary} + + + + + {children} + + + + ); +}; +CardSection.propTypes = { + none: bool, + children: node.isRequired, + summary: string, + isCardCollapsibleOpen: bool.isRequired, +}; +CardSection.defaultProps = { + none: false, + summary: null, +}; + +export default CardSection; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.test.jsx new file mode 100644 index 000000000..5d3dd8a37 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/CardSection.test.jsx @@ -0,0 +1,12 @@ +import { shallow } from 'enzyme'; +import CardSection from './CardSection'; + +describe('CardSection', () => { + test('open', () => { + expect(shallow(

Section Text

)).toMatchSnapshot(); + }); + + test('closed', () => { + expect(shallow(

Section Text

)).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx index 8efba552a..0bf304d2c 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx @@ -1,23 +1,22 @@ import React from 'react'; import { Collapsible, Icon, Card } from '@edx/paragon'; import { KeyboardArrowUp, KeyboardArrowDown } from '@edx/paragon/icons'; -import PropTypes from 'prop-types'; +import { + arrayOf, shape, string, node, +} from 'prop-types'; import { showFullCard } from './hooks'; +import CardSection from './CardSection'; export const SettingsOption = ({ - title, - summary, - none, - children, - className, + title, className, extraSections, children, summary, ...passThroughProps }) => { - const { isCardCollapsed, toggleCardCollapse } = showFullCard(); + const { isCardCollapsibleOpen, toggleCardCollapse } = showFullCard(); return ( - + @@ -31,36 +30,33 @@ export const SettingsOption = ({ - - - - {summary} - - - - - {children} - - - + + {children} + + {extraSections.map((section, index) => ( + <> + {isCardCollapsibleOpen &&
} + {/* eslint-disable-next-line react/no-array-index-key */} + + {section.children} + + + ))}
); }; - SettingsOption.propTypes = { - title: PropTypes.string.isRequired, - summary: PropTypes.string.isRequired, - none: PropTypes.bool, - className: PropTypes.string, - children: PropTypes.node.isRequired, + title: string.isRequired, + children: node.isRequired, + className: string, + summary: string.isRequired, + extraSections: arrayOf(shape({ + children: node, + })), }; SettingsOption.defaultProps = { - none: false, className: '', + extraSections: [], }; export default SettingsOption; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.test.jsx index ff53a6979..dd53fd12d 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.test.jsx @@ -3,10 +3,21 @@ import { shallow } from 'enzyme'; import SettingsOption from './SettingsOption'; describe('SettingsOption', () => { - describe('render', () => { - const testContent = (

My test content

); + describe('default with children', () => { + const children = (

My test content

); test('snapshot: renders correct', () => { - expect(shallow({testContent})).toMatchSnapshot(); + expect(shallow({children})).toMatchSnapshot(); + }); + }); + describe('with additional sections', () => { + const children = (

First Section

); + const sections = [

Second Section

,

Third Section

]; + test('snapshot: renders correct', () => { + expect(shallow( + + {children} + , + )).toMatchSnapshot(); }); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/CardSection.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/CardSection.test.jsx.snap new file mode 100644 index 000000000..e4aaeef38 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/CardSection.test.jsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CardSection closed 1`] = `""`; + +exports[`CardSection open 1`] = ` + + + + + summary + + + + + +

+ Section Text +

+ +
+
+`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/SettingsOption.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/SettingsOption.test.jsx.snap index 399359e7a..3699736bd 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/SettingsOption.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/SettingsOption.test.jsx.snap @@ -1,11 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`SettingsOption render snapshot: renders correct 1`] = ` +exports[`SettingsOption default with children snapshot: renders correct 1`] = ` - - - - - Settings Option Summary - - - - - -

- My test content -

- -
-
+

+ My test content +

+ +
+`; + +exports[`SettingsOption with additional sections snapshot: renders correct 1`] = ` + + + + + + Settings Option Title + + + + + + + + + + + +

+ First Section +

+
+ +
`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js index 92072b309..ca5b9ef18 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js @@ -21,10 +21,10 @@ export const showAdvancedSettingsCards = () => { }; export const showFullCard = () => { - const [isCardCollapsed, setIsCardCollapsed] = module.state.cardCollapsed(false); + const [isCardCollapsibleOpen, setIsCardCollapsibleOpen] = module.state.cardCollapsed(false); return { - isCardCollapsed, - toggleCardCollapse: () => setIsCardCollapsed(!isCardCollapsed), + isCardCollapsibleOpen, + toggleCardCollapse: () => setIsCardCollapsibleOpen(!isCardCollapsibleOpen), }; }; @@ -147,8 +147,9 @@ export const scoringCardHooks = (scoring, updateSettings) => { }; }; -export const showAnswerCardHooks = (showAnswer, updateSettings) => { +export const useAnswerSettings = (showAnswer, updateSettings) => { const [showAttempts, setShowAttempts] = module.state.showAttempts(false); + const numberOfAttemptsChoice = [ ShowAnswerTypesKeys.AFTER_SOME_NUMBER_OF_ATTEMPTS, ShowAnswerTypesKeys.AFTER_ALL_ATTEMPTS, @@ -173,9 +174,14 @@ export const showAnswerCardHooks = (showAnswer, updateSettings) => { updateSettings({ showAnswer: { ...showAnswer, afterAttempts: attempts } }); }; + const handleExplanationChange = (event) => { + updateSettings({ solutionExplanation: event.target.value }); + }; + return { handleShowAnswerChange, handleAttemptsChange, + handleExplanationChange, showAttempts, }; }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js index bf23778b5..8f907c4a1 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js @@ -53,7 +53,7 @@ describe('Problem settings hooks', () => { output = hooks.showFullCard(); }); test('test default state is false', () => { - expect(output.isCardCollapsed).toBeFalsy(); + expect(output.isCardCollapsibleOpen).toBeFalsy(); }); test('test toggleCardCollapse to true', () => { output.toggleCardCollapse(); @@ -220,7 +220,7 @@ describe('Problem settings hooks', () => { afterAttempts: 5, }; beforeEach(() => { - output = hooks.showAnswerCardHooks(showAnswer, updateSettings); + output = hooks.useAnswerSettings(showAnswer, updateSettings); }); test('test handleShowAnswerChange', () => { const value = 'always'; @@ -232,6 +232,11 @@ describe('Problem settings hooks', () => { output.handleAttemptsChange({ target: { value } }); expect(updateSettings).toHaveBeenCalledWith({ showAnswer: { ...showAnswer, afterAttempts: parseInt(value) } }); }); + test('handleExplanationChange should update settings', () => { + const value = 'explanation'; + output.handleExplanationChange({ target: { value } }); + expect(updateSettings).toHaveBeenCalledWith({ solutionExplanation: value }); + }); }); describe('Timer card hooks', () => { diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx index b2caf9a8d..229363a32 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx @@ -67,7 +67,11 @@ export const SettingsWidget = ({
- +
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js index f8bf23431..09a6007cf 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js @@ -194,6 +194,16 @@ export const messages = { defaultMessage: 'Switch To Advanced Editor', description: 'message to confirm that a user wants to use the advanced editor', }, + explanationInputLabel: { + id: 'authoring.problemeditor.settings.showAnswer.explanation.inputLabel', + defaultMessage: 'Explanation', + description: 'answer explanation input label', + }, + explanationSettingText: { + id: 'authoring.problemeditor.settings.showAnswer.explanation.text', + defaultMessage: 'Provide an explanation for the correct answer.', + description: 'Solution Explanation text', + }, }; export default messages; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx index cdd8186ac..4a8c9cc56 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx @@ -7,10 +7,11 @@ import SettingsOption from '../SettingsOption'; import { ShowAnswerTypes, ShowAnswerTypesKeys } from '../../../../../../data/constants/problem'; import { selectors } from '../../../../../../data/redux'; import messages from '../messages'; -import { showAnswerCardHooks } from '../hooks'; +import { useAnswerSettings } from '../hooks'; export const ShowAnswerCard = ({ showAnswer, + solutionExplanation, updateSettings, // inject intl, @@ -21,24 +22,23 @@ export const ShowAnswerCard = ({ const { handleShowAnswerChange, handleAttemptsChange, + handleExplanationChange, showAttempts, - } = showAnswerCardHooks(showAnswer, updateSettings); - return ( - -
+ } = useAnswerSettings(showAnswer, updateSettings); + + const showAnswerSection = ( + <> +
-
+
- + {showAttempts && ( - + )} + + ); + + const explanationSection = ( + <> +
+ + + +
+ + + + + ); + + return ( + + {showAnswerSection} ); }; @@ -73,10 +100,14 @@ ShowAnswerCard.propTypes = { intl: intlShape.isRequired, // eslint-disable-next-line showAnswer: PropTypes.any.isRequired, + solutionExplanation: PropTypes.string, updateSettings: PropTypes.func.isRequired, studioEndpointUrl: PropTypes.string.isRequired, learningContextId: PropTypes.string.isRequired, }; +ShowAnswerCard.defaultProps = { + solutionExplanation: '', +}; export const mapStateToProps = (state) => ({ studioEndpointUrl: selectors.app.studioEndpointUrl(state), diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx index 63d2e2bfe..c4c5652e4 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx @@ -3,10 +3,10 @@ import { shallow } from 'enzyme'; import { formatMessage } from '../../../../../../../testUtils'; import { selectors } from '../../../../../../data/redux'; import { ShowAnswerCard, mapStateToProps, mapDispatchToProps } from './ShowAnswerCard'; -import { showAnswerCardHooks } from '../hooks'; +import { useAnswerSettings } from '../hooks'; jest.mock('../hooks', () => ({ - showAnswerCardHooks: jest.fn(), + useAnswerSettings: jest.fn(), })); jest.mock('../../../../../../data/redux', () => ({ @@ -34,17 +34,17 @@ describe('ShowAnswerCard', () => { learningContextId: 'sOMEcouRseId', }; - const showAnswerCardHooksProps = { - handleShowAnswerChange: jest.fn().mockName('showAnswerCardHooks.handleShowAnswerChange'), - handleAttemptsChange: jest.fn().mockName('showAnswerCardHooks.handleAttemptsChange'), + const useAnswerSettingsProps = { + handleShowAnswerChange: jest.fn().mockName('useAnswerSettings.handleShowAnswerChange'), + handleAttemptsChange: jest.fn().mockName('useAnswerSettings.handleAttemptsChange'), }; - showAnswerCardHooks.mockReturnValue(showAnswerCardHooksProps); + useAnswerSettings.mockReturnValue(useAnswerSettingsProps); describe('behavior', () => { - it(' calls showAnswerCardHooks when initialized', () => { + it(' calls useAnswerSettings when initialized', () => { shallow(); - expect(showAnswerCardHooks).toHaveBeenCalledWith(showAnswer, props.updateSettings); + expect(useAnswerSettings).toHaveBeenCalledWith(showAnswer, props.updateSettings); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap index abecf5039..6a3700a8c 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap @@ -3,6 +3,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints 1`] = ` @@ -65,7 +65,7 @@ exports[`ResetCard snapshot snapshot: renders reset true setting card 1`] = ` exports[`ResetCard snapshot snapshot: renders reset true setting card 2`] = ` diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ScoringCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ScoringCard.test.jsx.snap index 6a28aa416..397b39802 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ScoringCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ScoringCard.test.jsx.snap @@ -3,7 +3,7 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = ` @@ -52,7 +52,7 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = ` exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] = ` @@ -101,7 +101,7 @@ exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] = exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`] = ` diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ShowAnswerCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ShowAnswerCard.test.jsx.snap index 18ebdbb3d..d16dbc7d8 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ShowAnswerCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/ShowAnswerCard.test.jsx.snap @@ -3,12 +3,38 @@ exports[`ShowAnswerCard snapshot snapshot: show answer setting card 1`] = ` +
+ + + +
+ + + + , + }, + ] + } summary="After Some Number of Attempts" title="Show answer" >
- +