Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/components/Grid/GridView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const GridView = props => {
const headerProps = { columns, sortHandler, currentSortField }

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

const handleLoadMore = () => {
Expand Down
2 changes: 0 additions & 2 deletions src/projects/actions/phasesTopics.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ const getPhaseTopicWithMember = (dispatch, projectId, phaseId, tag) => {
return new Promise((resolve, reject) => {
return dispatch({
type: LOAD_PHASE_FEED,
// TODO $PROJECT_PLAN$ remove getting topics for project 5021
// and uncomment calling for getting topics for phase
payload: getTopicsWithComments('project', `${projectId}`, `phase#${phaseId}`, false),
meta: { tag, phaseId }
})
Expand Down
37 changes: 35 additions & 2 deletions src/projects/actions/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ import {
MILESTONE_STATUS,
PHASE_STATUS_ACTIVE,
PHASE_DIRTY,
PHASE_DIRTY_UNDO
PHASE_DIRTY_UNDO,
PROJECT_STATUS_IN_REVIEW,
PHASE_STATUS_REVIEWED,
PROJECT_STATUS_REVIEWED,
PROJECT_STATUS_ACTIVE
} from '../../config/constants'
import {
updateProductMilestone,
Expand Down Expand Up @@ -434,7 +438,36 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
} else {
optionallyUpdateFirstMilestone()
}
return true

// update project caused by phase updates
}).then(() => {
const project = state.projectState.project

// if one phase moved to REVIEWED status, make project IN_REVIEW too
if (
_.includes([PROJECT_STATUS_DRAFT], project.status) &&
phase.status !== PHASE_STATUS_REVIEWED &&
updatedProps.status === PHASE_STATUS_REVIEWED
) {
dispatch(
updateProject(projectId, {
status: PROJECT_STATUS_IN_REVIEW
}, true)
)
}

// if one phase moved to ACTIVE status, make project ACTIVE too
if (
_.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) &&
phase.status !== PHASE_STATUS_ACTIVE &&
updatedProps.status === PHASE_STATUS_ACTIVE
) {
dispatch(
updateProject(projectId, {
status: PROJECT_STATUS_ACTIVE
}, true)
)
}
})
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/projects/detail/components/SpecSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,15 @@ const SpecSection = props => {
}
case 'project-name': {
const refCodeFieldName = 'details.utm.code'
const refCode = _.get(project, refCodeFieldName, undefined)
const refCode = _.get(project, refCodeFieldName, '')
const queryParamRefCode = qs.parse(window.location.search).refCode
return (
<div className="project-name-section">
<div className="editable-project-name">
<TCFormFields.TextInput
name="name"
placeholder="Project Name"
value={_.get(project, 'name', undefined)}
value={_.get(project, 'name', '')}
wrapperClass="project-name"
maxLength={ PROJECT_NAME_MAX_LENGTH }
required={props.required}
Expand Down Expand Up @@ -265,9 +265,9 @@ SpecSection.propTypes = {
sectionNumber: PropTypes.number.isRequired,
showHidden: PropTypes.bool,
isCreation: PropTypes.bool,
addAttachment: PropTypes.func.isRequired,
updateAttachment: PropTypes.func.isRequired,
removeAttachment: PropTypes.func.isRequired,
addAttachment: PropTypes.func,
updateAttachment: PropTypes.func,
removeAttachment: PropTypes.func,
}

export default scrollToAnchors(SpecSection)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*
* Renders one milestone in timeline. Inside it renders:
* - milestone title
* - milestone description
* - milestone edit form (if open)
* - component depend on the milestone type
*/
Expand Down Expand Up @@ -264,6 +263,7 @@ class Milestone extends React.Component {
<MilestoneTypePhaseSpecification
milestone={milestone}
updateMilestoneContent={this.updateMilestoneContent}
extendMilestone={this.extendMilestone}
completeMilestone={this.completeMilestone}
currentUser={currentUser}
/>
Expand All @@ -273,6 +273,7 @@ class Milestone extends React.Component {
<MilestoneTypeProgress
milestone={milestone}
updateMilestoneContent={this.updateMilestoneContent}
extendMilestone={this.extendMilestone}
completeMilestone={this.completeMilestone}
currentUser={currentUser}
/>
Expand Down Expand Up @@ -350,6 +351,7 @@ class Milestone extends React.Component {
<MilestoneTypeFinalFixes
milestone={milestone}
updateMilestoneContent={this.updateMilestoneContent}
extendMilestone={this.extendMilestone}
completeFinalFixesMilestone={this.completeFinalFixesMilestone}
submitFinalFixesRequest={this.submitFinalFixesRequest}
currentUser={currentUser}
Expand All @@ -370,6 +372,7 @@ class Milestone extends React.Component {
<MilestoneTypeDelivery
milestone={milestone}
updateMilestoneContent={this.updateMilestoneContent}
extendMilestone={this.extendMilestone}
completeMilestone={this.completeMilestone}
submitFinalFixesRequest={this.submitFinalFixesRequest}
currentUser={currentUser}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* MilestoneExtensionRequest HOC
*
* Provides the next props for component:
* - extensionRequestDialog - dialog to requests extension
* - extensionRequestButton - button to open request extension dialog
* - extensionRequestConfirmation - dialog to confirm requested extension
*/

import React from 'react'
import PT from 'prop-types'
import _ from 'lodash'

import MilestonePostMessage from '../MilestonePostMessage'

export const withMilestoneExtensionRequest = (Component) => {
class MilestoneExtensionRequest extends React.Component {
constructor(props) {
super(props)

this.state = {
isShowExtensionRequestMessage: false,
}

this.showExtensionRequestMessage = this.showExtensionRequestMessage.bind(this)
this.hideExtensionRequestMessage = this.hideExtensionRequestMessage.bind(this)
this.requestExtension = this.requestExtension.bind(this)
this.approveExtension = this.approveExtension.bind(this)
this.declineExtension = this.declineExtension.bind(this)
}

showExtensionRequestMessage() {
this.setState({
isShowExtensionRequestMessage: true,
isSelectWarningVisible: false,
})
}

hideExtensionRequestMessage() {
this.setState({ isShowExtensionRequestMessage: false })
}

requestExtension(value) {
const { updateMilestoneContent } = this.props

const extensionDuration = parseInt(value, 10)

updateMilestoneContent({
extensionRequest: {
duration: extensionDuration,
}
})
}

declineExtension() {
const { updateMilestoneContent } = this.props

updateMilestoneContent({
extensionRequest: null,
})
}

approveExtension() {
const { extendMilestone, milestone } = this.props
const content = _.get(milestone, 'details.content')
const extensionRequest = _.get(milestone, 'details.content.extensionRequest')

extendMilestone(extensionRequest.duration, {
details: {
...milestone.details,
content: {
...content,
extensionRequest: null,
}
}
})
}

render() {
const { milestone } = this.props
const { isShowExtensionRequestMessage } = this.state

const extensionRequest = _.get(milestone, 'details.content.extensionRequest')

const extensionRequestDialog = isShowExtensionRequestMessage ? (
<MilestonePostMessage
label={'Milestone extension request'}
theme="warning"
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.'}
isShowSelection
buttons={[
{ title: 'Cancel', onClick: this.hideExtensionRequestMessage, type: 'default' },
{ title: 'Request extension', onClick: this.requestExtension, type: 'warning' },
]}
/>
) : null

const extensionRequestButton = !extensionRequest ? (
<button
className={'tc-btn tc-btn-warning'}
onClick={this.showExtensionRequestMessage}
>
Request Extension
</button>
) : null

const extensionRequestConfirmation = extensionRequest ? (
<MilestonePostMessage
label="Milestone extension requested"
theme="primary"
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.`}
buttons={[
{ title: 'Decline extension', onClick: this.declineExtension, type: 'warning' },
{ title: 'Approve extension', onClick: this.approveExtension, type: 'primary' },
]}
/>
) : null

return (
<Component
{...{
...this.props,
extensionRequestDialog,
extensionRequestButton,
extensionRequestConfirmation,
}}
/>
)
}
}

MilestoneExtensionRequest.propTypes = {
extendMilestone: PT.func.isRequired,
milestone: PT.object.isRequired,
updateMilestoneContent: PT.func.isRequired,
}

return MilestoneExtensionRequest
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { withMilestoneExtensionRequest } from './MilestoneExtensionRequest'
export { withMilestoneExtensionRequest }
Loading