diff --git a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx index e90f56a7d..44459144e 100644 --- a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx +++ b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.jsx @@ -30,9 +30,20 @@ class ImageSequence extends React.Component { super(props); this.state = { choiceId: null, + hasChanged: false }; } + onUpdateChoice = (itemId, choiceId, newChoice, fileIds) => { + this.setState({ hasChanged: true }); + this.props.updateChoice(itemId, choiceId, newChoice, fileIds); + } + + onSave = () => { + this.setState({ hasChanged: false }); + this.props.save(); + } + getFeedback() { const { question } = this.props.item; const strings = this.props.localizeStrings('imageSequence'); @@ -63,6 +74,21 @@ class ImageSequence extends React.Component { } render() { + let saveOptions = ( + + ); + + if (this.state.hasChanged) { + saveOptions = ( + + ); + } + return (
- + {saveOptions}
{ this.getFeedback() }
diff --git a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx index c850050f8..640fdb830 100644 --- a/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx +++ b/client/js/_author/components/assessments/question_types/image_sequence/_image_sequence.spec.jsx @@ -50,6 +50,7 @@ describe('image sequence component', () => { it('renders the component', () => { expect(result.find('.au-c-question__feedback').length).toBe(2); + expect(result.state().hasChanged).toEqual(false); }); it('renders two Feedback components', () => { @@ -66,4 +67,16 @@ describe('image sequence component', () => { feedback.at(0).nodes[0].props.updateItem(); expect(calledFunc).toBeTruthy(); }); + + it('changes state when call onUpdateChoice', () => { + expect(result.state().hasChanged).toEqual(false); + result.instance().onUpdateChoice(); + expect(result.state().hasChanged).toEqual(true); + }); + + it('sets disabled flag correctly on the Save button', () => { + expect(result.find({ disabled: true }).length).toEqual(1); + result.setState({ hasChanged: true }); + expect(result.find({ disabled: true }).length).toEqual(0); + }); }); diff --git a/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx b/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx index 7c946ecbd..6dca840eb 100644 --- a/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx +++ b/client/js/_author/components/assessments/question_types/movable_word_sentence/movable_word_sentence.jsx @@ -28,10 +28,42 @@ class MovableWordSentence extends React.Component { duplicateAnswers: React.PropTypes.arrayOf(React.PropTypes.string), }; + constructor(props) { + super(props); + this.state = { + hasChanged: false + }; + } + + onUpdateChoice = (itemId, choiceId, newChoice, fileIds) => { + this.setState({ hasChanged: true }); + this.props.updateChoice(itemId, choiceId, newChoice, fileIds); + } + + onSave = () => { + this.setState({ hasChanged: false }); + this.props.save(); + } + render() { const { question, id } = this.props.item; const strings = this.props.localizeStrings('movableWordSentence'); + let saveOptions = ( + + ); + + if (this.state.hasChanged) { + saveOptions = ( + + ); + } + return (
this.props.updateChoice(id, choice.id, newChoice, fileIds) + (newChoice, fileIds) => this.onUpdateChoice(id, choice.id, newChoice, fileIds) } isActive={this.props.isActive && choice.id === this.props.activeChoice} deleteChoice={() => this.props.deleteChoice(choice)} @@ -58,7 +90,7 @@ class MovableWordSentence extends React.Component { this.props.createChoice()} /> - + {saveOptions}
{ it('renders the movable word sentence component', () => { expect(result.find('.au-c-movable__answers')); + expect(result.state().hasChanged).toEqual(false); }); it('renders Option', () => { @@ -109,4 +110,16 @@ describe('movable word sentece component', () => { result.find('.au-c-movable__answers').simulate('blur', { target: { value: 'Preposition' } }); expect(calledFunc).toBeTruthy(); }); + + it('changes state when call onUpdateChoice', () => { + expect(result.state().hasChanged).toEqual(false); + result.instance().onUpdateChoice(); + expect(result.state().hasChanged).toEqual(true); + }); + + it('sets disabled flag correctly on the Save button', () => { + expect(result.find({ disabled: true }).length).toEqual(1); + result.setState({ hasChanged: true }); + expect(result.find({ disabled: true }).length).toEqual(0); + }); }); diff --git a/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx b/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx index 20d8d35b0..9ab86b695 100644 --- a/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx +++ b/client/js/_author/components/assessments/question_types/question_common/save_option_button.jsx @@ -3,10 +3,16 @@ import localize from '../../../../locales/localize'; function saveOption(props) { const strings = props.localizeStrings('saveOption'); + let classes = 'au-c-btn au-c-btn--sm au-c-btn--maroon au-u-ml-md'; + + if (props.disabled) { + classes += ' is-inactive'; + } return ( @@ -16,6 +22,7 @@ function saveOption(props) { saveOption.propTypes = { save: React.PropTypes.func.isRequired, localizeStrings: React.PropTypes.func.isRequired, + disabled: React.PropTypes.bool }; export default localize(saveOption); diff --git a/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx b/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx index cb158f4b1..64bf0806b 100644 --- a/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx +++ b/client/js/_author/components/assessments/question_types/question_common/save_option_button.spec.jsx @@ -25,4 +25,11 @@ describe('save option button component', () => { button.simulate('click'); expect(calledFunction).toBeTruthy(); }); + + it('has inactive class if disabled', () => { + expect(result.find('.is-inactive').length).toEqual(0); + props.disabled = true; + result = shallow(); + expect(result.find('.is-inactive').length).toEqual(1); + }); });