From 1d9404b999e5cee391780de8f9e8b46f56b1433b Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Tue, 28 Aug 2018 19:47:45 +0800 Subject: [PATCH 1/6] issue #2355 - Discussion on project is sometimes displaying other project discussion seeming from browser cache. --- src/projects/detail/ProjectDetail.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/projects/detail/ProjectDetail.jsx b/src/projects/detail/ProjectDetail.jsx index fc6bec1e2..6a8edbad6 100644 --- a/src/projects/detail/ProjectDetail.jsx +++ b/src/projects/detail/ProjectDetail.jsx @@ -6,6 +6,7 @@ import { connect } from 'react-redux' import _ from 'lodash' import { renderComponent, branch, compose, withProps } from 'recompose' import { loadProjectDashboard } from '../actions/projectDashboard' +import { clearLoadedProject } from '../actions/project' import { LOAD_PROJECT_FAILURE, PROJECT_ROLE_CUSTOMER, PROJECT_ROLE_OWNER, ROLE_ADMINISTRATOR, ROLE_CONNECT_ADMIN, ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER @@ -77,6 +78,10 @@ class ProjectDetail extends Component { this.props.loadProjectDashboard(projectId) } + componentWillUnmount() { + this.props.clearLoadedProject() + } + componentWillReceiveProps({isProcessing, isLoading, error, project, match}) { // handle just deleted projects if (! (error || isLoading || isProcessing) && _.isEmpty(project)) @@ -138,7 +143,7 @@ const mapStateToProps = ({projectState, projectDashboard, loadUser, productsTime } } -const mapDispatchToProps = { loadProjectDashboard } +const mapDispatchToProps = { loadProjectDashboard, clearLoadedProject } ProjectDetail.propTypes = { project: PropTypes.object, From f7164abf6cac04923fc576a925f9b1065153859c Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 29 Aug 2018 11:28:40 +0800 Subject: [PATCH 2/6] issue #2445 - List the phase topic in the left panel --- src/config/constants.js | 4 + src/projects/actions/project.js | 49 ++++- .../detail/components/PhaseCard/PhaseCard.jsx | 30 ++- .../detail/components/ProjectStage.jsx | 30 +-- .../detail/components/ProjectStages.jsx | 6 + .../WorkInProgress/WorkInProgress.jsx | 3 +- .../detail/containers/DashboardContainer.jsx | 30 ++- .../detail/containers/ProjectInfoContainer.js | 4 +- .../containers/ProjectPlanContainer.jsx | 186 +++++++++++------- src/projects/reducers/project.js | 49 ++++- 10 files changed, 280 insertions(+), 111 deletions(-) diff --git a/src/config/constants.js b/src/config/constants.js index 690231fcf..a059be99e 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -186,6 +186,10 @@ export const DELETE_PHASE_FEED_COMMENT_PENDING = 'DELETE_PHASE_FEED_COMMENT_PEN export const DELETE_PHASE_FEED_COMMENT_SUCCESS = 'DELETE_PHASE_FEED_COMMENT_SUCCESS' export const DELETE_PHASE_FEED_COMMENT_FAILURE = 'DELETE_PHASE_FEED_COMMENT_FAILURE' +export const EXPAND_PROJECT_PHASE = 'EXPAND_PROJECT_PHASE' +export const COLLAPSE_PROJECT_PHASE = 'COLLAPSE_PROJECT_PHASE' +export const COLLAPSE_ALL_PROJECT_PHASES = 'COLLAPSE_ALL_PROJECT_PHASES' + // Project Sort export const PROJECT_SORT = 'PROJECT_SORT' export const PROJECT_SORT_FAILURE = 'PROJECT_SORT_FAILURE' diff --git a/src/projects/actions/project.js b/src/projects/actions/project.js index 508e10c82..da6513e10 100644 --- a/src/projects/actions/project.js +++ b/src/projects/actions/project.js @@ -48,13 +48,56 @@ import { PROJECT_STATUS_IN_REVIEW, PHASE_STATUS_REVIEWED, PROJECT_STATUS_REVIEWED, - PROJECT_STATUS_ACTIVE + PROJECT_STATUS_ACTIVE, + EXPAND_PROJECT_PHASE, + COLLAPSE_PROJECT_PHASE, + COLLAPSE_ALL_PROJECT_PHASES, } from '../../config/constants' import { updateProductMilestone, updateProductTimeline } from './productsTimelines' +/** + * Expand phase and optionaly expand particular tab + * + * @param {Number} phaseId phase id + * @param {String} tab (optional) tab id + */ +export function expandProjectPhase(phaseId, tab) { + return (dispatch) => { + return dispatch({ + type: EXPAND_PROJECT_PHASE, + payload: { phaseId, tab } + }) + } +} + +/** + * Collapse phase + * + * @param {Number} phaseId phase id + */ +export function collapseProjectPhase(phaseId) { + return (dispatch) => { + return dispatch({ + type: COLLAPSE_PROJECT_PHASE, + payload: { phaseId } + }) + } +} + +/** + * Collapse all phases and reset tabs to default + */ +export function collapseAllProjectPhases() { + return (dispatch) => { + return dispatch({ + type: COLLAPSE_ALL_PROJECT_PHASES, + }) + } +} + export function loadProject(projectId) { return (dispatch) => { return dispatch({ @@ -446,7 +489,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) { // if one phase moved to REVIEWED status, make project IN_REVIEW too if ( - _.includes([PROJECT_STATUS_DRAFT], project.status) && + _.includes([PROJECT_STATUS_DRAFT], project.status) && phase.status !== PHASE_STATUS_REVIEWED && updatedProps.status === PHASE_STATUS_REVIEWED ) { @@ -459,7 +502,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) { // 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) && + _.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) && phase.status !== PHASE_STATUS_ACTIVE && updatedProps.status === PHASE_STATUS_ACTIVE ) { diff --git a/src/projects/detail/components/PhaseCard/PhaseCard.jsx b/src/projects/detail/components/PhaseCard/PhaseCard.jsx index 3c3d439f2..6dc446638 100644 --- a/src/projects/detail/components/PhaseCard/PhaseCard.jsx +++ b/src/projects/detail/components/PhaseCard/PhaseCard.jsx @@ -37,9 +37,7 @@ class PhaseCard extends React.Component { this.onClose = this.onClose.bind(this) this.state = { - isExpanded: '', isEditting: false, - isDetailView: false } } @@ -56,11 +54,11 @@ class PhaseCard extends React.Component { } toggleCardView() { - this.setState({ - isDetailView: true, - isExpanded: !this.state.isExpanded - - }) + if (this.props.isExpanded) { + this.props.collapseProjectPhase(this.props.phaseId) + } else { + this.props.expandProjectPhase(this.props.phaseId) + } } toggleEditView(e) { @@ -71,10 +69,7 @@ class PhaseCard extends React.Component { } onClose(){ - this.setState({ - isDetailView: false, - isExpanded: false - }) + this.props.collapseProjectPhase(this.props.phaseId) } render() { @@ -86,6 +81,8 @@ class PhaseCard extends React.Component { isUpdating, timeline, hasReadPosts, + phaseId, + isExpanded, } = this.props const progressInPercent = attr.progressInPercent || 0 @@ -99,12 +96,12 @@ class PhaseCard extends React.Component { const hasUnseen = hasReadPosts return ( -
+
{ - {(matches) => (matches || !this.state.isDetailView ? ( + {(matches) => (matches || !isExpanded ? (
-
+
@@ -248,14 +245,15 @@ PhaseCard.propTypes = { attr: PT.shape({ duration: PT.string.isRequired, icon: PT.string.isRequired, - isExpanded: PT.bool, paidStatus: PT.string.isRequired, posts: PT.string, startEndDates: PT.string.isRequired, status: PT.string.isRequired, title: PT.string.isRequired, hasReadPosts: PT.bool, - }) + }), + phaseId: PT.number.isRequired, + isExpanded: PT.bool, } diff --git a/src/projects/detail/components/ProjectStage.jsx b/src/projects/detail/components/ProjectStage.jsx index c1a793c42..946aadf52 100644 --- a/src/projects/detail/components/ProjectStage.jsx +++ b/src/projects/detail/components/ProjectStage.jsx @@ -4,7 +4,6 @@ import React from 'react' import PT from 'prop-types' import _ from 'lodash' -import uncontrollable from 'uncontrollable' import { formatNumberWithCommas } from '../../../helpers/format' import { getPhaseActualData } from '../../../helpers/projectHelper' @@ -93,6 +92,7 @@ class ProjectStage extends React.Component{ this.removeProductAttachment = this.removeProductAttachment.bind(this) this.updateProductAttachment = this.updateProductAttachment.bind(this) this.addProductAttachment = this.addProductAttachment.bind(this) + this.onTabClick = this.onTabClick.bind(this) } removeProductAttachment(attachmentId) { @@ -116,9 +116,14 @@ class ProjectStage extends React.Component{ addProductAttachment(project.id, phase.id, product.id, attachment) } + onTabClick(tab) { + const { expandProjectPhase, phase } = this.props + + expandProjectPhase(phase.id, tab) + } + render() { const { - activeTab, phase, phaseIndex, project, @@ -130,8 +135,10 @@ class ProjectStage extends React.Component{ updateProduct, fireProductDirty, fireProductDirtyUndo, - onTabClick, deleteProjectPhase, + phaseState, + collapseProjectPhase, + expandProjectPhase, // comes from phaseFeedHOC currentUser, @@ -156,7 +163,7 @@ class ProjectStage extends React.Component{ const hasTimeline = !!timeline const defaultActiveTab = hasTimeline ? 'timeline' : 'posts' - const currentActiveTab = activeTab ? activeTab : defaultActiveTab + const currentActiveTab = _.get(phaseState, 'tab', defaultActiveTab) const postNotifications = filterNotificationsByPosts(notifications, _.get(feed, 'posts', [])) const unreadPostNotifications = filterReadNotifications(postNotifications) const hasReadPosts = unreadPostNotifications.length > 0 @@ -169,11 +176,15 @@ class ProjectStage extends React.Component{ deleteProjectPhase={() => deleteProjectPhase(project.id, phase.id)} timeline={timeline} hasReadPosts={hasReadPosts} + phaseId={phase.id} + isExpanded={_.get(phaseState, 'isExpanded')} + collapseProjectPhase={collapseProjectPhase} + expandProjectPhase={expandProjectPhase} >
(
@@ -82,6 +85,7 @@ const ProjectStages = ({ phases.map((phase, index) => ( )) } diff --git a/src/projects/detail/components/WorkInProgress/WorkInProgress.jsx b/src/projects/detail/components/WorkInProgress/WorkInProgress.jsx index 071c55564..7d98561db 100644 --- a/src/projects/detail/components/WorkInProgress/WorkInProgress.jsx +++ b/src/projects/detail/components/WorkInProgress/WorkInProgress.jsx @@ -11,7 +11,7 @@ import ProjectStage from '../ProjectStage' import './WorkInProgress.scss' -const WorkInProgress = ({ activePhases, ...props }) => ( +const WorkInProgress = ({ activePhases, phasesStates, ...props }) => (
View all @@ -19,6 +19,7 @@ const WorkInProgress = ({ activePhases, ...props }) => ( {activePhases.map((activePhase) => ( diff --git a/src/projects/detail/containers/DashboardContainer.jsx b/src/projects/detail/containers/DashboardContainer.jsx index e3c76946e..acdce3493 100644 --- a/src/projects/detail/containers/DashboardContainer.jsx +++ b/src/projects/detail/containers/DashboardContainer.jsx @@ -14,7 +14,15 @@ import { filterProjectNotifications, } from '../../../routes/notifications/helpers/notifications' import { toggleNotificationRead, toggleBundledNotificationRead } from '../../../routes/notifications/actions' -import { updateProduct, fireProductDirty, fireProductDirtyUndo, deleteProjectPhase } from '../../actions/project' +import { + updateProduct, + fireProductDirty, + fireProductDirtyUndo, + deleteProjectPhase, + expandProjectPhase, + collapseProjectPhase, + collapseAllProjectPhases, +} from '../../actions/project' import { addProductAttachment, updateProductAttachment, removeProductAttachment } from '../../actions/projectAttachment' import MediaQuery from 'react-responsive' @@ -54,6 +62,12 @@ class DashboardContainer extends React.Component { } } + componentWillUnmount() { + const { collapseAllProjectPhases } = this.props + + collapseAllProjectPhases() + } + render() { const { project, @@ -72,9 +86,12 @@ class DashboardContainer extends React.Component { removeProductAttachment, deleteProjectPhase, feeds, - productsTimelines + productsTimelines, + phasesStates, + expandProjectPhase, + collapseProjectPhase, } = this.props - + // system notifications const notReadNotifications = filterReadNotifications(notifications.notifications) const unreadProjectUpdate = filterProjectNotifications(filterNotificationsByProjectId(notReadNotifications, project.id)) @@ -135,6 +152,9 @@ class DashboardContainer extends React.Component { updateProductAttachment={updateProductAttachment} removeProductAttachment={removeProductAttachment} deleteProjectPhase={deleteProjectPhase} + phasesStates={phasesStates} + expandProjectPhase={expandProjectPhase} + collapseProjectPhase={collapseProjectPhase} /> } @@ -155,6 +175,7 @@ const mapStateToProps = ({ notifications, projectState, projectTopics }) => ({ isProcessing: projectState.processing, phases: projectState.phases, feeds: projectTopics.feeds[PROJECT_FEED_TYPE_PRIMARY].topics, + phasesStates: projectState.phasesStates, }) const mapDispatchToProps = { @@ -167,6 +188,9 @@ const mapDispatchToProps = { updateProductAttachment, removeProductAttachment, deleteProjectPhase, + expandProjectPhase, + collapseProjectPhase, + collapseAllProjectPhases, } export default connect(mapStateToProps, mapDispatchToProps)(DashboardContainer) diff --git a/src/projects/detail/containers/ProjectInfoContainer.js b/src/projects/detail/containers/ProjectInfoContainer.js index ac5fe320e..c563d8862 100644 --- a/src/projects/detail/containers/ProjectInfoContainer.js +++ b/src/projects/detail/containers/ProjectInfoContainer.js @@ -8,7 +8,7 @@ import TeamManagementContainer from './TeamManagementContainer' import { updateProject, deleteProject } from '../../actions/project' import { setDuration } from '../../../helpers/projectHelper' import { PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, - DIRECT_PROJECT_URL, SALESFORCE_PROJECT_LEAD_LINK, PROJECT_STATUS_CANCELLED } from '../../../config/constants' + DIRECT_PROJECT_URL, SALESFORCE_PROJECT_LEAD_LINK, PROJECT_STATUS_CANCELLED, PROJECT_FEED_TYPE_PRIMARY } from '../../../config/constants' import ProjectInfo from '../../../components/ProjectInfo/ProjectInfo' class ProjectInfoContainer extends React.Component { @@ -133,7 +133,7 @@ class ProjectInfoContainer extends React.Component { const discussions = feeds.map((feed) => ({ title: `${feed.title}`, - address: `/projects/${project.id}#feed-${feed.id}`, + address: feed.tag === PROJECT_FEED_TYPE_PRIMARY ? `/projects/${project.id}#feed-${feed.id}` : `/projects/${project.id}/plan#phase-${feed.phaseId}`, noNewPage: true, onClick: onChannelClick ? () => onChannelClick(feed) : null, isActive: feed.id === activeChannelId, diff --git a/src/projects/detail/containers/ProjectPlanContainer.jsx b/src/projects/detail/containers/ProjectPlanContainer.jsx index a7be88c7b..6609df8a6 100644 --- a/src/projects/detail/containers/ProjectPlanContainer.jsx +++ b/src/projects/detail/containers/ProjectPlanContainer.jsx @@ -6,9 +6,18 @@ */ import React from 'react' import PT from 'prop-types' +import _ from 'lodash' import { connect } from 'react-redux' -import { updateProduct, fireProductDirty, fireProductDirtyUndo, deleteProjectPhase } from '../../actions/project' +import { + updateProduct, + fireProductDirty, + fireProductDirtyUndo, + deleteProjectPhase, + expandProjectPhase, + collapseProjectPhase, + collapseAllProjectPhases, +} from '../../actions/project' import { addProductAttachment, updateProductAttachment, removeProductAttachment } from '../../actions/projectAttachment' import TwoColsLayout from '../components/TwoColsLayout' @@ -21,78 +30,108 @@ import { SCREEN_BREAKPOINT_MD, PHASE_STATUS_DRAFT, PROJECT_STATUS_COMPLETED, PROJECT_STATUS_CANCELLED, PROJECT_FEED_TYPE_PRIMARY, PHASE_STATUS_ACTIVE } from '../../../config/constants' import Sticky from 'react-stickynode' import { Link } from 'react-router-dom' +import { scrollToHash } from '../../../components/ScrollToAnchors' import './ProjectPlanContainer.scss' -const ProjectPlanContainer = (props) => { - const { - project, - isSuperUser, - isManageUser, - currentMemberRole, - phases, - feeds, - productsTimelines - } = props - - // manager user sees all phases - // customer user doesn't see unplanned (draft) phases - const visiblePhases = phases && phases.filter((phase) => ( - isSuperUser || isManageUser || phase.status !== PHASE_STATUS_DRAFT - )) - - const activePhases = phases ? phases.filter((phase) => phase.status === PHASE_STATUS_ACTIVE) : [] - - const isProjectLive = project.status !== PROJECT_STATUS_COMPLETED && project.status !== PROJECT_STATUS_CANCELLED - - const leftArea = ( - - ) - - return ( - - - - {(matches) => { - if (matches) { - return {leftArea} - } else { - return leftArea - } - }} - - - - - {visiblePhases && visiblePhases.length > 0 ? ( - [ - activePhases.length > 0 && , - - ] - ) : ( - - )} - {isProjectLive && isManageUser && (
- Add New Phase -
)} -
- -
- ) +class ProjectPlanContainer extends React.Component { + constructor(props) { + super(props) + + this.onChannelClick = this.onChannelClick.bind(this) + } + + onChannelClick(topic) { + const { expandProjectPhase } = this.props + const phaseId = parseInt(topic.tag.replace('phase#', ''), 10) + + expandProjectPhase(phaseId, 'posts') + scrollToHash(`phase-${phaseId}`) + } + + componentWillUnmount() { + const { collapseAllProjectPhases } = this.props + + collapseAllProjectPhases() + } + + render() { + const { + project, + isSuperUser, + isManageUser, + currentMemberRole, + phases, + productsTimelines, + phasesTopics, + } = this.props + + // manager user sees all phases + // customer user doesn't see unplanned (draft) phases + const visiblePhases = phases && phases.filter((phase) => ( + isSuperUser || isManageUser || phase.status !== PHASE_STATUS_DRAFT + )) + + const activePhases = phases ? phases.filter((phase) => phase.status === PHASE_STATUS_ACTIVE) : [] + + const isProjectLive = project.status !== PROJECT_STATUS_COMPLETED && project.status !== PROJECT_STATUS_CANCELLED + // get list of phase topic in same order as phases + const topics = _.compact( + visiblePhases.map((phase) => ({ + ..._.get(phasesTopics, `[${phase.id}].topic`), + phaseId: phase.id, + })) + ) + + const leftArea = ( + + ) + + return ( + + + + {(matches) => { + if (matches) { + return {leftArea} + } else { + return leftArea + } + }} + + + + + {visiblePhases && visiblePhases.length > 0 ? ( + [ + activePhases.length > 0 && , + + ] + ) : ( + + )} + {isProjectLive && isManageUser && (
+ Add New Phase +
)} +
+ +
+ ) + } } ProjectPlanContainer.propTypes = { @@ -106,10 +145,12 @@ ProjectPlanContainer.propTypes = { productsTimelines: PT.object.isRequired, } -const mapStateToProps = ({ projectState, projectTopics }) => ({ +const mapStateToProps = ({ projectState, projectTopics, phasesTopics }) => ({ productTemplates: projectState.allProductTemplates, phases: projectState.phases, feeds: projectTopics.feeds[PROJECT_FEED_TYPE_PRIMARY].topics, + phasesTopics, + phasesStates: projectState.phasesStates, }) const mapDispatchToProps = { @@ -120,6 +161,9 @@ const mapDispatchToProps = { updateProductAttachment, removeProductAttachment, deleteProjectPhase, + expandProjectPhase, + collapseProjectPhase, + collapseAllProjectPhases, } export default connect(mapStateToProps, mapDispatchToProps)(ProjectPlanContainer) diff --git a/src/projects/reducers/project.js b/src/projects/reducers/project.js index ac9d92894..0606421c8 100644 --- a/src/projects/reducers/project.js +++ b/src/projects/reducers/project.js @@ -15,7 +15,8 @@ import { GET_PROJECTS_SUCCESS, PROJECT_DIRTY, PROJECT_DIRTY_UNDO, LOAD_PROJECT_PHASES_SUCCESS, LOAD_PROJECT_PHASES_PENDING, LOAD_PROJECT_TEMPLATE_SUCCESS, LOAD_PROJECT_PRODUCT_TEMPLATES_SUCCESS, LOAD_ALL_PRODUCT_TEMPLATES_SUCCESS, PRODUCT_DIRTY, PRODUCT_DIRTY_UNDO, UPDATE_PRODUCT_FAILURE, UPDATE_PRODUCT_SUCCESS, UPDATE_PHASE_SUCCESS, UPDATE_PHASE_PENDING, UPDATE_PHASE_FAILURE, - DELETE_PROJECT_PHASE_PENDING, DELETE_PROJECT_PHASE_SUCCESS, DELETE_PROJECT_PHASE_FAILURE, PHASE_DIRTY_UNDO, PHASE_DIRTY + DELETE_PROJECT_PHASE_PENDING, DELETE_PROJECT_PHASE_SUCCESS, DELETE_PROJECT_PHASE_FAILURE, PHASE_DIRTY_UNDO, PHASE_DIRTY, + EXPAND_PROJECT_PHASE, COLLAPSE_PROJECT_PHASE, COLLAPSE_ALL_PROJECT_PHASES, } from '../../config/constants' import _ from 'lodash' import update from 'react-addons-update' @@ -34,7 +35,8 @@ const initialState = { allProductTemplates: [], phases: null, phasesNonDirty: null, - isLoadingPhases: false + isLoadingPhases: false, + phasesStates: {} // controls opened phases and tabs of the phases } // NOTE: We should always update projectNonDirty state whenever we update the project state @@ -98,6 +100,49 @@ function getProductInPhases(phases, phaseId, productId) { export const projectState = function (state=initialState, action) { switch (action.type) { + case EXPAND_PROJECT_PHASE: { + const { phaseId, tab } = action.payload + const currentPhaseTab = state.phasesStates[phaseId] || {} + const updatedPhaseTab = { + ...currentPhaseTab, + isExpanded: true + } + if (tab) { + updatedPhaseTab.tab = tab + } + + return { + ...state, + phasesStates: { + ...state.phasesStates, + [phaseId]: updatedPhaseTab + } + } + } + + case COLLAPSE_PROJECT_PHASE: { + const { phaseId } = action.payload + const currentPhaseTab = state.phasesStates[phaseId] || {} + const updatedPhaseTab = { + ...currentPhaseTab, + isExpanded: false + } + + return { + ...state, + phasesStates: { + ...state.phasesStates, + [phaseId]: updatedPhaseTab + } + } + } + + case COLLAPSE_ALL_PROJECT_PHASES: + return { + ...state, + phasesStates: {}, + } + case LOAD_PROJECT_PENDING: return Object.assign({}, state, { isLoading: true, From 5fe328ff10ede83e4d1dd99d8df55e6a508bf95d Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 29 Aug 2018 13:32:00 +0800 Subject: [PATCH 3/6] issue #2445 - don't show 'undefined' channels names during loading --- .../detail/containers/ProjectPlanContainer.jsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/projects/detail/containers/ProjectPlanContainer.jsx b/src/projects/detail/containers/ProjectPlanContainer.jsx index 6609df8a6..4a8ac9820 100644 --- a/src/projects/detail/containers/ProjectPlanContainer.jsx +++ b/src/projects/detail/containers/ProjectPlanContainer.jsx @@ -77,10 +77,18 @@ class ProjectPlanContainer extends React.Component { const isProjectLive = project.status !== PROJECT_STATUS_COMPLETED && project.status !== PROJECT_STATUS_CANCELLED // get list of phase topic in same order as phases const topics = _.compact( - visiblePhases.map((phase) => ({ - ..._.get(phasesTopics, `[${phase.id}].topic`), - phaseId: phase.id, - })) + visiblePhases.map((phase) => { + const topic = _.get(phasesTopics, `[${phase.id}].topic`) + + if (!topic) { + return null + } + + return ({ + ...topic, + phaseId: phase.id, + }) + }) ) const leftArea = ( From 54ecdbaf9a8338a84a0ccb511bb64b382610de1c Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 29 Aug 2018 13:59:18 +0800 Subject: [PATCH 4/6] issue #2448 - Phase form is not showing updated values --- .../detail/components/PhaseCard/PhaseCard.jsx | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/projects/detail/components/PhaseCard/PhaseCard.jsx b/src/projects/detail/components/PhaseCard/PhaseCard.jsx index 6dc446638..7e0bb1df2 100644 --- a/src/projects/detail/components/PhaseCard/PhaseCard.jsx +++ b/src/projects/detail/components/PhaseCard/PhaseCard.jsx @@ -188,26 +188,28 @@ class PhaseCard extends React.Component { {!this.state.isEditting && (
{this.props.children}
)} - {(
- {!isUpdating && ( - - )} - {canDelete && !isUpdating && ( - { - if (confirm(`Are you sure you want to delete phase '${attr.phase.name}'?`)) { - deleteProjectPhase() - } - }} - /> - )} - {isUpdating && } -
)} + {isManageUser && this.state.isEditting && ( +
+ {!isUpdating && ( + + )} + {canDelete && !isUpdating && ( + { + if (confirm(`Are you sure you want to delete phase '${attr.phase.name}'?`)) { + deleteProjectPhase() + } + }} + /> + )} + {isUpdating && } +
+ )}
):( From a0120e0de394dfeef545547b0d7a5bd8082a70b1 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 29 Aug 2018 15:10:37 +0800 Subject: [PATCH 5/6] issue #2273 - shorter texts for buttons to fit 320px mobile screen --- .../MilestoneTypeCheckpointReview.jsx | 6 +----- .../MilestoneTypeFinalDesigns/MilestoneTypeFinalDesigns.jsx | 6 +----- .../MilestoneTypePhaseSpecification.jsx | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/projects/detail/components/timeline/milestones/MilestoneTypeCheckpointReview/MilestoneTypeCheckpointReview.jsx b/src/projects/detail/components/timeline/milestones/MilestoneTypeCheckpointReview/MilestoneTypeCheckpointReview.jsx index ccbedaca4..9d8d5c896 100644 --- a/src/projects/detail/components/timeline/milestones/MilestoneTypeCheckpointReview/MilestoneTypeCheckpointReview.jsx +++ b/src/projects/detail/components/timeline/milestones/MilestoneTypeCheckpointReview/MilestoneTypeCheckpointReview.jsx @@ -376,11 +376,7 @@ class MilestoneTypeCheckpointReview extends React.Component { onClick={!currentUser.isCustomer ? this.showCompleteReviewConfirmation : this.completeReview} disabled={this.shouldDisableCompleteReviewButton(links, selectedLinks) && !isInReview} > - Complete review ({ - daysLeft >= 0 - ? `${hoursLeft}h remaining` - : `${-hoursLeft}h delay` - }) + Complete review ({hoursLeft}h) )} {!currentUser.isCustomer && extensionRequestButton} diff --git a/src/projects/detail/components/timeline/milestones/MilestoneTypeFinalDesigns/MilestoneTypeFinalDesigns.jsx b/src/projects/detail/components/timeline/milestones/MilestoneTypeFinalDesigns/MilestoneTypeFinalDesigns.jsx index 38db8fec9..8052ede87 100644 --- a/src/projects/detail/components/timeline/milestones/MilestoneTypeFinalDesigns/MilestoneTypeFinalDesigns.jsx +++ b/src/projects/detail/components/timeline/milestones/MilestoneTypeFinalDesigns/MilestoneTypeFinalDesigns.jsx @@ -399,11 +399,7 @@ class MilestoneTypeFinalDesigns extends React.Component { onClick={!currentUser.isCustomer ? this.showCompleteReviewConfirmation : this.showCustomerCompleteReviewConfirmation} disabled={!isInReview} > - Complete review ({ - daysLeft >= 0 - ? `${hoursLeft}h remaining` - : `${-daysLeft}h delay` - }) + Complete review ({hoursLeft}h) )} {!currentUser.isCustomer && extensionRequestButton} diff --git a/src/projects/detail/components/timeline/milestones/MilestoneTypePhaseSpecification/MilestoneTypePhaseSpecification.jsx b/src/projects/detail/components/timeline/milestones/MilestoneTypePhaseSpecification/MilestoneTypePhaseSpecification.jsx index 50b8f291c..126640e81 100644 --- a/src/projects/detail/components/timeline/milestones/MilestoneTypePhaseSpecification/MilestoneTypePhaseSpecification.jsx +++ b/src/projects/detail/components/timeline/milestones/MilestoneTypePhaseSpecification/MilestoneTypePhaseSpecification.jsx @@ -105,7 +105,7 @@ class MilestoneTypePhaseSpecification extends React.Component { onRemoveLink={this.removeUrl} onUpdateLink={this.updatedUrl} fields={[{ name: 'url' }]} - addButtonTitle="Add specification document link" + addButtonTitle="Add specification" formAddTitle="Specification document link" formAddButtonTitle="Add link" formUpdateTitle="Editing a link" From b3c40a06c632bcd4dbb3bca68ff8ec777f0dc14b Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 29 Aug 2018 17:36:26 +0800 Subject: [PATCH 6/6] issue #2273 - Put edit icon to the space between title and progress --- .../detail/components/PhaseCard/PhaseCard.scss | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/projects/detail/components/PhaseCard/PhaseCard.scss b/src/projects/detail/components/PhaseCard/PhaseCard.scss index 913a171b0..f9e7bfa93 100644 --- a/src/projects/detail/components/PhaseCard/PhaseCard.scss +++ b/src/projects/detail/components/PhaseCard/PhaseCard.scss @@ -206,7 +206,11 @@ display: flex; align-items: center; position: relative; - justify-content: space-between; + justify-content: flex-start; + + @media screen and (max-width: $screen-md - 1px) { + justify-content: space-between; + } } .edit-btn { width: 40px; @@ -215,7 +219,11 @@ background-size: 15px; cursor: pointer; transition: 0.25s; - margin: auto auto auto 0; + flex: 0 0 40px; + + @media screen and (max-width: $screen-md - 1px) { + margin-right: -30px; + } } .toggle-arrow { position: absolute;