Skip to content

Commit

Permalink
added warning window when cancelling an expanded story
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielRMuller committed Feb 11, 2019
1 parent 5ebc1f0 commit 5c9b28a
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,33 +1,52 @@
import React from 'react';

const ExpandedStoryControls = ({ onCancel, onSave, onDelete, readOnly }) => {
return (
<div className="form-group Story__controls">
<input className="save"
onClick={onSave}
type="button"
value={I18n.t('save')}
disabled={readOnly}
/>

<input className="delete"
onClick={() => {
if (window.confirm(I18n.t('story destroy confirm'))){
onDelete();
}
}}
type="button"
value={I18n.t('delete')}
disabled={readOnly}
/>

<input className="cancel"
onClick={onCancel}
type="button"
value={I18n.t('cancel')}
/>
</div>
);
import React, { Component } from 'react';

class ExpandedStoryControls extends Component {
constructor(props) {
super(props);

this.handleCancel = this.handleCancel.bind(this);
}

handleCancel() {
const { onCancel, isDirty } = this.props;

if (isDirty && !window.confirm(I18n.t('story unsaved changes'))) {
return;
}
onCancel();
}

render() {
const { onSave, onDelete, readOnly } = this.props;

return (
<div className="form-group Story__controls">
<input className="save"
onClick={onSave}
type="button"
value={I18n.t('save')}
disabled={readOnly}
/>

<input className="delete"
onClick={() => {
if (window.confirm(I18n.t('story destroy confirm'))){
onDelete();
}
}}
type="button"
value={I18n.t('delete')}
disabled={readOnly}
/>

<input className="cancel"
onClick={this.handleCancel}
type="button"
value={I18n.t('cancel')}
/>
</div>
);
}
};

export default ExpandedStoryControls;
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const ExpandedStory = ({
<div className="Story Story--expanded">
<ExpandedStoryControls
onCancel={onToggle}
isDirty={story._editing._isDirty}
onSave={() => updateStory(story, project.id)}
onDelete={() => deleteStory(story.id, project.id)}
readOnly={Story.isAccepted(story)}
Expand Down
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ en:
reset_tour_success: "Tour was successfully reset"
reset_tour_fail: "An error has ocurred, please try again"
story destroy confirm: "Are you sure you want to destroy this story?"
story unsaved changes: "You have unsaved changes, are you sure you want to cancel?"
stories_destroy_success: "Stories were successfully destroyed"
stories_destroy_fail: "Stories couldn't be destroyed due some validation errors"
update_stories_successfully: "Stories were successfully updated"
Expand Down
1 change: 1 addition & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ es:
reset_tour_success: "La excursión se restableció correctamente"
reset_tour_fail: "Ha ocurrido un error, por favor intente otra vez"
story destroy confirm: "¿Estás seguro de que quieres destruir esta historia?"
story unsaved changes: "¿Usted tiene cambios no guardados, está seguro de que desea cancelar?"
stories_destroy_success: "Las historias fueron destruidas con éxito"
stories_destroy_fail: "Las historias no se pudieron destruir debido a algunos errores de validación"
update_stories_successfully: "Las historias se actualizaron con éxito"
Expand Down
1 change: 1 addition & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pt-BR:
reset_tour_success: "A tour foi resetada com sucesso"
reset_tour_fail: "Ocorreu um erro, por favor tente novamente"
story destroy confirm: "Você tem certeza que deseja excluir esta história?"
story unsaved changes: "Você tem mudanças não salvas, tem certeza que deseja cancelar?"
stories_destroy_success: "As histórias foram destruídas com sucesso"
stories_destroy_fail: "As histórias não puderam ser destruídas por alguns erros de validação"
update_stories_successfully: "As histórias foram atualizadas com sucesso"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ describe('<ExpandedStoryControls />', () => {
});

describe('when the user click on delete', () => {
beforeEach(function() {
beforeEach(function () {
sinon.stub(window, 'confirm').returns(true);
});

afterEach(function() {
afterEach(function () {
window.confirm.restore();
});

Expand All @@ -55,76 +55,125 @@ describe('<ExpandedStoryControls />', () => {
});
});

describe('when the user click on cancell', () => {
describe('when the user click on cancel', () => {
beforeEach(function() {
sinon.stub(window, 'confirm')
});

afterEach(function() {
window.confirm.restore();
});

it('triggers the toggle callback', () => {
const onCancel = sinon.spy();
const handleCancel = sinon.spy();

const wrapper = shallow(
<ExpandedStoryControls
readOnly={false}
onCancel={onCancel}
onCancel={handleCancel}
/>
);

wrapper.find('.cancel').simulate('click');

expect(onCancel).toHaveBeenCalled();
expect(handleCancel).toHaveBeenCalled();
});
});

describe('readOnly', () => {
describe("when it's true", () => {
let wrapper;
it('triggers a warning window when there is unsaved changes', () => {
const handleCancel = sinon.spy();

beforeEach(() => {
wrapper = shallow(
<ExpandedStoryControls
readOnly={true}
/>
);
});
const wrapper = shallow(
<ExpandedStoryControls
readOnly={false}
isDirty={true}
onCancel={handleCancel}
/>
);

it('disable save button', () => {
const button = wrapper.find('.save');
wrapper.find('.cancel').simulate('click');

expect(button.prop('disabled')).toBe(true);
});
expect(window.confirm).toHaveBeenCalled();
});

it('disable delete button', () => {
const button = wrapper.find('.delete');
it('does not trigger a warning window when no changes were made', () => {
const handleCancel = sinon.spy();

expect(button.prop('disabled')).toBe(true);
});
const wrapper = shallow(
<ExpandedStoryControls
readOnly={false}
isDirty={false}
onCancel={handleCancel}
/>
);

it("don't set disable prop to cancel button", () => {
const button = wrapper.find('.cancel');
wrapper.find('.cancel').simulate('click');

expect(button.prop('disabled')).toBe(undefined);
});
expect(window.confirm).not.toHaveBeenCalled();
});

describe("when it's false", () => {
let wrapper;
describe('when the user clicks cancel on window.confirm', () => {
it('does not call onCancel', () => {
window.confirm.returns(false);
const handleCancel = sinon.spy();

beforeEach(() => {
wrapper = shallow(
<ExpandedStoryControls
readOnly={false}
/>
);
expect(handleCancel).not.toHaveBeenCalled();
});
});
});

it("don't disable save button", () => {
const button = wrapper.find('.save');
describe('readOnly', () => {
describe("when it's true", () => {
let wrapper;

expect(button.prop('disabled')).toBe(false);
});
beforeEach(() => {
wrapper = shallow(
<ExpandedStoryControls
readOnly={true}
/>
);
});

it("don't disable delete button", () => {
const button = wrapper.find('.delete');
it('disable save button', () => {
const button = wrapper.find('.save');

expect(button.prop('disabled')).toBe(false);
});
expect(button.prop('disabled')).toBe(true);
});

it('disable delete button', () => {
const button = wrapper.find('.delete');

expect(button.prop('disabled')).toBe(true);
});

it("don't set disable prop to cancel button", () => {
const button = wrapper.find('.cancel');

expect(button.prop('disabled')).toBe(undefined);
});
});

describe("when it's false", () => {
let wrapper;

beforeEach(() => {
wrapper = shallow(
<ExpandedStoryControls
readOnly={false}
/>
);
});

it("don't disable save button", () => {
const button = wrapper.find('.save');

expect(button.prop('disabled')).toBe(false);
});

it("don't disable delete button", () => {
const button = wrapper.find('.delete');

expect(button.prop('disabled')).toBe(false);
});
});
});
});

0 comments on commit 5c9b28a

Please sign in to comment.