diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/messages.js b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/messages.js
index d047f9552..bd2358fc7 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/messages.js
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/messages.js
@@ -56,5 +56,22 @@ const messages = defineMessages({
defaultMessage: 'is not selected',
description: 'Bold & underlined text for feedback if option is not selected',
},
+
+ addAnswerRangeButtonText: {
+ id: 'authoring.answerwidget.answer.addAnswerRangeButton',
+ defaultMessage: 'Add answer range',
+ description: 'Button text to add a range of answers',
+ },
+ answerRangeTextboxPlaceholder: {
+ id: 'authoring.answerwidget.answer.answerRangeTextboxPlaceholder',
+ defaultMessage: 'Enter an answer range',
+ description: 'Text to prompt the user to add an answer range to the textbox.',
+ },
+ answerRangeHelperText: {
+ id: 'authoring.answerwidget.answer.answerRangeHelperText',
+ defaultMessage: 'Enter min and max values separated by a comma. Use a bracket to include the number next to it in the range, or a parenthesis to exclude the number. For example, to identify the correct answers as 5, 6, or 7, but not 8, specify [5,8).',
+ description: 'Helper text describing usage of answer ranges',
+ },
});
+
export default messages;
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/Tolerance/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/Tolerance/index.jsx
index bda7efd3d..06929a34a 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/Tolerance/index.jsx
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/Tolerance/index.jsx
@@ -7,13 +7,10 @@ import messages from './messages';
import { ToleranceTypes } from './constants';
// eslint-disable-next-line no-unused-vars
-export const isAnswerRangeSet = ({ answers }) =>
- // TODO: for TNL 10258
- // eslint-disable-next-line implicit-arrow-linebreak
- false;
+export const isAnswerRangeSet = ({ answers }) => !!answers[0].isAnswerRange;
export const handleToleranceTypeChange = ({ updateSettings, tolerance, answers }) => (event) => {
- if (!isAnswerRangeSet(answers)) {
+ if (!isAnswerRangeSet({ answers })) {
let value;
if (event.target.value === ToleranceTypes.none.type) {
value = null;
@@ -26,7 +23,7 @@ export const handleToleranceTypeChange = ({ updateSettings, tolerance, answers }
};
export const handleToleranceValueChange = ({ updateSettings, tolerance, answers }) => (event) => {
- if (!isAnswerRangeSet(answers)) {
+ if (!isAnswerRangeSet({ answers })) {
const newTolerance = { value: event.target.value, type: tolerance.type };
updateSettings({ tolerance: newTolerance });
}
@@ -52,7 +49,7 @@ export const ToleranceCard = ({
// inject
intl,
}) => {
- const canEdit = isAnswerRangeSet({ answers });
+ const isAnswerRange = isAnswerRangeSet({ answers });
let summary = getSummary({ tolerance, intl });
useEffect(() => { summary = getSummary({ tolerance, intl }); }, [tolerance]);
return (
@@ -61,7 +58,7 @@ export const ToleranceCard = ({
summary={summary}
none={tolerance.type === ToleranceTypes.none.type}
>
- { canEdit
+ { isAnswerRange
&& (
{Object.keys(ToleranceTypes).map((toleranceType) => (
@@ -90,7 +87,7 @@ export const ToleranceCard = ({
))}
- { tolerance?.type !== ToleranceTypes.none.type && !canEdit
+ { tolerance?.type !== ToleranceTypes.none.type && !isAnswerRange
&& (
({
{children}
)),
Form: {
Control: jest.fn(({
- children, onChange, as, value,
+ children, onChange, as, value, disabled,
}) => {
if (as === 'select') {
- return ();
+ return ();
}
return ();
}),
@@ -49,7 +50,15 @@ describe('ToleranceCard', () => {
};
const props = {
- answers: [], // TODO: for TNL 10258
+ answers: [{
+ id: 'A',
+ correct: true,
+ selectedFeedback: '',
+ title: 'An Answer',
+ isAnswerRange: false,
+ unselectedFeedback: '',
+ },
+ ],
updateSettings: jest.fn(),
intl: {
formatMessage,
@@ -74,6 +83,32 @@ describe('ToleranceCard', () => {
const NumberText = screen.getByText(`± ${mockToleranceNumber.value}`);
expect(NumberText).toBeDefined();
});
+
+ it('If there is an answer range, show message and disable dropdown.', () => {
+ const rangeprops = {
+ answers: [{
+ id: 'A',
+ correct: true,
+ selectedFeedback: '',
+ title: 'An Answer',
+ isAnswerRange: true,
+ unselectedFeedback: '',
+ },
+ ],
+ updateSettings: jest.fn(),
+ intl: {
+ formatMessage,
+ },
+ };
+
+ render();
+ const NumberText = screen.getByText(messages.toleranceAnswerRangeWarning.defaultMessage);
+ expect(NumberText).toBeDefined();
+ expect(screen.getByTestId('select').getAttributeNames().includes('disabled')).toBeTruthy();
+ });
});
describe('Type Select', () => {
it('Renders the types for selection', async () => {
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap
index c22fd2c4c..e4f96de36 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap
@@ -40,7 +40,7 @@ exports[`EditorProblemView component renders simple view 1`] = `
className="editProblemView d-flex flex-row flex-nowrap justify-content-end"
>
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx
index 8258a84e4..1c9bdb49e 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx
@@ -40,7 +40,7 @@ export const EditProblemView = ({
) : (
-
+
diff --git a/src/editors/containers/ProblemEditor/data/OLXParser.js b/src/editors/containers/ProblemEditor/data/OLXParser.js
index 39b43ef71..ca4965bd4 100644
--- a/src/editors/containers/ProblemEditor/data/OLXParser.js
+++ b/src/editors/containers/ProblemEditor/data/OLXParser.js
@@ -263,7 +263,6 @@ export class OLXParser {
let answerFeedback = '';
const answers = [];
let responseParam = {};
- // TODO: UI needs to be added to support adding tolerence in numeric response.
const feedback = this.getFeedback(numericalresponse);
if (_.has(numericalresponse, 'responseparam')) {
const type = _.get(numericalresponse, 'responseparam.@_type');
@@ -272,11 +271,13 @@ export class OLXParser {
[type]: defaultValue,
};
}
+ const isAnswerRange = /[([]\d*,\d*[)\]]/gm.test(numericalresponse['@_answer']);
answers.push({
id: indexToLetterMap[answers.length],
title: numericalresponse['@_answer'],
correct: true,
selectedFeedback: feedback,
+ isAnswerRange,
...responseParam,
});
@@ -299,6 +300,7 @@ export class OLXParser {
title: additionalAnswer['@_answer'],
correct: true,
selectedFeedback: answerFeedback,
+ isAnswerRange: false,
});
}
return { answers };
diff --git a/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js b/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js
index 89bde5b7f..c2e534dee 100644
--- a/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js
+++ b/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js
@@ -351,12 +351,14 @@ export const numericInputWithFeedbackAndHintsOLX = {
title: '100',
correct: true,
selectedFeedback: 'You can specify optional feedback like this, which appears after this answer is submitted.
',
+ isAnswerRange: false,
tolerance: '5',
},
{
id: 'B',
title: '200',
correct: true,
+ isAnswerRange: false,
selectedFeedback: 'You can specify optional feedback like this, which appears after this answer is submitted.
',
},
],
diff --git a/src/editors/data/redux/problem/reducers.js b/src/editors/data/redux/problem/reducers.js
index 38aafa91e..5642f81e2 100644
--- a/src/editors/data/redux/problem/reducers.js
+++ b/src/editors/data/redux/problem/reducers.js
@@ -85,8 +85,24 @@ const problem = createSlice({
deleteAnswer: (state, { payload }) => {
const { id, correct } = payload;
if (state.answers.length <= 1) {
+ if (state.answers.length > 0 && state.answers[0].isAnswerRange) {
+ return {
+ ...state,
+ correctAnswerCount: 1,
+ answers: [{
+ id: 'A',
+ title: '',
+ selectedFeedback: '',
+ unselectedFeedback: '',
+ correct: state.problemType === ProblemTypeKeys.NUMERIC,
+ isAnswerRange: false,
+ },
+ ],
+ };
+ }
return state;
}
+
let { correctAnswerCount } = state;
if (correct) {
correctAnswerCount -= 1;
@@ -115,6 +131,7 @@ const problem = createSlice({
selectedFeedback: '',
unselectedFeedback: '',
correct: state.problemType === ProblemTypeKeys.NUMERIC,
+ isAnswerRange: false,
};
let { correctAnswerCount } = state;
if (state.problemType === ProblemTypeKeys.NUMERIC) {
@@ -131,6 +148,24 @@ const problem = createSlice({
answers,
};
},
+ addAnswerRange: (state) => {
+ // As you may only have one answer range at a time, overwrite the answer object.
+ const newOption = {
+ id: 'A',
+ title: '',
+ selectedFeedback: '',
+ unselectedFeedback: '',
+ correct: state.problemType === ProblemTypeKeys.NUMERIC,
+ isAnswerRange: true,
+ };
+ const correctAnswerCount = 1;
+ return {
+ ...state,
+ correctAnswerCount,
+ answers: [newOption],
+ };
+ },
+
updateSettings: (state, { payload }) => ({
...state,
settings: {
diff --git a/src/editors/data/redux/problem/reducers.test.js b/src/editors/data/redux/problem/reducers.test.js
index 2b3b003b7..4466eb852 100644
--- a/src/editors/data/redux/problem/reducers.test.js
+++ b/src/editors/data/redux/problem/reducers.test.js
@@ -56,6 +56,7 @@ describe('problem reducer', () => {
correct: false,
selectedFeedback: '',
title: '',
+ isAnswerRange: false,
unselectedFeedback: '',
};
expect(reducer(testingState, actions.addAnswer(answer))).toEqual({
@@ -91,6 +92,7 @@ describe('problem reducer', () => {
correct: false,
selectedFeedback: '',
title: '',
+ isAnswerRange: false,
unselectedFeedback: '',
};
it('sets answers', () => {
@@ -116,6 +118,26 @@ describe('problem reducer', () => {
});
});
});
+
+ describe('addAnswerRange', () => {
+ const answerRange = {
+ id: 'A',
+ correct: true,
+ selectedFeedback: '',
+ title: '',
+ isAnswerRange: true,
+ unselectedFeedback: '',
+ };
+ it('sets answerRange', () => {
+ expect(reducer({ ...testingState, problemType: ProblemTypeKeys.NUMERIC }, actions.addAnswerRange())).toEqual({
+ ...testingState,
+ correctAnswerCount: 1,
+ problemType: ProblemTypeKeys.NUMERIC,
+ answers: [answerRange],
+ });
+ });
+ });
+
describe('updateAnswer', () => {
it('sets answers, as well as setting the correctAnswerCount ', () => {
const answer = { id: 'A', correct: true };
@@ -162,6 +184,39 @@ describe('problem reducer', () => {
}],
});
});
+ it('if you delete an answer range, it will be replaced with a blank answer', () => {
+ const answer = {
+ id: 'A',
+ correct: true,
+ selectedFeedback: '',
+ title: '',
+ isAnswerRange: false,
+ unselectedFeedback: '',
+ };
+ const answerRange = {
+ id: 'A',
+ correct: false,
+ selectedFeedback: '',
+ title: '',
+ isAnswerRange: true,
+ unselectedFeedback: '',
+ };
+
+ expect(reducer(
+ {
+ ...testingState,
+ problemType: ProblemTypeKeys.NUMERIC,
+ correctAnswerCount: 1,
+ answers: [{ ...answerRange }],
+ },
+ actions.deleteAnswer(answer),
+ )).toEqual({
+ ...testingState,
+ problemType: ProblemTypeKeys.NUMERIC,
+ correctAnswerCount: 1,
+ answers: [{ ...answer }],
+ });
+ });
});
});
});