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
1 change: 1 addition & 0 deletions src/components/AssetsLibrary/LinksGridView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const LinksGridView = ({
renderLink={ renderLink }
goBack={goBack}
formatModifyDate={formatModifyDate}
isLinkSubFolder
/>)}
{(!subFolderContent) && (
<div styleName={cn({'assets-gridview-container-active': (linkToEdit >= 0 || linkToDelete >= 0)}, '')}>
Expand Down
4 changes: 2 additions & 2 deletions src/components/AssetsLibrary/SubFolder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class SubFolder extends React.Component {
}

render() {
const { link, renderLink, goBack, formatModifyDate } = this.props
const { link, renderLink, goBack, formatModifyDate, isLinkSubFolder } = this.props
const { linkToDelete } = this.state
return (
<div styleName={cn({'assets-gridview-container-active': (linkToDelete >= 0)}, '')}>
Expand Down Expand Up @@ -88,7 +88,7 @@ class SubFolder extends React.Component {
}
let iconPath
try {
if (this.isURLValid(childLink.title)) {
if (isLinkSubFolder) {
//Link Icon here
iconPath = require('../../assets/icons/link-12.svg')
} else {
Expand Down
18 changes: 16 additions & 2 deletions src/components/TopicCard/TopicCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,24 @@ import cn from 'classnames'

import UserTooltip from '../User/UserTooltip'
import NotificationBellAvatar from './NotificationBellAvatar'
import {
CODER_BOT_USER_FNAME,
CODER_BOT_USER_LNAME,
} from '../../config/constants'
import { isSystemUser } from '../../helpers/tcHelpers'

import FileIcon from '../../assets/icons/file-12.svg'
import LinkIcon from '../../assets/icons/link-12.svg'
import InvisibleIcon from '../../assets/icons/invisible-12.svg'

import styles from './TopicCard.scss'

const SYSTEM_USER = {
firstName: CODER_BOT_USER_FNAME,
lastName: CODER_BOT_USER_LNAME,
photoURL: require('../../assets/images/avatar-coder.svg')
}

/**
* The topic card that shows the topic title, number of links, files, etc
*/
Expand All @@ -32,13 +44,15 @@ const TopicCard = ({
const pluralize = (name, num) => `${name}${num > 1 ? 's' : ''}`

const lastMessageUserId = last(posts).userId
const lastMessageAuthor = get(allMembers, lastMessageUserId)
const lastMessageAuthor = isSystemUser(lastMessageUserId) ? SYSTEM_USER : get(allMembers, lastMessageUserId)
const lastMessageDate = formatDate(lastActivityAt)
const numNewMessages = get(notifications, 'length')
const newMessagesFromDate = formatDate(get(notifications, '0.date'))
const numFiles = sumBy(posts, p => get(p, 'attachments.length', 0))
const numLinks = sumBy(posts, p => get(p, 'links.length', 0))

const authorUser = isSystemUser(get(author, 'userId')) ? SYSTEM_USER : author

return (
<Link to={`/projects/${projectId}/messages/${topicId}`}>
<div className={styles.container}>
Expand All @@ -47,7 +61,7 @@ const TopicCard = ({
{numNewMessages && <NotificationBellAvatar />}
{!numNewMessages && author && (
<UserTooltip
usr={author}
usr={authorUser}
previewAvatar
size={40}
id={'userTooltip-inTopicCard-' + topicId}
Expand Down
12 changes: 1 addition & 11 deletions src/components/UserSummary/UserSummary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ import Avatar from 'appirio-tech-react-components/components/Avatar/Avatar'
import moment from 'moment'

import './UserSummary.scss'
import _ from 'lodash'
import {
ROLE_CONNECT_COPILOT,
ROLE_CONNECT_MANAGER,
ROLE_ADMINISTRATOR,
ROLE_CONNECT_ADMIN } from '../../../config/constants'


const UserSummary = ({user}) => {
// TODO: Replace hardcoded values with real data
Expand All @@ -19,9 +12,6 @@ const UserSummary = ({user}) => {
drafts: 7,
delivered: 5
} */
const powerUserRoles = [ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, ROLE_ADMINISTRATOR, ROLE_CONNECT_ADMIN]
const isCustomer = _.intersection(user.roles, powerUserRoles).length === 0
const role = isCustomer ? 'Customer' : 'Member'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maxceem just a note, it was showing me as Customer even when I have power user roles.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vikasrohit I guess it was an issue with logic. If I'm not mistaken we didn't have direct requirements from the product team on what text should be shown here. So I've simplified logic to always show User since for now.

const userName = (user.firstName && user.lastName) && `${user.firstName} ${user.lastName}`
const memberSince = moment(user.createdAt).format('MMM YYYY')
return (
Expand All @@ -38,7 +28,7 @@ const UserSummary = ({user}) => {
@{user.handle}
</div>
<div styleName="member-since">
{role} since {memberSince}
User since {memberSince}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/projectHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ export function getProjectNavLinks(project, projectId) {
// choose set of menu links based on the project version
const navLinks = project.version === 'v3' ? [
{ label: 'Dashboard', to: `/projects/${projectId}`, Icon: DashboardIcon, iconClassName: 'stroke' },
{ label: 'Messages', to: `/projects/${projectId}/messages`, Icon: MessagesIcon, iconClassName: 'stroke' },
{ label: 'Messages', to: `/projects/${projectId}/messages`, Icon: MessagesIcon, iconClassName: 'stroke', exact: false },
{ label: 'Scope', to: `/projects/${projectId}/scope`, Icon: ScopeIcon, iconClassName: 'fill' },
// { label: 'Reports', to: '#', Icon: ReportsIcon },
{ label: 'Assets Library', to: `/projects/${projectId}/assets`, Icon: AssetsLibraryIcon, iconClassName: 'stroke' },
Expand Down
17 changes: 8 additions & 9 deletions src/projects/detail/Messages.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
-ms-flex: $number;
flex: $number;
}

// FIXME
.messages-container {
@include flexBox;
max-width: 1110px;
margin: 20px auto;
margin: 20px;
height: calc(100% - 80px);// 20px is for bottom margin, 60px for footer

.left-area {
@include flexWidth(1);
max-width: 360px;
Expand All @@ -31,28 +31,27 @@
@include flexWidth(2);
margin-left: 4 * $base-unit;
overflow-y: auto;

.messaging-empty-state {
margin-bottom: 4 * $base-unit;
}

.new-post-composer {
margin-bottom: 4 * $base-unit;
background-color: $tc-white;

.modal-row:hover {
background-color: $tc-white;
}

.btn-close {
display: none;
}
}

.feed-action-card + .feed-action-card {
margin-top: 4 * $base-unit;
}
}
}
}

117 changes: 87 additions & 30 deletions src/projects/detail/containers/MessagesContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import React from 'react'
import { Prompt, withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import update from 'react-addons-update'
import MediaQuery from 'react-responsive'
import MessageList from '../../../components/MessageList/MessageList'
import MessagingEmptyState from '../../../components/MessageList/MessagingEmptyState'
import MessageDetails from '../../../components/MessageDetails/MessageDetails'
import NewPost from '../../../components/Feed/NewPost'
import { loadProjectMessages, createProjectTopic, saveProjectTopic, deleteProjectTopic, loadFeedComments, addFeedComment, saveFeedComment, deleteFeedComment, getFeedComment } from '../../actions/projectTopics'
import spinnerWhileLoading from '../../../components/LoadingSpinner'
import FullHeightContainer from 'appirio-tech-react-components/components/FullHeightContainer/FullHeightContainer'
import FooterV2 from '../../../components/FooterV2/FooterV2'
import TwoColsLayout from '../../../components/TwoColsLayout'
import Sticky from '../../../components/Sticky'
import ProjectInfoContainer from './ProjectInfoContainer'

import {
THREAD_MESSAGES_PAGE_SIZE,
Expand All @@ -19,7 +21,8 @@ import {
CODER_BOT_USERID,
CODER_BOT_USER_FNAME,
CODER_BOT_USER_LNAME,
TC_SYSTEM_USERID
TC_SYSTEM_USERID,
SCREEN_BREAKPOINT_MD,
} from '../../../config/constants'

const SYSTEM_USER = {
Expand Down Expand Up @@ -417,9 +420,58 @@ class MessagesView extends React.Component {
})
}

/**
* Returns the sidebar content
*/
getSidebarContent() {
const {
location,
currentMemberRole,
project,
phases,
isSuperUser,
isManageUser,
productsTimelines,
phasesTopics,
isProcessing
} = this.props

const leftArea = (
<ProjectInfoContainer
location={location}
currentMemberRole={currentMemberRole}
project={project}
phases={phases}
isSuperUser={isSuperUser}
isManageUser={isManageUser}
productsTimelines={productsTimelines}
phasesTopics={phasesTopics}
isProjectProcessing={isProcessing}

// we never load feeds from the old Discussions tab,
// otherwise it would cause conflicts with the logic to load feeds on in this Container
feeds={[]}
isFeedsLoading
/>
)

return (
<MediaQuery minWidth={SCREEN_BREAKPOINT_MD}>
{matches => {
if (matches) {
return <Sticky top={60}>{leftArea}</Sticky>
} else {
return leftArea
}
}}
</MediaQuery>
)
}

render() {
const {threads, isCreateNewMessage, showEmptyState, scrollPosition} = this.state
const { currentUser, isCreatingFeed, currentMemberRole, error } = this.props
const leftArea = this.getSidebarContent()
const activeThread = threads.filter((item) => item.isActive)[0]
const onLeaveMessage = this.onLeave() || ''
const renderRightPanel = () => {
Expand Down Expand Up @@ -460,34 +512,39 @@ class MessagesView extends React.Component {
}

return (
<FullHeightContainer offset={80}>
<Prompt
when={!!onLeaveMessage}
message={onLeaveMessage}
/>
<div className="messages-container">
<div className="left-area">
<MessageList
onAdd={this.onNewThreadClick}
threads={threads}
onSelect={this.onThreadSelect}
showAddButton={!!currentMemberRole}
showEmptyState={showEmptyState && !threads.length}
scrollPosition={scrollPosition}
/>
<FooterV2 />
</div>
<div className="right-area">
{ (showEmptyState && !threads.length) &&
<MessagingEmptyState
currentUser={currentUser}
onClose={() => this.setState({showEmptyState: false})}
/>
}
{ renderRightPanel() }
<TwoColsLayout noPadding>
<TwoColsLayout.Sidebar>
{leftArea}
</TwoColsLayout.Sidebar>

<TwoColsLayout.Content>
<Prompt
when={!!onLeaveMessage}
message={onLeaveMessage}
/>
<div className="messages-container">
<div className="left-area">
<MessageList
onAdd={this.onNewThreadClick}
threads={threads}
onSelect={this.onThreadSelect}
showAddButton={!!currentMemberRole}
showEmptyState={showEmptyState && !threads.length}
scrollPosition={scrollPosition}
/>
</div>
<div className="right-area">
{ (showEmptyState && !threads.length) &&
<MessagingEmptyState
currentUser={currentUser}
onClose={() => this.setState({showEmptyState: false})}
/>
}
{ renderRightPanel() }
</div>
</div>
</div>
</FullHeightContainer>
</TwoColsLayout.Content>
</TwoColsLayout>
)
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/projects/detail/containers/MessagesTabContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ class MessagesTabContainer extends React.Component {
this.props.createProjectTopic(project.id, newFeed)
}

componentWillReceiveProps(nextProps) {
// reset title and content in the state after successful post creation
// so that we treat the post editor not changed, thus when we leave the page we don't get confirmation alert
if (this.props.isCreatingFeed && !nextProps.isCreatingFeed && !nextProps.error) {
this.setState({
newPost: {
title: '',
content: ''
}
})
}
}

isChanged() {
const { newPost } = this.state
const notEmpty = str => str && !!trim(str).length
Expand Down