fix: separate feedback onchange for each field (#214)
This commit is contained in:
@@ -28,6 +28,8 @@ export const AnswerOption = ({
|
||||
const dispatch = useDispatch();
|
||||
const removeAnswer = hooks.removeAnswer({ answer, dispatch });
|
||||
const setAnswer = hooks.setAnswer({ answer, hasSingleAnswer, dispatch });
|
||||
const setSelectedFeedback = hooks.setSelectedFeedback({ answer, hasSingleAnswer, dispatch });
|
||||
const setUnselectedFeedback = hooks.setUnselectedFeedback({ answer, hasSingleAnswer, dispatch });
|
||||
const { isFeedbackVisible, toggleFeedback } = hooks.useFeedback(answer);
|
||||
|
||||
return (
|
||||
@@ -57,7 +59,8 @@ export const AnswerOption = ({
|
||||
<FeedbackBox
|
||||
problemType={problemType}
|
||||
answer={answer}
|
||||
setAnswer={setAnswer}
|
||||
setSelectedFeedback={setSelectedFeedback}
|
||||
setUnselectedFeedback={setUnselectedFeedback}
|
||||
intl={intl}
|
||||
/>
|
||||
</Collapsible.Body>
|
||||
|
||||
@@ -50,7 +50,8 @@ exports[`AnswerOption render snapshot: renders correct option with feedback 1`]
|
||||
}
|
||||
}
|
||||
problemType="multiplechoiceresponse"
|
||||
setAnswer={[Function]}
|
||||
setSelectedFeedback={[Function]}
|
||||
setUnselectedFeedback={[Function]}
|
||||
/>
|
||||
</Body>
|
||||
</div>
|
||||
@@ -126,7 +127,8 @@ exports[`AnswerOption render snapshot: renders correct option with selected unse
|
||||
}
|
||||
}
|
||||
problemType="choiceresponse"
|
||||
setAnswer={[Function]}
|
||||
setSelectedFeedback={[Function]}
|
||||
setUnselectedFeedback={[Function]}
|
||||
/>
|
||||
</Body>
|
||||
</div>
|
||||
|
||||
@@ -7,10 +7,12 @@ import FeedbackControl from './FeedbackControl';
|
||||
import { messages } from './messages';
|
||||
|
||||
export const FeedbackBox = ({
|
||||
answer, setAnswer, intl,
|
||||
answer,
|
||||
intl,
|
||||
setSelectedFeedback,
|
||||
setUnselectedFeedback,
|
||||
}) => {
|
||||
const props = {
|
||||
onChange: (e) => setAnswer({ selectedFeedback: e.target.value }),
|
||||
answer,
|
||||
intl,
|
||||
};
|
||||
@@ -22,6 +24,7 @@ export const FeedbackBox = ({
|
||||
feedback={answer.selectedFeedback}
|
||||
labelMessage={messages.selectedFeedbackLabel}
|
||||
labelMessageBoldUnderline={messages.selectedFeedbackLabelBoldUnderlineText}
|
||||
onChange={setSelectedFeedback}
|
||||
{...props}
|
||||
/>
|
||||
<FeedbackControl
|
||||
@@ -29,6 +32,7 @@ export const FeedbackBox = ({
|
||||
feedback={answer.unselectedFeedback}
|
||||
labelMessage={messages.unSelectedFeedbackLabel}
|
||||
labelMessageBoldUnderline={messages.unSelectedFeedbackLabelBoldUnderlineText}
|
||||
onChange={setUnselectedFeedback}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
@@ -37,6 +41,8 @@ export const FeedbackBox = ({
|
||||
FeedbackBox.propTypes = {
|
||||
answer: answerOptionProps.isRequired,
|
||||
setAnswer: PropTypes.func.isRequired,
|
||||
setSelectedFeedback: PropTypes.func.isRequired,
|
||||
setUnselectedFeedback: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ const answerWithFeedback = {
|
||||
const props = {
|
||||
answer: answerWithFeedback,
|
||||
intl: {},
|
||||
setAnswer: jest.fn(),
|
||||
};
|
||||
|
||||
describe('FeedbackBox component', () => {
|
||||
|
||||
@@ -31,7 +31,6 @@ exports[`FeedbackBox component renders 1`] = `
|
||||
"id": "authoring.answerwidget.feedback.selected.label.boldunderline",
|
||||
}
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<FeedbackControl
|
||||
answer={
|
||||
@@ -60,7 +59,6 @@ exports[`FeedbackBox component renders 1`] = `
|
||||
"id": "authoring.answerwidget.feedback.unselected.label.boldunderline",
|
||||
}
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -9,24 +9,40 @@ export const state = StrictDict({
|
||||
});
|
||||
|
||||
export const removeAnswer = ({ answer, dispatch }) => () => {
|
||||
dispatch(actions.problem.deleteAnswer({ id: answer.id }));
|
||||
dispatch(actions.problem.deleteAnswer({ id: answer.id, correct: answer.correct }));
|
||||
};
|
||||
|
||||
export const setAnswer = ({ answer, hasSingleAnswer, dispatch }) => (payload) => {
|
||||
dispatch(actions.problem.updateAnswer({ id: answer.id, hasSingleAnswer, ...payload }));
|
||||
};
|
||||
|
||||
export const setSelectedFeedback = ({ answer, hasSingleAnswer, dispatch }) => (e) => {
|
||||
dispatch(actions.problem.updateAnswer({
|
||||
id: answer.id,
|
||||
hasSingleAnswer,
|
||||
selectedFeedback: e.target.value,
|
||||
}));
|
||||
};
|
||||
|
||||
export const setUnselectedFeedback = ({ answer, hasSingleAnswer, dispatch }) => (e) => {
|
||||
dispatch(actions.problem.updateAnswer({
|
||||
id: answer.id,
|
||||
hasSingleAnswer,
|
||||
unselectedFeedback: e.target.value,
|
||||
}));
|
||||
};
|
||||
|
||||
export const useFeedback = (answer) => {
|
||||
const [isFeedbackVisible, setIsFeedbackVisible] = module.state.isFeedbackVisible(false);
|
||||
useEffect(() => {
|
||||
// Show feedback fields if feedback is present
|
||||
const isVisible = !!answer.selectedFeedback || !!answer.unselectedFeedback || !!answer.feedback;
|
||||
const isVisible = !!answer.selectedFeedback || !!answer.unselectedFeedback;
|
||||
setIsFeedbackVisible(isVisible);
|
||||
}, [answer]);
|
||||
|
||||
const toggleFeedback = (open) => {
|
||||
// Do not allow to hide if feedback is added
|
||||
if (!!answer.selectedFeedback || !!answer.unselectedFeedback || !!answer.feedback) {
|
||||
if (!!answer.selectedFeedback || !!answer.unselectedFeedback) {
|
||||
setIsFeedbackVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { actions } from '../../../../../data/redux';
|
||||
import { MockUseState } from '../../../../../../testUtils';
|
||||
import { ProblemTypeKeys } from '../../../../../data/constants/problem';
|
||||
import * as module from './hooks';
|
||||
@@ -28,7 +31,7 @@ const answerWithOnlyFeedback = {
|
||||
id: 'A',
|
||||
title: 'Answer 1',
|
||||
correct: true,
|
||||
feedback: 'some feedback',
|
||||
selectedFeedback: 'some feedback',
|
||||
};
|
||||
|
||||
describe('Answer Options Hooks', () => {
|
||||
@@ -36,6 +39,59 @@ describe('Answer Options Hooks', () => {
|
||||
describe('state hooks', () => {
|
||||
state.testGetter(state.keys.isFeedbackVisible);
|
||||
});
|
||||
describe('removeAnswer', () => {
|
||||
test('it dispatches actions.problem.deleteAnswer', () => {
|
||||
const answer = { id: 'A', correct: false };
|
||||
const dispatch = useDispatch();
|
||||
module.removeAnswer({ answer, dispatch })();
|
||||
expect(dispatch).toHaveBeenCalledWith(actions.problem.deleteAnswer({
|
||||
id: answer.id,
|
||||
correct: answer.correct,
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('setAnswer', () => {
|
||||
test('it dispatches actions.problem.updateAnswer', () => {
|
||||
const answer = { id: 'A' };
|
||||
const hasSingleAnswer = false;
|
||||
const dispatch = useDispatch();
|
||||
const payload = { random: 'string' };
|
||||
module.setAnswer({ answer, hasSingleAnswer, dispatch })(payload);
|
||||
expect(dispatch).toHaveBeenCalledWith(actions.problem.updateAnswer({
|
||||
id: answer.id,
|
||||
hasSingleAnswer,
|
||||
...payload,
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('setSelectedFeedback', () => {
|
||||
test('it dispatches actions.problem.updateAnswer', () => {
|
||||
const answer = { id: 'A' };
|
||||
const hasSingleAnswer = false;
|
||||
const dispatch = useDispatch();
|
||||
const e = { target: { value: 'string' } };
|
||||
module.setSelectedFeedback({ answer, hasSingleAnswer, dispatch })(e);
|
||||
expect(dispatch).toHaveBeenCalledWith(actions.problem.updateAnswer({
|
||||
id: answer.id,
|
||||
hasSingleAnswer,
|
||||
selectedFeedback: e.target.value,
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('setUnselectedFeedback', () => {
|
||||
test('it dispatches actions.problem.updateAnswer', () => {
|
||||
const answer = { id: 'A' };
|
||||
const hasSingleAnswer = false;
|
||||
const dispatch = useDispatch();
|
||||
const e = { target: { value: 'string' } };
|
||||
module.setUnselectedFeedback({ answer, hasSingleAnswer, dispatch })(e);
|
||||
expect(dispatch).toHaveBeenCalledWith(actions.problem.updateAnswer({
|
||||
id: answer.id,
|
||||
hasSingleAnswer,
|
||||
unselectedFeedback: e.target.value,
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('useFeedback hook', () => {
|
||||
beforeEach(() => { state.mock(); });
|
||||
afterEach(() => { state.restore(); });
|
||||
@@ -2,7 +2,7 @@ import _ from 'lodash-es';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { indexToLetterMap } from '../../../containers/ProblemEditor/data/OLXParser';
|
||||
import { StrictDict } from '../../../utils';
|
||||
import { ProblemTypeKeys, ShowAnswerTypesKeys } from '../../constants/problem';
|
||||
import { ShowAnswerTypesKeys } from '../../constants/problem';
|
||||
|
||||
const nextAlphaId = (lastId) => String.fromCharCode(lastId.charCodeAt(0) + 1);
|
||||
const initialState = {
|
||||
@@ -103,14 +103,11 @@ const problem = createSlice({
|
||||
const newOption = {
|
||||
id: currAnswers.length ? nextAlphaId(currAnswers[currAnswers.length - 1].id) : 'A',
|
||||
title: '',
|
||||
selectedFeedback: undefined,
|
||||
unselectedFeedback: undefined,
|
||||
selectedFeedback: '',
|
||||
unselectedFeedback: '',
|
||||
correct: false,
|
||||
};
|
||||
if (state.problemType === ProblemTypeKeys.MULTISELECT) {
|
||||
newOption.unselectedFeedback = '';
|
||||
}
|
||||
newOption.selectedFeedback = '';
|
||||
|
||||
const answers = [
|
||||
...currAnswers,
|
||||
newOption,
|
||||
|
||||
@@ -26,6 +26,14 @@ describe('problem reducer', () => {
|
||||
[
|
||||
['updateQuestion', 'question'],
|
||||
].map(args => setterTest(...args));
|
||||
describe('setEnableTypeSelection', () => {
|
||||
it('sets given problemType to null', () => {
|
||||
expect(reducer(testingState, actions.setEnableTypeSelection())).toEqual({
|
||||
...testingState,
|
||||
problemType: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('load', () => {
|
||||
it('sets answers', () => {
|
||||
const answer = {
|
||||
@@ -33,7 +41,7 @@ describe('problem reducer', () => {
|
||||
correct: false,
|
||||
selectedFeedback: '',
|
||||
title: '',
|
||||
unselectedFeedback: undefined,
|
||||
unselectedFeedback: '',
|
||||
};
|
||||
expect(reducer(testingState, actions.addAnswer(answer))).toEqual({
|
||||
...testingState,
|
||||
@@ -99,7 +107,7 @@ describe('problem reducer', () => {
|
||||
});
|
||||
describe('deleteAnswer', () => {
|
||||
it('sets answers, as well as setting the correctAnswerCount ', () => {
|
||||
const answer = { id: 'A' };
|
||||
const answer = { id: 'A', correct: false };
|
||||
expect(reducer(
|
||||
{
|
||||
...testingState,
|
||||
|
||||
Reference in New Issue
Block a user