fix: separate local and static grade data
This commit is contained in:
@@ -29,7 +29,10 @@ export class CriterionFeedback extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
config, isGrading, value, valueIsInvalid,
|
||||
config,
|
||||
isGrading,
|
||||
value,
|
||||
valueIsInvalid,
|
||||
} = this.props;
|
||||
if (config === feedbackRequirement.disabled) {
|
||||
return null;
|
||||
@@ -57,7 +60,7 @@ export class CriterionFeedback extends React.Component {
|
||||
}
|
||||
|
||||
CriterionFeedback.defaultProps = {
|
||||
value: '',
|
||||
value: { local: '', review: '' },
|
||||
};
|
||||
|
||||
CriterionFeedback.propTypes = {
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('Criterion Feedback', () => {
|
||||
orderNum: 1,
|
||||
config: 'config string',
|
||||
isGrading: true,
|
||||
value: 'some value',
|
||||
value: { grading: 'grading value', review: 'review value' },
|
||||
gradeStatus: gradeStatuses.ungraded,
|
||||
setValue: jest.fn().mockName('this.props.setValue'),
|
||||
valueIsInvalid: false,
|
||||
|
||||
@@ -32,9 +32,10 @@ export class RadioCriterion extends React.Component {
|
||||
isGrading,
|
||||
radioIsInvalid,
|
||||
} = this.props;
|
||||
const value = isGrading ? data.grading : data.review;
|
||||
return (
|
||||
<>
|
||||
<Form.RadioSet name={config.name} value={data.selectedOption || ''}>
|
||||
<Form.RadioSet name={config.name} value={value}>
|
||||
{config.options.map((option) => (
|
||||
<Form.Radio
|
||||
className="criteria-option"
|
||||
@@ -60,8 +61,8 @@ export class RadioCriterion extends React.Component {
|
||||
|
||||
RadioCriterion.defaultProps = {
|
||||
data: {
|
||||
selectedOption: '',
|
||||
feedback: '',
|
||||
grading: '',
|
||||
review: '',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -86,8 +87,8 @@ RadioCriterion.propTypes = {
|
||||
),
|
||||
}).isRequired,
|
||||
data: PropTypes.shape({
|
||||
selectedOption: PropTypes.string,
|
||||
feedback: PropTypes.string,
|
||||
grading: PropTypes.string,
|
||||
review: PropTypes.string,
|
||||
}),
|
||||
setCriterionOption: PropTypes.func.isRequired,
|
||||
radioIsInvalid: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -18,8 +18,8 @@ jest.mock('data/redux/app/selectors', () => ({
|
||||
}));
|
||||
jest.mock('data/redux/grading/selectors', () => ({
|
||||
selected: {
|
||||
criterionGradeData: jest.fn((...args) => ({
|
||||
selectedCriterionGradeData: args,
|
||||
criterionSelectedOption: jest.fn((...args) => ({
|
||||
selectedCriterionSelectedOption: args,
|
||||
})),
|
||||
criterionSelectedIsInvalid: jest.fn((...args) => ({
|
||||
selectedCriterionSelectedIsInvalid: args,
|
||||
@@ -54,8 +54,8 @@ describe('Radio Criterion Container', () => {
|
||||
],
|
||||
},
|
||||
data: {
|
||||
selectedOption: 'selected option',
|
||||
feedback: 'data feedback',
|
||||
review: 'selected review option',
|
||||
grading: 'selected grading option',
|
||||
},
|
||||
setCriterionOption: jest.fn().mockName('this.props.setCriterionOption'),
|
||||
radioIsInvalid: false,
|
||||
@@ -142,9 +142,9 @@ describe('Radio Criterion Container', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('selectors.grading.selected.criterionGradeData', () => {
|
||||
test('selectors.grading.selected.criterionSelectedOption', () => {
|
||||
expect(mapped.data).toEqual(
|
||||
selectors.grading.selected.criterionGradeData(testState, ownProps),
|
||||
selectors.grading.selected.criterionSelectedOption(testState, ownProps),
|
||||
);
|
||||
});
|
||||
test('selectors.grading.selected.criterionSelectedIsInvalid', () => {
|
||||
|
||||
@@ -21,28 +21,4 @@ exports[`Criterion Feedback snapshot feedback value is invalid 1`] = `
|
||||
|
||||
exports[`Criterion Feedback snapshot is configure to disabled 1`] = `null`;
|
||||
|
||||
exports[`Criterion Feedback snapshot is graded 1`] = `
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
as="input"
|
||||
className="criterion-feedback feedback-input"
|
||||
disabled={true}
|
||||
floatingLabel="Comments"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
value="some value"
|
||||
/>
|
||||
</Form.Group>
|
||||
`;
|
||||
|
||||
exports[`Criterion Feedback snapshot is grading 1`] = `
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
as="input"
|
||||
className="criterion-feedback feedback-input"
|
||||
disabled={false}
|
||||
floatingLabel="Add comments"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
value="some value"
|
||||
/>
|
||||
</Form.Group>
|
||||
`;
|
||||
exports[`Criterion Feedback snapshot is graded 1`] = ``;
|
||||
|
||||
@@ -4,7 +4,7 @@ exports[`Radio Criterion Container snapshot is grading 1`] = `
|
||||
<React.Fragment>
|
||||
<Form.RadioSet
|
||||
name="random name"
|
||||
value="selected option"
|
||||
value="selected grading option"
|
||||
>
|
||||
<Form.Radio
|
||||
className="criteria-option"
|
||||
@@ -32,7 +32,7 @@ exports[`Radio Criterion Container snapshot is not grading 1`] = `
|
||||
<React.Fragment>
|
||||
<Form.RadioSet
|
||||
name="random name"
|
||||
value="selected option"
|
||||
value="selected review option"
|
||||
>
|
||||
<Form.Radio
|
||||
className="criteria-option"
|
||||
|
||||
@@ -56,7 +56,7 @@ export class RubricFeedback extends React.Component {
|
||||
as="input"
|
||||
className="rubric-feedback feedback-input"
|
||||
floatingLabel={this.inputLabel}
|
||||
value={value}
|
||||
value={isGrading ? value.grading : value.review}
|
||||
onChange={this.onChange}
|
||||
disabled={!isGrading}
|
||||
/>
|
||||
@@ -71,7 +71,7 @@ export class RubricFeedback extends React.Component {
|
||||
}
|
||||
|
||||
RubricFeedback.defaultProps = {
|
||||
value: '',
|
||||
value: { grading: '', review: '' },
|
||||
};
|
||||
|
||||
RubricFeedback.propTypes = {
|
||||
|
||||
@@ -89,7 +89,7 @@ describe('Rubric Feedback component', () => {
|
||||
expect(el.isEmptyRender()).toEqual(false);
|
||||
const input = el.find('.rubric-feedback.feedback-input');
|
||||
expect(input.prop('disabled')).toEqual(false);
|
||||
expect(input.prop('value')).toEqual(props.value);
|
||||
expect(input.prop('value')).toEqual(props.value.grading);
|
||||
});
|
||||
|
||||
test('is graded (the input are disabled)', () => {
|
||||
@@ -100,7 +100,7 @@ describe('Rubric Feedback component', () => {
|
||||
expect(el.isEmptyRender()).toEqual(false);
|
||||
const input = el.find('.rubric-feedback.feedback-input');
|
||||
expect(input.prop('disabled')).toEqual(true);
|
||||
expect(input.prop('value')).toEqual(props.value);
|
||||
expect(input.prop('value')).toEqual(props.value.review);
|
||||
});
|
||||
|
||||
test('is having invalid feedback (feedback get render)', () => {
|
||||
|
||||
@@ -69,7 +69,7 @@ exports[`Rubric Feedback component snapshot is graded 1`] = `
|
||||
disabled={true}
|
||||
floatingLabel="Comments"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
value="some value"
|
||||
value="review value"
|
||||
/>
|
||||
</Form.Group>
|
||||
`;
|
||||
@@ -100,7 +100,7 @@ exports[`Rubric Feedback component snapshot is grading 1`] = `
|
||||
disabled={false}
|
||||
floatingLabel="Add comments"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
value="some value"
|
||||
value="grading value"
|
||||
/>
|
||||
</Form.Group>
|
||||
`;
|
||||
|
||||
@@ -28,6 +28,18 @@ const initialState = {
|
||||
* }
|
||||
*/
|
||||
},
|
||||
localGradeData: {
|
||||
/**
|
||||
* <submissionId>: {
|
||||
* overallFeedback: '',
|
||||
* criteria: [{
|
||||
* orderNum: 0,
|
||||
* points: 0,
|
||||
* comments: '',
|
||||
* }],
|
||||
* }
|
||||
*/
|
||||
},
|
||||
activeIndex: null,
|
||||
current: {
|
||||
/**
|
||||
@@ -59,35 +71,49 @@ const initialState = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the given state's gradeData entry for the seleted submission,
|
||||
* overlaying the passed data on top of the existing data for the that
|
||||
* submission.
|
||||
* Updates the given state's gradeData entry for the seleted submission.
|
||||
* @return {object} - new state
|
||||
*/
|
||||
export const updateGradeData = (state, data) => ({
|
||||
export const loadGradeData = (state, data) => ({
|
||||
...state,
|
||||
gradeData: {
|
||||
...state.gradeData,
|
||||
[state.current.submissionId]: {
|
||||
...state.gradeData[state.current.submissionId],
|
||||
...data,
|
||||
},
|
||||
[state.current.submissionId]: { ...data },
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the given state's gradeData entry for the seleted submission,
|
||||
* Updates the state's localGradeData entry for the seleted submission,
|
||||
* overlaying the passed data on top of the existing data for the that
|
||||
* submission.
|
||||
* @return {object} - new state
|
||||
*/
|
||||
export const updateLocalGradeData = (state, data) => {
|
||||
const currentId = state.current.submissionId;
|
||||
return {
|
||||
...state,
|
||||
localGradeData: {
|
||||
...state.localGradeData,
|
||||
[currentId]: state.localGradeData[currentId]
|
||||
? { ...state.localGradeData[currentId], ...data }
|
||||
: { ...data },
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the given state's localGradeData entry for the seleted submission,
|
||||
* overlaying the passed data on top of the existing data for the criterion
|
||||
* at the given index (orderNum) for the rubric.
|
||||
* @return {object} - new state
|
||||
*/
|
||||
export const updateCriterion = (state, orderNum, data) => {
|
||||
const entry = state.gradeData[state.current.submissionId];
|
||||
const entry = state.localGradeData[state.current.submissionId];
|
||||
const criteria = {
|
||||
...entry.criteria,
|
||||
[orderNum]: { ...entry.criteria[orderNum], ...data },
|
||||
};
|
||||
return updateGradeData(state, { ...entry, criteria });
|
||||
return updateLocalGradeData(state, { ...entry, criteria });
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@@ -129,7 +155,7 @@ const grading = createSlice({
|
||||
selected: payload,
|
||||
activeIndex: 0,
|
||||
}),
|
||||
startGrading: (state, { payload }) => updateGradeData(
|
||||
startGrading: (state, { payload }) => updateLocalGradeData(
|
||||
{
|
||||
...state,
|
||||
current: { ...state.current, lockStatus: lockStatuses.inProgress },
|
||||
@@ -137,7 +163,7 @@ const grading = createSlice({
|
||||
{ ...payload },
|
||||
),
|
||||
setRubricFeedback: (state, { payload }) => (
|
||||
updateGradeData(state, { overallFeedback: payload })
|
||||
updateLocalGradeData(state, { overallFeedback: payload })
|
||||
),
|
||||
setCriterionOption: (state, { payload: { orderNum, value } }) => (
|
||||
updateCriterion(state, orderNum, { selectedOption: value })
|
||||
@@ -166,12 +192,12 @@ const grading = createSlice({
|
||||
lockStatus: lockStatuses.unlocked,
|
||||
},
|
||||
}),
|
||||
clearGrade: (state) => {
|
||||
const gradeData = { ...state.gradeData };
|
||||
delete gradeData[state.current.submissionId];
|
||||
stopGrading: (state) => {
|
||||
const localGradeData = { ...state.localGradeData };
|
||||
delete localGradeData[state.current.submissionId];
|
||||
return {
|
||||
...state,
|
||||
gradeData,
|
||||
localGradeData,
|
||||
current: {
|
||||
...state.current,
|
||||
lockStatus: lockStatuses.unlocked,
|
||||
|
||||
@@ -10,6 +10,7 @@ export const simpleSelectors = {
|
||||
activeIndex: state => state.grading.activeIndex,
|
||||
current: state => state.grading.current,
|
||||
gradeData: state => state.grading.gradeData,
|
||||
localGradeData: state => state.grading.localGradeData,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -121,12 +122,39 @@ selected.gradeData = createSelector(
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns list of criterion grade data for the current selection
|
||||
* @return {obj[]} criterion grade data entries
|
||||
* Returns the local grade data for the selected submission
|
||||
* @return {obj} local grade data
|
||||
* { score, overallFeedback, criteria }
|
||||
*/
|
||||
selected.localGradeData = createSelector(
|
||||
[module.selected.submissionId, module.simpleSelectors.localGradeData],
|
||||
(submissionId, localGradeData) => localGradeData[submissionId],
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns list of criterion grade data for the current selection for review
|
||||
* and grading views.
|
||||
* @return {obj} criterion grade data entries ({ review: [{}], grading: [{}] })
|
||||
*/
|
||||
selected.criteriaGradeData = createSelector(
|
||||
[module.selected.gradeData],
|
||||
(data) => (data ? data.criteria : []),
|
||||
[module.selected.gradeData, module.selected.localGradeData],
|
||||
(data, localData) => ({
|
||||
grading: (localData ? localData.criteria : []),
|
||||
review: (data ? data.criteria : []),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns list of criterion grade data for the current selection for both
|
||||
* review and grading views.
|
||||
* @return {obj} criterion grade data entries ({ review: [{}], grading: [{}] })
|
||||
*/
|
||||
selected.criteriaGradeData = createSelector(
|
||||
[module.selected.gradeData, module.selected.localGradeData],
|
||||
(data, localData) => ({
|
||||
grading: (localData ? localData.criteria : {}),
|
||||
review: (data ? data.criteria : {}),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -139,12 +167,17 @@ selected.score = createSelector(
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the rubric-level feedback for the selected submission
|
||||
* @return {string} selected submission's associated rubric-level feedback
|
||||
* Returns the rubric-level feedback for the selected submission for both review
|
||||
* and grading views.
|
||||
* @return {obj} selected submission's associated rubric-level feedback
|
||||
* ({ review: '', grading: '' })
|
||||
*/
|
||||
selected.overallFeedback = createSelector(
|
||||
[module.selected.gradeData],
|
||||
(data) => (data ? data.overallFeedback : ''),
|
||||
[module.selected.gradeData, module.selected.localGradeData],
|
||||
(data, localData) => ({
|
||||
review: (data ? data.overallFeedback : ''),
|
||||
grading: (localData ? localData.overallFeedback : ''),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -170,24 +203,47 @@ selected.isValidForSubmit = createSelector(
|
||||
|
||||
/**
|
||||
* Returns the grade data for the given criterion of the current
|
||||
* selection
|
||||
* selection for both review and grading views.
|
||||
* @param {number} orderNum - criterion orderNum (and index)
|
||||
* @return {obj} - Grade Data associated with the criterion
|
||||
* ({ review: {}, grading: {} })
|
||||
*/
|
||||
selected.criterionGradeData = (state, { orderNum }) => {
|
||||
const data = module.selected.criteriaGradeData(state);
|
||||
return data ? data[orderNum] : {};
|
||||
const { grading, review } = module.selected.criteriaGradeData(state);
|
||||
return {
|
||||
review: review ? review[orderNum] : {},
|
||||
grading: grading ? grading[orderNum] : {},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the selected option for the given criterion of the current selection for
|
||||
* both review and grading views.
|
||||
* @param {number} orderNum - criterion orderNum (and index)
|
||||
* @return {obj} - selected option associated with the criterion
|
||||
* ({ review: '', grading: '' })
|
||||
*/
|
||||
selected.criterionSelectedOption = (state, { orderNum }) => {
|
||||
const { grading, review } = module.selected.criterionGradeData(state, { orderNum });
|
||||
return {
|
||||
grading: grading ? grading.selectedOption : '',
|
||||
review: review ? review.selectedOption : '',
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the critierion-level feedback for the selected submission, given the
|
||||
* orderNum of the criterion.
|
||||
* orderNum of the criterion for both review and grading views.
|
||||
* @param {number} orderNum - criterion index
|
||||
* @return {string} - criterion-level feedback response for the given criterion.
|
||||
* @return {obj} - criterion-level feedback response for the given criterion.
|
||||
* ({ review: '', grading: '' }),
|
||||
*/
|
||||
selected.criterionFeedback = (state, { orderNum }) => {
|
||||
const data = module.selected.criterionGradeData(state, { orderNum });
|
||||
return data ? data.feedback : '';
|
||||
const { grading, review } = module.selected.criterionGradeData(state, { orderNum });
|
||||
return {
|
||||
grading: grading ? grading.feedback : '',
|
||||
review: review ? review.feedback : '',
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,7 +159,7 @@ export const cancelGrading = () => (dispatch, getState) => {
|
||||
* to False
|
||||
*/
|
||||
export const stopGrading = () => (dispatch) => {
|
||||
dispatch(actions.grading.clearGrade());
|
||||
dispatch(actions.grading.stopGrading());
|
||||
dispatch(actions.app.setGrading(false));
|
||||
};
|
||||
|
||||
|
||||
@@ -339,10 +339,10 @@ describe('grading thunkActions', () => {
|
||||
});
|
||||
|
||||
describe('stopGrading', () => {
|
||||
it('dispatches grading.clearGrade and app.setGrading(false)', () => {
|
||||
it('dispatches grading.stopGrading and app.setGrading(false)', () => {
|
||||
thunkActions.stopGrading()(dispatch, getState);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.grading.clearGrade()],
|
||||
[actions.grading.stopGrading()],
|
||||
[actions.app.setGrading(false)],
|
||||
]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user