Skip to content

Commit ceaf6b8

Browse files
author
vikasrohit
authored
Merge pull request #2425 from appirio-tech/feature/v2-4-5
Feature/v2 4 5
2 parents f273453 + af7f759 commit ceaf6b8

File tree

21 files changed

+491
-557
lines changed

21 files changed

+491
-557
lines changed

src/components/Grid/GridView.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const GridView = props => {
1818
const headerProps = { columns, sortHandler, currentSortField }
1919

2020
const renderItem = (item, index) => {
21-
return item.isPlaceholder ? <Placeholder columns={columns} /> : <ListComponent columns={columns} item={item} key={index}/>
21+
return item.isPlaceholder ? <Placeholder columns={columns} key={`placeholder-${index}`} /> : <ListComponent columns={columns} item={item} key={item.id}/>
2222
}
2323

2424
const handleLoadMore = () => {

src/projects/actions/phasesTopics.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ const getPhaseTopicWithMember = (dispatch, projectId, phaseId, tag) => {
3737
return new Promise((resolve, reject) => {
3838
return dispatch({
3939
type: LOAD_PHASE_FEED,
40-
// TODO $PROJECT_PLAN$ remove getting topics for project 5021
41-
// and uncomment calling for getting topics for phase
4240
payload: getTopicsWithComments('project', `${projectId}`, `phase#${phaseId}`, false),
4341
meta: { tag, phaseId }
4442
})

src/projects/actions/project.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ import {
4444
MILESTONE_STATUS,
4545
PHASE_STATUS_ACTIVE,
4646
PHASE_DIRTY,
47-
PHASE_DIRTY_UNDO
47+
PHASE_DIRTY_UNDO,
48+
PROJECT_STATUS_IN_REVIEW,
49+
PHASE_STATUS_REVIEWED,
50+
PROJECT_STATUS_REVIEWED,
51+
PROJECT_STATUS_ACTIVE
4852
} from '../../config/constants'
4953
import {
5054
updateProductMilestone,
@@ -434,7 +438,36 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
434438
} else {
435439
optionallyUpdateFirstMilestone()
436440
}
437-
return true
441+
442+
// update project caused by phase updates
443+
}).then(() => {
444+
const project = state.projectState.project
445+
446+
// if one phase moved to REVIEWED status, make project IN_REVIEW too
447+
if (
448+
_.includes([PROJECT_STATUS_DRAFT], project.status) &&
449+
phase.status !== PHASE_STATUS_REVIEWED &&
450+
updatedProps.status === PHASE_STATUS_REVIEWED
451+
) {
452+
dispatch(
453+
updateProject(projectId, {
454+
status: PROJECT_STATUS_IN_REVIEW
455+
}, true)
456+
)
457+
}
458+
459+
// if one phase moved to ACTIVE status, make project ACTIVE too
460+
if (
461+
_.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) &&
462+
phase.status !== PHASE_STATUS_ACTIVE &&
463+
updatedProps.status === PHASE_STATUS_ACTIVE
464+
) {
465+
dispatch(
466+
updateProject(projectId, {
467+
status: PROJECT_STATUS_ACTIVE
468+
}, true)
469+
)
470+
}
438471
})
439472
}
440473
}

src/projects/detail/components/SpecSection.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,15 @@ const SpecSection = props => {
196196
}
197197
case 'project-name': {
198198
const refCodeFieldName = 'details.utm.code'
199-
const refCode = _.get(project, refCodeFieldName, undefined)
199+
const refCode = _.get(project, refCodeFieldName, '')
200200
const queryParamRefCode = qs.parse(window.location.search).refCode
201201
return (
202202
<div className="project-name-section">
203203
<div className="editable-project-name">
204204
<TCFormFields.TextInput
205205
name="name"
206206
placeholder="Project Name"
207-
value={_.get(project, 'name', undefined)}
207+
value={_.get(project, 'name', '')}
208208
wrapperClass="project-name"
209209
maxLength={ PROJECT_NAME_MAX_LENGTH }
210210
required={props.required}
@@ -265,9 +265,9 @@ SpecSection.propTypes = {
265265
sectionNumber: PropTypes.number.isRequired,
266266
showHidden: PropTypes.bool,
267267
isCreation: PropTypes.bool,
268-
addAttachment: PropTypes.func.isRequired,
269-
updateAttachment: PropTypes.func.isRequired,
270-
removeAttachment: PropTypes.func.isRequired,
268+
addAttachment: PropTypes.func,
269+
updateAttachment: PropTypes.func,
270+
removeAttachment: PropTypes.func,
271271
}
272272

273273
export default scrollToAnchors(SpecSection)

src/projects/detail/components/timeline/Milestone/Milestone.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
*
44
* Renders one milestone in timeline. Inside it renders:
55
* - milestone title
6-
* - milestone description
76
* - milestone edit form (if open)
87
* - component depend on the milestone type
98
*/
@@ -264,6 +263,7 @@ class Milestone extends React.Component {
264263
<MilestoneTypePhaseSpecification
265264
milestone={milestone}
266265
updateMilestoneContent={this.updateMilestoneContent}
266+
extendMilestone={this.extendMilestone}
267267
completeMilestone={this.completeMilestone}
268268
currentUser={currentUser}
269269
/>
@@ -273,6 +273,7 @@ class Milestone extends React.Component {
273273
<MilestoneTypeProgress
274274
milestone={milestone}
275275
updateMilestoneContent={this.updateMilestoneContent}
276+
extendMilestone={this.extendMilestone}
276277
completeMilestone={this.completeMilestone}
277278
currentUser={currentUser}
278279
/>
@@ -350,6 +351,7 @@ class Milestone extends React.Component {
350351
<MilestoneTypeFinalFixes
351352
milestone={milestone}
352353
updateMilestoneContent={this.updateMilestoneContent}
354+
extendMilestone={this.extendMilestone}
353355
completeFinalFixesMilestone={this.completeFinalFixesMilestone}
354356
submitFinalFixesRequest={this.submitFinalFixesRequest}
355357
currentUser={currentUser}
@@ -370,6 +372,7 @@ class Milestone extends React.Component {
370372
<MilestoneTypeDelivery
371373
milestone={milestone}
372374
updateMilestoneContent={this.updateMilestoneContent}
375+
extendMilestone={this.extendMilestone}
373376
completeMilestone={this.completeMilestone}
374377
submitFinalFixesRequest={this.submitFinalFixesRequest}
375378
currentUser={currentUser}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* MilestoneExtensionRequest HOC
3+
*
4+
* Provides the next props for component:
5+
* - extensionRequestDialog - dialog to requests extension
6+
* - extensionRequestButton - button to open request extension dialog
7+
* - extensionRequestConfirmation - dialog to confirm requested extension
8+
*/
9+
10+
import React from 'react'
11+
import PT from 'prop-types'
12+
import _ from 'lodash'
13+
14+
import MilestonePostMessage from '../MilestonePostMessage'
15+
16+
export const withMilestoneExtensionRequest = (Component) => {
17+
class MilestoneExtensionRequest extends React.Component {
18+
constructor(props) {
19+
super(props)
20+
21+
this.state = {
22+
isShowExtensionRequestMessage: false,
23+
}
24+
25+
this.showExtensionRequestMessage = this.showExtensionRequestMessage.bind(this)
26+
this.hideExtensionRequestMessage = this.hideExtensionRequestMessage.bind(this)
27+
this.requestExtension = this.requestExtension.bind(this)
28+
this.approveExtension = this.approveExtension.bind(this)
29+
this.declineExtension = this.declineExtension.bind(this)
30+
}
31+
32+
showExtensionRequestMessage() {
33+
this.setState({
34+
isShowExtensionRequestMessage: true,
35+
isSelectWarningVisible: false,
36+
})
37+
}
38+
39+
hideExtensionRequestMessage() {
40+
this.setState({ isShowExtensionRequestMessage: false })
41+
}
42+
43+
requestExtension(value) {
44+
const { updateMilestoneContent } = this.props
45+
46+
const extensionDuration = parseInt(value, 10)
47+
48+
updateMilestoneContent({
49+
extensionRequest: {
50+
duration: extensionDuration,
51+
}
52+
})
53+
}
54+
55+
declineExtension() {
56+
const { updateMilestoneContent } = this.props
57+
58+
updateMilestoneContent({
59+
extensionRequest: null,
60+
})
61+
}
62+
63+
approveExtension() {
64+
const { extendMilestone, milestone } = this.props
65+
const content = _.get(milestone, 'details.content')
66+
const extensionRequest = _.get(milestone, 'details.content.extensionRequest')
67+
68+
extendMilestone(extensionRequest.duration, {
69+
details: {
70+
...milestone.details,
71+
content: {
72+
...content,
73+
extensionRequest: null,
74+
}
75+
}
76+
})
77+
}
78+
79+
render() {
80+
const { milestone } = this.props
81+
const { isShowExtensionRequestMessage } = this.state
82+
83+
const extensionRequest = _.get(milestone, 'details.content.extensionRequest')
84+
85+
const extensionRequestDialog = isShowExtensionRequestMessage ? (
86+
<MilestonePostMessage
87+
label={'Milestone extension request'}
88+
theme="warning"
89+
message={'Be careful, requesting extensions will change the project overall milestone. Proceed with caution and only if there are not enough submissions to satisfy our delivery policy.'}
90+
isShowSelection
91+
buttons={[
92+
{ title: 'Cancel', onClick: this.hideExtensionRequestMessage, type: 'default' },
93+
{ title: 'Request extension', onClick: this.requestExtension, type: 'warning' },
94+
]}
95+
/>
96+
) : null
97+
98+
const extensionRequestButton = !extensionRequest ? (
99+
<button
100+
className={'tc-btn tc-btn-warning'}
101+
onClick={this.showExtensionRequestMessage}
102+
>
103+
Request Extension
104+
</button>
105+
) : null
106+
107+
const extensionRequestConfirmation = extensionRequest ? (
108+
<MilestonePostMessage
109+
label="Milestone extension requested"
110+
theme="primary"
111+
message={`Due to unusually high load on our network we had less than the minimum number or design submissions. In order to provide you with the appropriate number of design options we’ll have to extend the milestone with ${extensionRequest.duration * 24}h. This time would be enough to increase the capacity and make sure your project is successful.<br /><br />Please make a decision in the next 24h. After that we will automatically extend the project to make sure we deliver success to you.`}
112+
buttons={[
113+
{ title: 'Decline extension', onClick: this.declineExtension, type: 'warning' },
114+
{ title: 'Approve extension', onClick: this.approveExtension, type: 'primary' },
115+
]}
116+
/>
117+
) : null
118+
119+
return (
120+
<Component
121+
{...{
122+
...this.props,
123+
extensionRequestDialog,
124+
extensionRequestButton,
125+
extensionRequestConfirmation,
126+
}}
127+
/>
128+
)
129+
}
130+
}
131+
132+
MilestoneExtensionRequest.propTypes = {
133+
extendMilestone: PT.func.isRequired,
134+
milestone: PT.object.isRequired,
135+
updateMilestoneContent: PT.func.isRequired,
136+
}
137+
138+
return MilestoneExtensionRequest
139+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { withMilestoneExtensionRequest } from './MilestoneExtensionRequest'
2+
export { withMilestoneExtensionRequest }

0 commit comments

Comments
 (0)