Skip to content

Commit

Permalink
Merge 1fd4f69 into 4493cdc
Browse files Browse the repository at this point in the history
  • Loading branch information
kostadriano committed Dec 10, 2018
2 parents 4493cdc + 1fd4f69 commit 9450101
Show file tree
Hide file tree
Showing 14 changed files with 324 additions and 16 deletions.
3 changes: 2 additions & 1 deletion app/assets/javascripts/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export default keyMirror({
RECEIVE_USERS: null,
RECEIVE_STORIES: null,
RECEIVE_PAST_ITERATIONS: null,
TOGGLE_STORY: null
TOGGLE_STORY: null,
EDIT_STORY: null
});
6 changes: 6 additions & 0 deletions app/assets/javascripts/actions/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ export const toggleStory = (id) => ({
type: actionTypes.TOGGLE_STORY,
id
});

export const editStory = (id, newAttributes) => ({
type: actionTypes.EDIT_STORY,
id,
newAttributes
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { isFeature } from '../../../models/beta/story';

export class ExpandedStoryEstimate extends React.Component {
editStory(event) {
const newValue = event.target.value;

this.props.onEdit({ estimate: newValue });
};

render() {
const { project, story } = this.props;

return (
<div className="Story__section">
<div className="Story__section-title">
{ I18n.translate('activerecord.attributes.story.estimate') }
</div>

<select
defaultValue={story.estimate}
className="form-control input-sm"
onChange={(event) => this.editStory(event)}
disabled={!isFeature(story)}
>
<option value=''>
{ I18n.translate('story.no_estimate') }
</option>
{
project.pointValues.map((value) => (
<option value={value} key={value}>
{ value }
</option>
))
}
</select>
</div>
);
};
};

ExpandedStoryEstimate.propTypes = {
project: PropTypes.object,
story: PropTypes.object
};

const mapStateToProps = ({ project }) => ({ project });

export default connect(
mapStateToProps,
null
)(ExpandedStoryEstimate);
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import { types } from '../../../models/beta/story';

export class ExpandedStoryType extends React.Component {
editStory(event) {
const newValue = event.target.value;

this.props.onEdit({ storyType: newValue });
};

render() {
const { story } = this.props;

return (
<div className="Story__section">
<div className="Story__section-title">
{ I18n.translate('activerecord.attributes.story.story_type') }
</div>

<select
defaultValue={story.storyType}
className="form-control input-sm"
onChange={(event) => this.editStory(event)}
>
{
types.map((value) => (
<option value={value} key={value}>
{ value }
</option>
))
}
</select>
</div>
);
};
};

ExpandedStoryType.propTypes = {
story: PropTypes.object
};

export default ExpandedStoryType;
24 changes: 20 additions & 4 deletions app/assets/javascripts/components/story/ExpandedStory/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,27 @@ import React from 'react';
import PropTypes from 'prop-types';
import ExpandedStoryHistoryLocation from './ExpandedStoryHistoryLocation';
import ExpandedStoryControls from './ExpandedStoryControls';
import ExpandedStoryEstimate from './ExpandedStoryEstimate';
import ExpandedStoryType from './ExpandedStoryType';
import { editStory } from '../../../actions/story';
import { connect } from 'react-redux';

const ExpandedStory = (props) => {
const { story, onToggle } = props;
export const ExpandedStory = (props) => {
const { story, onToggle, editStory } = props;

return (
<div className="Story Story--expanded">
<ExpandedStoryControls onCancel={onToggle}/>
<ExpandedStoryControls onCancel={onToggle} />
<ExpandedStoryHistoryLocation story={story} />
<div className="Story__inline-block">
<ExpandedStoryEstimate story={story}
onEdit={(newAttributes) => editStory(story.id, newAttributes)}
/>

<ExpandedStoryType story={story}
onEdit={(newAttributes) => editStory(story.id, newAttributes)}
/>
</div>
</div>
);
};
Expand All @@ -18,4 +31,7 @@ ExpandedStory.propTypes = {
story: PropTypes.object.isRequired
};

export default ExpandedStory;
export default connect(
null,
{ editStory }
)(ExpandedStory);
2 changes: 2 additions & 0 deletions app/assets/javascripts/models/beta/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ export const getCompletedPoints = story => {
export const isStoryNotEstimated = (storyType, estimate) => storyType === 'feature' && !estimate;

export const isRelease = (storyType) => storyType === 'release';

export const types = ['feature', 'bug', 'release', 'chore'];
4 changes: 3 additions & 1 deletion app/assets/javascripts/reducers/stories.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import actionTypes from 'actions/actionTypes';
import { toggleStories } from './story';
import { toggleStories, editStory } from './story';

const initialState = [];

Expand All @@ -9,6 +9,8 @@ const storiesReducer = (state = initialState, action) => {
return action.data;
case actionTypes.TOGGLE_STORY:
return toggleStories(state, action.id);
case actionTypes.EDIT_STORY:
return editStory(state, action.id, action.newAttributes);
default:
return state;
};
Expand Down
17 changes: 17 additions & 0 deletions app/assets/javascripts/reducers/story.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,26 @@ export const toggleStories = (stories, id) => {
if (story.id !== id) {
return story;
}

const previousState = !story.collapsed ? null : story;

return {
...story,
_previousState: previousState,
collapsed: !story.collapsed
};
});
};

export const editStory = (stories, id, newAttributes) => {
return stories.map((story) => {
if (story.id !== id) {
return story;
};

return {
...story,
...newAttributes
};
});
};
17 changes: 16 additions & 1 deletion app/assets/stylesheets/new_board/_story.scss
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,25 @@
}

&--expanded {
padding: 8px 10px;
background-color: $butter-2;
color: $aluminium-6;

.Story {
&__inline-block {
display: flex;
}

&__section-title {
font-size: 12px;
font-weight: bold;
margin-bottom: 5px;
}

&__section {
margin: 5px 5px 5px 0;
}

&__controls {
@extend .btn-group;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React from 'react';
import { shallow } from 'enzyme';
import { ExpandedStoryEstimate } from 'components/story/ExpandedStory/ExpandedStoryEstimate';

describe('<ExpandedStoryEstimate />', () => {
it("renders component with 'Fibonacci' point scale in select", () => {
const project = { pointValues: ['1','2','3','5','8'] };
const story = { estimate: null };

const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select').text();

project.pointValues.forEach((value) => {
expect(select).toContain(value);
});
});

it("renders component with 'Powers of two' point scale in select", () => {
const project = { pointValues: ['1','2','4','8'] };
const story = { estimate: null };

const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select').text();

project.pointValues.forEach((value) => {
expect(select).toContain(value);
});
});

it("renders component with 'Linear' point scale in select", () => {
const project = { pointValues: ['1','2','3','4','5'] };
const story = { estimate: null };

const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select').text();

project.pointValues.forEach((value) => {
expect(select).toContain(value);
});
});

describe("When story.estimate is not null", () => {
it("sets the select defaultValue as story.estimate", () => {
const project = { pointValues: ['1','2','3','5','8'] };

project.pointValues.forEach((value) => {
const story = { estimate: value };
const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select');

expect(select.props().defaultValue).toBe(value);
});
});
});

describe("When story.estimate is null", () => {
it("sets the select defaultValue as null", () => {
const project = { pointValues: ['1','2','3','4','5'] };
const story = { estimate: null };

const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select');

expect(select.props().defaultValue).toBe(null);
});
});

describe("When change storyType", () => {
describe("to a type that is not a feature", () =>{
const notFeatureTypes = ['bug', 'release', 'chore'];

it("disables estimate select", () =>{
const project = { pointValues: ['1','2','3','4','5'] };

notFeatureTypes.forEach((type) => {
const story = { storyType: type };
const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);

const select = wrapper.find('select');

expect(select.props().disabled).toBe(true);
});
});
});

describe("to a feature", () =>{
it("not disable estimate select", () =>{
const project = { pointValues: ['1','2','3','4','5'] };
const story = { storyType: 'bug' };

const wrapper = shallow(<ExpandedStoryEstimate project={project} story={story}/>);
const select = wrapper.find('select');

expect(select.props().disabled).toBe(true);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { shallow } from 'enzyme';
import ExpandedStory from 'components/story/ExpandedStory/index';
import { ExpandedStory } from 'components/story/ExpandedStory/index';
import storyFactory from '../../../support/factories/storyFactory';

describe('<ExpandedStory />', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { shallow } from 'enzyme';
import ExpandedStoryType from 'components/story/ExpandedStory/ExpandedStoryType';

describe('<ExpandedStoryEstimate />', () => {
it("sets defaultValue as story.storyType in select", () => {
const storyTypes = ['feature', 'bug', 'release', 'chore'];

storyTypes.forEach((type) => {
const story = { storyType: type };
const wrapper = shallow(<ExpandedStoryType story={story} />);
const select = wrapper.find('select');

expect(select.props().defaultValue).toBe(type);
});
});
});
9 changes: 6 additions & 3 deletions spec/javascripts/components/story/story_item_spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import React from 'react';
import { shallow } from 'enzyme';
import { StoryItem } from 'components/story/StoryItem';
import storyFactory from '../../support/factories/storyFactory'
import storyFactory from '../../support/factories/storyFactory';
import ExpandedStory from 'components/story/ExpandedStory';
import CollapsedStory from 'components/story/CollapsedStory';


describe('<StoryItem />', () => {
it('renders the StoryItem component within a Collapsed Story', () => {
const story = storyFactory({ collapsed: true });
const wrapper = shallow(<StoryItem story={story} />);

expect(wrapper.find('CollapsedStory')).toExist();
expect(wrapper.find(CollapsedStory)).toExist();
});

it('renders the StoryItem component within a Expanded Story', () => {
const story = storyFactory({ collapsed: false });
const wrapper = shallow(<StoryItem story={story} />);

expect(wrapper.find('ExpandedStory')).toExist();
expect(wrapper.find(ExpandedStory)).toExist();
});
});
Loading

0 comments on commit 9450101

Please sign in to comment.