Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/#195 collapse standups #196

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
01293fa
Refactor: Modify to collapse standups to a summary panel and a detail…
jdmedlock Jan 16, 2019
9da30f9
Refactor: Modify layout to match mockup
jdmedlock Jan 16, 2019
c82e21a
Refactor: Update CSS with layout modifications
jdmedlock Jan 16, 2019
dd53f8c
Refactor: Change background color of standup summary and detail panels
jdmedlock Jan 17, 2019
5ff8dd5
Refactor: Convert `NewsfeedStandup` to be a stateful component
jdmedlock Jan 17, 2019
eacb11c
Refactor: Add state to `NewsfeedStandup` to maintain selected standup
jdmedlock Jan 17, 2019
1adda59
Refactor: Update `NewsFeedStandup` to hold standups array and selecte…
jdmedlock Jan 18, 2019
9a9bafb
Refactor: Remove unnecessary `console.log` statements and add key to …
jdmedlock Jan 18, 2019
6c37035
Refactor: Add recent standup to Summary panel and adjust Summary layout
jdmedlock Jan 18, 2019
4c22ad5
Refactor: Add all, pending, and count of missed standups to Summary p…
jdmedlock Jan 18, 2019
b147243
Refactor: Update to only display most recent pending standup
jdmedlock Jan 18, 2019
e5bf7d1
Refactor: Add edge cases to standup summary panel and organize logic
jdmedlock Jan 19, 2019
fddbe69
Fix: Add `rel="noopener noreferrer"` to anchor tags with `target="_bl…
jdmedlock Jan 19, 2019
c88ab6e
Refacor: Convert class methods to arrow syntax
jdmedlock Jan 19, 2019
408fd6b
Refactor: Add `SummaryList` component
jdmedlock Jan 23, 2019
10627a1
Refactor: Move standup rendering logic to StandupList for all types o…
jdmedlock Jan 23, 2019
f35249f
Refactor: Add More/Less anchor to change completed standup display co…
jdmedlock Jan 24, 2019
aa1d03e
Refactor: Remove unnecessary comment
jdmedlock Jan 24, 2019
9d2cff8
Refactor: Add check for no standup to Pending and Most Recent Standup…
jdmedlock Jan 25, 2019
7424a8e
Refactor: Split `SummaryList` component into list-specific components
jdmedlock Jan 25, 2019
337ede4
Feature: Add logic to display standup entry form when pending standup…
jdmedlock Jan 25, 2019
3b8810f
Refactor: Replace hardcoded display count limit with constant
jdmedlock Jan 30, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/components/FeedPortal/components/GithubActivity.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const IssueIcon = () => {

export const GithubActivityPullRequest = ( data ) => {
return (
<a href={data.url} target="_blank" className="github-activity-container">
<a href={data.url} target="_blank"
rel="noopener noreferrer" className="github-activity-container">
<PRIcon />
<div className="github-activity-text">
<div className="github-activity-title">{data.title}</div>
Expand All @@ -30,7 +31,8 @@ export const GithubActivityPullRequest = ( data ) => {
}
export const GithubActivityIssue = ( data ) => {
return (
<a href={data.url} target="_blank" className="github-activity-container">
<a href={data.url} target="_blank" rel="noopener noreferrer"
className="github-activity-container">
<IssueIcon />
<div className="github-activity-text">
<div className="github-activity-title">{data.title}</div>
Expand Down
28 changes: 15 additions & 13 deletions src/components/FeedPortal/components/NewsFeed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,28 @@ const NewsFeed = ({ type, loading, data }) => {
${project ? `${project.team_name.toUpperCase()}` : "ALL"} NEWS
`;


const renderNewsfeedItems = items => items.map(
item => {
return FeedItemContainer({
component: NewsfeedItems[item.type],
item,
key: item.id,
})
});
}
);

const renderStandups = standups => standups.map(
standup => (
standup.submitted_at
? FeedItemContainer({
item: { standup, type: "NewsfeedStandup", user: standup.member, timestamp: standup.submitted_at },
key: standup.id,
component: NewsfeedItems.NewsfeedStandup,
})
: null
),
);
const renderStandups = standups => {
return (
FeedItemContainer({
item: {
standups, type: "NewsfeedStandup",
user: standups[standups.length-1].member,
timestamp: standups[standups.length-1].submitted_at },
key: standups[standups.length-1].id,
component: NewsfeedItems.NewsfeedStandup,
})
);
};

const renderFeed = ({ user, project }) => {
let dataToRender = (
Expand Down Expand Up @@ -91,6 +91,8 @@ const getNewsfeed = (project_id) => {
worked_on
working_on
blocked_on
is_expired
expiration
member {
id
username
Expand Down
98 changes: 51 additions & 47 deletions src/components/FeedPortal/components/NewsfeedStandup.jsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,61 @@
import * as React from 'react';
import React from 'react';
import PropTypes from 'prop-types';

import "./NewsfeedStandup.css";
import FeedItemContainer from "./FeedItem";
import StandupDetail from "./StandupDetail";
import StandupSummary from "./StandupSummary";

const sentimentMap = {
red: 'Trouble Ahead!',
yellow: 'Nervous',
green: 'Great!',
};

const responseLabelMap = {
progress_sentiment: 'Health Status',
worked_on: 'Worked on',
working_on: 'Working on',
blocked_on: 'Blocked on',
}
class NewsfeedStandup extends React.Component {

static propTypes = {
standups: PropTypes.array.isRequired,
timestamp: PropTypes.number.isRequired,
type: PropTypes.string.isRequired,
user: PropTypes.object.isRequired,
};

const classNameSelector = (item, data) => {
let className = "team-standup-answer";
if (item === "progress_sentiment") {
className += ` team-standup-status--${data}`;
constructor(props) {
super(props);

const { standups } = props;
this.state = {
standups: standups,
selected_standup: {},
};

this.updateSelectedStandup = this.updateSelectedStandup.bind(this);
}
return className;
};

const renderResponses = standupFields => Object.keys(standupFields).map(
standupField => {
const fieldValue = standupFields[standupField];
const className = classNameSelector(standupField, fieldValue);
updateSelectedStandup= (standup) => {
this.setState({ selected_standup: { ...standup } });
}

renderResponses = () => {
return (
<div className="team-standup-data" key={standupField}>
<label className="team-standup-label">{responseLabelMap[standupField]} :</label>
<div className={className}>
{
standupField === "progress_sentiment"
? sentimentMap[fieldValue]
: fieldValue
}
<React.Fragment>
<div className="team-standup-container">
<div className="team-standup-summary">
<StandupSummary
standups={ this.state.standups }
updateSelectedStandup={ this.updateSelectedStandup }/>
</div>
<div className="team-standup-detail">
<StandupDetail { ...{ standup: this.state.selected_standup } }/>
</div>
</div>
</div>
</React.Fragment>
);
},
);

const NewsfeedStandup = ({
standup: {
progress_sentiment,
worked_on,
working_on,
blocked_on,
},
}) => (
<div className="team-standup-card-container">
{renderResponses({ progress_sentiment, worked_on, working_on, blocked_on })}
</div>
);
};

render = () => {
return (
<React.Fragment>
{ this.renderResponses() }
</React.Fragment>
);
}

}

export default NewsfeedStandup;
48 changes: 40 additions & 8 deletions src/components/FeedPortal/components/NewsfeedStandup.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
@import '../../../styles/abstracts/_variables.scss';


/*
==========================
CONTAINER
==========================
*/
.team-standup-card-container {
background-color: $palest-grey;
padding: 40px;
.team-standup-container {
display: grid;
grid-template-columns: 25% 72%;
grid-gap: 1rem;
}

.team-standup-summary {
background-color: white;
display: table-cell; // Force height of all children to that of largest child
grid-column: 1;
grid-row: 1;
padding: .25rem;
}

.team-standup-detail {
background-color: white;
display: table-cell; // Force height of all children to that of largest child
grid-column: 2;
grid-row: 1;
padding: .25rem;
}
/*
==========================
Expand All @@ -24,12 +40,21 @@ data object

.team-standup-label {
grid-area: l;
border-right: 1px solid $grey;
display: block;
padding-bottom: 30px;
font-size: 14px;
color: $med-grey;
text-transform: uppercase;
color: #9e9e9e;
}

.team-standup-label--bordered {
border-right: 1px solid #9e9e9e;
}

.team-standup-label--padtop {
padding-top: 1rem;
}

.team-standup-label--padded {
padding-bottom: 30px;
}

.team-standup-answer {
Expand All @@ -39,6 +64,13 @@ data object
color: $dark-grey;
padding-bottom: 30px;
}

.team-standup-id {
display: block;
font-size: 12px;
color: $health-green;
padding-left: 0;
}
/*
==========================
COLORED STATUS
Expand Down
95 changes: 95 additions & 0 deletions src/components/FeedPortal/components/StandupCompleted.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from 'react';
import PropTypes from 'prop-types';

import "./NewsfeedStandup.css";

const INITIAL_LIST_LIMIT = 3;

class StandupCompleted extends React.Component {

static propTypes = {
sortedStandups: PropTypes.array.isRequired,
newStandupSelected: PropTypes.func.isRequired,
updateSelectedStandup: PropTypes.func.isRequired,
}

constructor(props) {
super(props);
this.defaultDisplayListCount = INITIAL_LIST_LIMIT;
this.state = {
listDisplayLimit: this.defaultDisplayListCount,
scrollText: "More..."
};
}

filterStandups = (standup, standupIndex, displayCount) => {
return standupIndex !== 0 && standup.submitted_at && displayCount <= this.state.listDisplayLimit;
}

renderMore = (sortedStandups) => {
const completedStandupCount = sortedStandups.reduce((count, standup, standupIndex) => {
if (this.filterStandups(standup, standupIndex, 0)) {
count += 1;
}
return count;
}, 0);

return (
<div>
{ completedStandupCount > INITIAL_LIST_LIMIT
? <a id="team-standup-scroll" href='#' className="team-standup-id"
onClick={ (e) => {
if (this.state.scrollText === 'More...') {
this.setState({
listDisplayLimit: completedStandupCount,
scrollText: 'Less...'
});
} else {
this.setState({
listDisplayLimit: this.defaultDisplayListCount,
scrollText: 'More...'
});
}
} }>
{ this.state.scrollText }
</a>
: null
}
</div>
);
}

render = () => {
const { sortedStandups, newStandupSelected, updateSelectedStandup } = this.props;
let displayCount = 1;
const incrementDisplayCount = () => {
displayCount += 1;
};

return (
<React.Fragment>
<label className='team-standup-label team-standup-label--padtop'>
Completed Standups
</label>
{ sortedStandups.length > 0
? sortedStandups.map( (standup, standupIndex) => (
this.filterStandups(standup, standupIndex, displayCount)
? <a href='#' className="team-standup-id" key={standup.submitted_at}
onClick={ (e) => {
newStandupSelected(e, standup, updateSelectedStandup);
} }>
{ new Date(standup.submitted_at).toLocaleDateString()} - { standup.member.username }
{ incrementDisplayCount() }
</a>
: null
))
: <div className="team-standup-id">No standups</div>
}
{ this.renderMore(sortedStandups) }
</React.Fragment>
);
};

}

export default StandupCompleted;
Loading