LearnersGuild/echo

View on GitHub
src/common/components/ProjectDetail/index.jsx

Summary

Maintainability
A
2 hrs
Test Coverage
/* eslint-disable react/jsx-handler-names */
import React, {Component, PropTypes} from 'react'
import {Link} from 'react-router'
import {IconButton} from 'react-toolbox/lib/button'
import FontIcon from 'react-toolbox/lib/font_icon'
import moment from 'moment-timezone'
import {Tab, Tabs} from 'react-toolbox'
import Helmet from 'react-helmet'
 
import ContentHeader from 'src/common/components/ContentHeader'
import ProjectUserSummary from 'src/common/components/ProjectUserSummary'
import {Flex} from 'src/common/components/Layout'
import {safeUrl, urlParts, objectValuesAreAllNull} from 'src/common/util'
 
import styles from './index.scss'
import theme from './theme.scss'
 
class ProjectDetail extends Component {
constructor(props) {
super(props)
 
this.state = {tabIndex: 0}
this.renderHeader = this.renderHeader.bind(this)
this.renderDetails = this.renderDetails.bind(this)
this.renderTabs = this.renderTabs.bind(this)
this.renderUserSummaries = this.renderUserSummaries.bind(this)
}
 
renderHeader() {
const {project: {name, retrospectiveSurveyId}, allowEdit, onClickEdit} = this.props
 
const editDisabled = Boolean(retrospectiveSurveyId)
const editButton = allowEdit ? (
<IconButton
icon="mode_edit"
onClick={onClickEdit}
disabled={editDisabled}
primary
/>
) : null
 
const title = (
<Flex alignItems="center">
<h5 className={styles.title}>{name}</h5>
{editButton}
</Flex>
)
 
return (
<div className={styles.header}>
<ContentHeader title={title}/>
</div>
)
}
 
Function `renderDetails` has 48 lines of code (exceeds 25 allowed). Consider refactoring.
Function `renderDetails` has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.
renderDetails() {
const {project = {}, projectUserSummaries} = this.props
const {chapter, cycle, phase} = project
 
const memberList = projectUserSummaries.map((projectUserSummary, index) => {
const {user} = projectUserSummary
const prefix = index > 0 ? ', ' : ''
return (
<Link key={index} to={`/users/${user.handle}`}>
<em>{`${prefix}${user.handle}`}</em>
</Link>
)
})
 
const {artifactURL} = project
const artifactLinkUrl = safeUrl(artifactURL)
const artifactHeader = artifactLinkUrl ? <div>Artifact</div> : null
const artifactLink = artifactLinkUrl ? (
<Link to={artifactLinkUrl} target="_blank">
<span>{`${urlParts(artifactLinkUrl).hostname} `}</span>
<FontIcon className={styles.fontIcon} value="open_in_new"/>
</Link>
) : null
 
return (
<div className={styles.details}>
<div className={styles.section}>
<Flex className={styles.list}>
<Flex className={styles.listLeftCol} flexDirection="column">
{artifactHeader}
<div>Members</div>
<div>Chapter</div>
<div>Cycle</div>
<div>State</div>
<div>Phase</div>
<div>Created on</div>
<div>Updated on</div>
</Flex>
<Flex className={styles.listRightCol} flexDirection="column">
{artifactLink}
<div>{memberList}</div>
<div>{chapter ? chapter.name : '--'}</div>
<div>{cycle ? cycle.cycleNumber : '--'}</div>
<div>{cycle ? cycle.state : '--'}</div>
<div>{phase ? phase.name : '--'}</div>
<div>{moment(project.createdAt).format('MMM DD, YYYY')}</div>
<div>{moment(project.updatedAt).format('MMM DD, YYYY')}</div>
</Flex>
</Flex>
</div>
</div>
)
}
 
renderUserSummaries() {
const {projectUserSummaries, project, unlockMemberSurvey, lockMemberSurvey, isLockingOrUnlocking} = this.props
 
const memberSummaries = (projectUserSummaries || [])
.map((userSummary, i) => {
const onUnlockMemberSurvey = () => unlockMemberSurvey(userSummary.user.id, project.id)
const onLockMemberSurvey = () => lockMemberSurvey(userSummary.user.id, project.id)
return (
<ProjectUserSummary
key={i} {...userSummary}
isLockingOrUnlocking={isLockingOrUnlocking}
onUnlockMemberSurvey={onUnlockMemberSurvey}
onLockMemberSurvey={onLockMemberSurvey}
/>
)
})
 
return (
<div>
{memberSummaries.length > 0 ?
memberSummaries :
<div>No project members.</div>
}
</div>
)
}
 
renderTabs() {
const {projectUserSummaries} = this.props
const hasProjectUserSummaries = (projectUserSummaries || []).length > 0
const hasViewableProjectUserSummaries = hasProjectUserSummaries && projectUserSummaries.every(({userProjectEvaluations}) => {
return !objectValuesAreAllNull({userProjectEvaluations})
})
 
return hasViewableProjectUserSummaries ? (
<div className={styles.tabs}>
<Tabs
index={this.state.tabIndex}
theme={theme}
fixed
>
<Tab label="Team Feedback"><div>{this.renderUserSummaries()}</div></Tab>
</Tabs>
</div>
) : <div/>
}
 
render() {
if (!this.props.project) {
return null
}
 
return (
<Flex className={styles.projectDetail} column>
<Helmet>
<title>{this.props.project.name}</title>
</Helmet>
{this.renderHeader()}
{this.renderDetails()}
{this.renderTabs()}
</Flex>
)
}
}
 
ProjectDetail.propTypes = {
project: PropTypes.shape({
name: PropTypes.string,
artifactURL: PropTypes.string,
createdAt: PropTypes.date,
updatedAt: PropTypes.date,
chapter: PropTypes.shape({
name: PropTypes.string,
}),
cycle: PropTypes.shape({
cycleNumber: PropTypes.number,
state: PropTypes.string,
startTimestamp: PropTypes.date,
endTimestamp: PropTypes.date,
}),
phase: PropTypes.shape({
name: PropTypes.string,
}),
retrospectiveSurveyId: PropTypes.string,
}),
projectUserSummaries: PropTypes.array,
isLockingOrUnlocking: PropTypes.bool,
allowEdit: PropTypes.bool,
onClickEdit: PropTypes.func,
unlockMemberSurvey: PropTypes.func,
lockMemberSurvey: PropTypes.func,
}
 
export default ProjectDetail