Skip to content

Commit 8060869

Browse files
authored
Merge pull request #2456 from appirio-tech/feature/v2-4-5-part3
Feature/v2 4 5 part3
2 parents 0f7b034 + 3b72db3 commit 8060869

File tree

15 files changed

+329
-145
lines changed

15 files changed

+329
-145
lines changed

src/config/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ export const DELETE_PHASE_FEED_COMMENT_PENDING = 'DELETE_PHASE_FEED_COMMENT_PEN
186186
export const DELETE_PHASE_FEED_COMMENT_SUCCESS = 'DELETE_PHASE_FEED_COMMENT_SUCCESS'
187187
export const DELETE_PHASE_FEED_COMMENT_FAILURE = 'DELETE_PHASE_FEED_COMMENT_FAILURE'
188188

189+
export const EXPAND_PROJECT_PHASE = 'EXPAND_PROJECT_PHASE'
190+
export const COLLAPSE_PROJECT_PHASE = 'COLLAPSE_PROJECT_PHASE'
191+
export const COLLAPSE_ALL_PROJECT_PHASES = 'COLLAPSE_ALL_PROJECT_PHASES'
192+
189193
// Project Sort
190194
export const PROJECT_SORT = 'PROJECT_SORT'
191195
export const PROJECT_SORT_FAILURE = 'PROJECT_SORT_FAILURE'

src/projects/actions/project.js

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,56 @@ import {
4848
PROJECT_STATUS_IN_REVIEW,
4949
PHASE_STATUS_REVIEWED,
5050
PROJECT_STATUS_REVIEWED,
51-
PROJECT_STATUS_ACTIVE
51+
PROJECT_STATUS_ACTIVE,
52+
EXPAND_PROJECT_PHASE,
53+
COLLAPSE_PROJECT_PHASE,
54+
COLLAPSE_ALL_PROJECT_PHASES,
5255
} from '../../config/constants'
5356
import {
5457
updateProductMilestone,
5558
updateProductTimeline
5659
} from './productsTimelines'
5760

61+
/**
62+
* Expand phase and optionaly expand particular tab
63+
*
64+
* @param {Number} phaseId phase id
65+
* @param {String} tab (optional) tab id
66+
*/
67+
export function expandProjectPhase(phaseId, tab) {
68+
return (dispatch) => {
69+
return dispatch({
70+
type: EXPAND_PROJECT_PHASE,
71+
payload: { phaseId, tab }
72+
})
73+
}
74+
}
75+
76+
/**
77+
* Collapse phase
78+
*
79+
* @param {Number} phaseId phase id
80+
*/
81+
export function collapseProjectPhase(phaseId) {
82+
return (dispatch) => {
83+
return dispatch({
84+
type: COLLAPSE_PROJECT_PHASE,
85+
payload: { phaseId }
86+
})
87+
}
88+
}
89+
90+
/**
91+
* Collapse all phases and reset tabs to default
92+
*/
93+
export function collapseAllProjectPhases() {
94+
return (dispatch) => {
95+
return dispatch({
96+
type: COLLAPSE_ALL_PROJECT_PHASES,
97+
})
98+
}
99+
}
100+
58101
export function loadProject(projectId) {
59102
return (dispatch) => {
60103
return dispatch({
@@ -446,7 +489,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
446489

447490
// if one phase moved to REVIEWED status, make project IN_REVIEW too
448491
if (
449-
_.includes([PROJECT_STATUS_DRAFT], project.status) &&
492+
_.includes([PROJECT_STATUS_DRAFT], project.status) &&
450493
phase.status !== PHASE_STATUS_REVIEWED &&
451494
updatedProps.status === PHASE_STATUS_REVIEWED
452495
) {
@@ -459,7 +502,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
459502

460503
// if one phase moved to ACTIVE status, make project ACTIVE too
461504
if (
462-
_.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) &&
505+
_.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) &&
463506
phase.status !== PHASE_STATUS_ACTIVE &&
464507
updatedProps.status === PHASE_STATUS_ACTIVE
465508
) {

src/projects/detail/ProjectDetail.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { connect } from 'react-redux'
66
import _ from 'lodash'
77
import { renderComponent, branch, compose, withProps } from 'recompose'
88
import { loadProjectDashboard } from '../actions/projectDashboard'
9+
import { clearLoadedProject } from '../actions/project'
910
import {
1011
LOAD_PROJECT_FAILURE, PROJECT_ROLE_CUSTOMER, PROJECT_ROLE_OWNER,
1112
ROLE_ADMINISTRATOR, ROLE_CONNECT_ADMIN, ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER
@@ -77,6 +78,10 @@ class ProjectDetail extends Component {
7778
this.props.loadProjectDashboard(projectId)
7879
}
7980

81+
componentWillUnmount() {
82+
this.props.clearLoadedProject()
83+
}
84+
8085
componentWillReceiveProps({isProcessing, isLoading, error, project, match}) {
8186
// handle just deleted projects
8287
if (! (error || isLoading || isProcessing) && _.isEmpty(project))
@@ -138,7 +143,7 @@ const mapStateToProps = ({projectState, projectDashboard, loadUser, productsTime
138143
}
139144
}
140145

141-
const mapDispatchToProps = { loadProjectDashboard }
146+
const mapDispatchToProps = { loadProjectDashboard, clearLoadedProject }
142147

143148
ProjectDetail.propTypes = {
144149
project: PropTypes.object,

src/projects/detail/components/PhaseCard/PhaseCard.jsx

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ class PhaseCard extends React.Component {
3737
this.onClose = this.onClose.bind(this)
3838

3939
this.state = {
40-
isExpanded: '',
4140
isEditting: false,
42-
isDetailView: false
4341
}
4442
}
4543

@@ -56,11 +54,11 @@ class PhaseCard extends React.Component {
5654
}
5755

5856
toggleCardView() {
59-
this.setState({
60-
isDetailView: true,
61-
isExpanded: !this.state.isExpanded
62-
63-
})
57+
if (this.props.isExpanded) {
58+
this.props.collapseProjectPhase(this.props.phaseId)
59+
} else {
60+
this.props.expandProjectPhase(this.props.phaseId)
61+
}
6462
}
6563

6664
toggleEditView(e) {
@@ -71,10 +69,7 @@ class PhaseCard extends React.Component {
7169
}
7270

7371
onClose(){
74-
this.setState({
75-
isDetailView: false,
76-
isExpanded: false
77-
})
72+
this.props.collapseProjectPhase(this.props.phaseId)
7873
}
7974

8075
render() {
@@ -86,6 +81,8 @@ class PhaseCard extends React.Component {
8681
isUpdating,
8782
timeline,
8883
hasReadPosts,
84+
phaseId,
85+
isExpanded,
8986
} = this.props
9087
const progressInPercent = attr.progressInPercent || 0
9188

@@ -99,12 +96,12 @@ class PhaseCard extends React.Component {
9996
const hasUnseen = hasReadPosts
10097

10198
return (
102-
<div styleName={'phase-card ' + (this.state.isExpanded ? ' expanded ' : ' ')}>
99+
<div styleName={'phase-card ' + (isExpanded ? ' expanded ' : ' ')} id={`phase-${phaseId}`}>
103100
{
104101
<MediaQuery minWidth={SCREEN_BREAKPOINT_MD}>
105-
{(matches) => (matches || !this.state.isDetailView ? (
102+
{(matches) => (matches || !isExpanded ? (
106103
<div>
107-
<div styleName={cn('static-view', { 'has-unseen': hasUnseen && !this.state.isExpanded })} onClick={!this.state.isEditting && this.toggleCardView }>
104+
<div styleName={cn('static-view', { 'has-unseen': hasUnseen && !isExpanded })} onClick={!this.state.isEditting && this.toggleCardView }>
108105
<div styleName="col">
109106
<div styleName="project-details">
110107
<div styleName="project-ico">
@@ -191,26 +188,28 @@ class PhaseCard extends React.Component {
191188
{!this.state.isEditting && (<div styleName="expandable-view">
192189
{this.props.children}
193190
</div>)}
194-
{(<div styleName={'sm-separator ' + ((!isManageUser || !this.state.isEditting) ? 'hide ': '')} >
195-
{!isUpdating && (
196-
<EditStageForm
197-
phase={attr.phase}
198-
phaseIndex={attr.phaseIndex}
199-
cancel={this.toggleEditView}
200-
timeline={timeline}
201-
/>
202-
)}
203-
{canDelete && !isUpdating && (
204-
<DeletePhase
205-
onDeleteClick={() => {
206-
if (confirm(`Are you sure you want to delete phase '${attr.phase.name}'?`)) {
207-
deleteProjectPhase()
208-
}
209-
}}
210-
/>
211-
)}
212-
{isUpdating && <LoadingIndicator />}
213-
</div>)}
191+
{isManageUser && this.state.isEditting && (
192+
<div styleName="sm-separator">
193+
{!isUpdating && (
194+
<EditStageForm
195+
phase={attr.phase}
196+
phaseIndex={attr.phaseIndex}
197+
cancel={this.toggleEditView}
198+
timeline={timeline}
199+
/>
200+
)}
201+
{canDelete && !isUpdating && (
202+
<DeletePhase
203+
onDeleteClick={() => {
204+
if (confirm(`Are you sure you want to delete phase '${attr.phase.name}'?`)) {
205+
deleteProjectPhase()
206+
}
207+
}}
208+
/>
209+
)}
210+
{isUpdating && <LoadingIndicator />}
211+
</div>
212+
)}
214213
</div>
215214
):(
216215
<MobilePage>
@@ -248,14 +247,15 @@ PhaseCard.propTypes = {
248247
attr: PT.shape({
249248
duration: PT.string.isRequired,
250249
icon: PT.string.isRequired,
251-
isExpanded: PT.bool,
252250
paidStatus: PT.string.isRequired,
253251
posts: PT.string,
254252
startEndDates: PT.string.isRequired,
255253
status: PT.string.isRequired,
256254
title: PT.string.isRequired,
257255
hasReadPosts: PT.bool,
258-
})
256+
}),
257+
phaseId: PT.number.isRequired,
258+
isExpanded: PT.bool,
259259
}
260260

261261

src/projects/detail/components/PhaseCard/PhaseCard.scss

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@
206206
display: flex;
207207
align-items: center;
208208
position: relative;
209-
justify-content: space-between;
209+
justify-content: flex-start;
210+
211+
@media screen and (max-width: $screen-md - 1px) {
212+
justify-content: space-between;
213+
}
210214
}
211215
.edit-btn {
212216
width: 40px;
@@ -215,7 +219,11 @@
215219
background-size: 15px;
216220
cursor: pointer;
217221
transition: 0.25s;
218-
margin: auto auto auto 0;
222+
flex: 0 0 40px;
223+
224+
@media screen and (max-width: $screen-md - 1px) {
225+
margin-right: -30px;
226+
}
219227
}
220228
.toggle-arrow {
221229
position: absolute;

src/projects/detail/components/ProjectStage.jsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import React from 'react'
55
import PT from 'prop-types'
66
import _ from 'lodash'
7-
import uncontrollable from 'uncontrollable'
87

98
import { formatNumberWithCommas } from '../../../helpers/format'
109
import { getPhaseActualData } from '../../../helpers/projectHelper'
@@ -93,6 +92,7 @@ class ProjectStage extends React.Component{
9392
this.removeProductAttachment = this.removeProductAttachment.bind(this)
9493
this.updateProductAttachment = this.updateProductAttachment.bind(this)
9594
this.addProductAttachment = this.addProductAttachment.bind(this)
95+
this.onTabClick = this.onTabClick.bind(this)
9696
}
9797

9898
removeProductAttachment(attachmentId) {
@@ -116,9 +116,14 @@ class ProjectStage extends React.Component{
116116
addProductAttachment(project.id, phase.id, product.id, attachment)
117117
}
118118

119+
onTabClick(tab) {
120+
const { expandProjectPhase, phase } = this.props
121+
122+
expandProjectPhase(phase.id, tab)
123+
}
124+
119125
render() {
120126
const {
121-
activeTab,
122127
phase,
123128
phaseIndex,
124129
project,
@@ -130,8 +135,10 @@ class ProjectStage extends React.Component{
130135
updateProduct,
131136
fireProductDirty,
132137
fireProductDirtyUndo,
133-
onTabClick,
134138
deleteProjectPhase,
139+
phaseState,
140+
collapseProjectPhase,
141+
expandProjectPhase,
135142

136143
// comes from phaseFeedHOC
137144
currentUser,
@@ -156,7 +163,7 @@ class ProjectStage extends React.Component{
156163

157164
const hasTimeline = !!timeline
158165
const defaultActiveTab = hasTimeline ? 'timeline' : 'posts'
159-
const currentActiveTab = activeTab ? activeTab : defaultActiveTab
166+
const currentActiveTab = _.get(phaseState, 'tab', defaultActiveTab)
160167
const postNotifications = filterNotificationsByPosts(notifications, _.get(feed, 'posts', []))
161168
const unreadPostNotifications = filterReadNotifications(postNotifications)
162169
const hasReadPosts = unreadPostNotifications.length > 0
@@ -169,11 +176,15 @@ class ProjectStage extends React.Component{
169176
deleteProjectPhase={() => deleteProjectPhase(project.id, phase.id)}
170177
timeline={timeline}
171178
hasReadPosts={hasReadPosts}
179+
phaseId={phase.id}
180+
isExpanded={_.get(phaseState, 'isExpanded')}
181+
collapseProjectPhase={collapseProjectPhase}
182+
expandProjectPhase={expandProjectPhase}
172183
>
173184
<div>
174185
<ProjectStageTabs
175186
activeTab={currentActiveTab}
176-
onTabClick={onTabClick}
187+
onTabClick={this.onTabClick}
177188
isSuperUser={isSuperUser}
178189
isManageUser={isManageUser}
179190
hasTimeline={hasTimeline}
@@ -225,13 +236,10 @@ class ProjectStage extends React.Component{
225236
}
226237

227238
ProjectStage.defaultProps = {
228-
activeTab: '',
229239
currentMemberRole: null,
230240
}
231241

232242
ProjectStage.propTypes = {
233-
activeTab: PT.string,
234-
onTabClick: PT.func.isRequired,
235243
project: PT.object.isRequired,
236244
currentMemberRole: PT.string,
237245
isProcessing: PT.bool.isRequired,
@@ -245,8 +253,4 @@ ProjectStage.propTypes = {
245253
deleteProjectPhase: PT.func.isRequired,
246254
}
247255

248-
const ProjectStageUncontrollable = uncontrollable(ProjectStage, {
249-
activeTab: 'onTabClick',
250-
})
251-
252-
export default phaseFeedHOC(ProjectStageUncontrollable)
256+
export default phaseFeedHOC(ProjectStage)

src/projects/detail/components/ProjectStages.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ function formatPhaseCardListFooterProps(phases, productsTimelines) {
6161
const ProjectStages = ({
6262
project,
6363
phases,
64+
phasesStates,
6465
productTemplates,
6566
productsTimelines,
6667
currentMemberRole,
@@ -74,6 +75,8 @@ const ProjectStages = ({
7475
removeProductAttachment,
7576
isManageUser,
7677
deleteProjectPhase,
78+
expandProjectPhase,
79+
collapseProjectPhase,
7780
}) => (
7881
<Section>
7982

@@ -82,6 +85,7 @@ const ProjectStages = ({
8285
phases.map((phase, index) => (
8386
<ProjectStage
8487
key={phase.id}
88+
phaseState={phasesStates[phase.id]}
8589
productTemplates={productTemplates}
8690
currentMemberRole={currentMemberRole}
8791
isProcessing={isProcessing}
@@ -97,6 +101,8 @@ const ProjectStages = ({
97101
updateProductAttachment={updateProductAttachment}
98102
removeProductAttachment={removeProductAttachment}
99103
deleteProjectPhase={deleteProjectPhase}
104+
expandProjectPhase={expandProjectPhase}
105+
collapseProjectPhase={collapseProjectPhase}
100106
/>
101107
))
102108
}

0 commit comments

Comments
 (0)