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
29 changes: 22 additions & 7 deletions src/components/Feed/NewPost.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ class NewPost extends React.Component {
constructor(props) {
super(props)
this.state = {editorState: EditorState.createEmpty(), expandedEditor: false, canSubmit: false}
this.onTitleChange = this.onTitleChange.bind(this)
this.onEditorChange = this.onEditorChange.bind(this)
this.handleKeyCommand = this.handleKeyCommand.bind(this)
this.toggleBlockType = this.toggleBlockType.bind(this)
this.toggleInlineStyle = this.toggleInlineStyle.bind(this)
this.onClickOutside = this.onClickOutside.bind(this)
this.onNewPostChange = this.onNewPostChange.bind(this)
this.validateSubmitState = this.validateSubmitState.bind(this)
}

componentDidMount() {
Expand All @@ -59,11 +60,11 @@ class NewPost extends React.Component {
}

componentWillReceiveProps(nextProps) {
if (!(nextProps.isCreating || nextProps.hasError && !nextProps.isCreating)) {
if (nextProps.isCreating !== this.props.isCreating && !nextProps.isCreating && !nextProps.hasError) {
this.setState({editorState: EditorState.createEmpty()})
this.refs.title.value = ''
}
this.onNewPostChange()
this.validateSubmitState()
}

onClickOutside(evt) {
Expand Down Expand Up @@ -125,15 +126,29 @@ class NewPost extends React.Component {

onEditorChange(editorState) {
this.setState({editorState})
this.onNewPostChange()
this.validateSubmitState()
if (this.props.onNewPostChange) {
// NOTE: uses getPlainText method to avoid newline character for empty content
this.props.onNewPostChange(this.refs.title.value, editorState.getCurrentContent().getPlainText())
}
}

onNewPostChange() {
validateSubmitState() {
const { editorState } = this.state
this.setState({
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && this.state.editorState.getCurrentContent().hasText()
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && editorState.getCurrentContent().hasText()
})
}

onTitleChange() {
const { editorState } = this.state
this.validateSubmitState()
if (this.props.onNewPostChange) {
// NOTE: uses getPlainText method to avoid newline character for empty content
this.props.onNewPostChange(this.refs.title.value, editorState.getCurrentContent().getPlainText())
}
}

render() {
const {currentUser, titlePlaceholder, isCreating} = this.props
const {editorState, canSubmit} = this.state
Expand Down Expand Up @@ -191,7 +206,7 @@ class NewPost extends React.Component {
ref="title"
className="new-post-title"
type="text"
onChange={this.onNewPostChange}
onChange={this.onTitleChange}
placeholder={ titlePlaceholder || 'Title of the post'}
/>
<div className="draftjs-editor tc-textarea">
Expand Down
4 changes: 2 additions & 2 deletions src/projects/detail/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Sticky from 'react-stickynode'

require('./Dashboard.scss')

const Dashboard = ({project, currentMemberRole}) => (
const Dashboard = ({project, currentMemberRole, route}) => (
<div>
<div className="dashboard-container">
<div className="left-area">
Expand All @@ -16,7 +16,7 @@ const Dashboard = ({project, currentMemberRole}) => (
</Sticky>
</div>
<div className="right-area">
<FeedContainer currentMemberRole={currentMemberRole} project={project} />
<FeedContainer currentMemberRole={currentMemberRole} project={project} route={route} />
</div>
</div>
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/projects/detail/Messages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import MessagesContainer from './containers/MessagesContainer'

require('./Messages.scss')

const Messages = ({ location, project, currentMemberRole }) => (
<MessagesContainer location={ location } project={ project } currentMemberRole={ currentMemberRole } />
const Messages = ({ location, project, currentMemberRole, route }) => (
<MessagesContainer
location={ location }
project={ project }
currentMemberRole={ currentMemberRole }
route={ route }
/>
)
export default Messages
42 changes: 40 additions & 2 deletions src/projects/detail/containers/FeedContainer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react'
import { withRouter } from 'react-router'
import _ from 'lodash'
import {
THREAD_MESSAGES_PAGE_SIZE,
Expand Down Expand Up @@ -36,7 +37,16 @@ class FeedView extends React.Component {
this.onNewCommentChange = this.onNewCommentChange.bind(this)
this.onShowAllComments = this.onShowAllComments.bind(this)
this.onAddNewComment = this.onAddNewComment.bind(this)
this.state = { feeds : [], showAll: [] }
this.onLeave = this.onLeave.bind(this)
this.isChanged = this.isChanged.bind(this)
this.onNewPostChange = this.onNewPostChange.bind(this)
this.state = { feeds : [], showAll: [], newPost: {} }
}

componentDidMount() {
const routeLeaveHook = this.props.router.setRouteLeaveHook(this.props.route, this.onLeave)
window.addEventListener('beforeunload', this.onLeave)
this.setState({ routeLeaveHook })
}

componentWillMount() {
Expand All @@ -47,6 +57,27 @@ class FeedView extends React.Component {
this.init(nextProps)
}

componentWillUnmount() {
if (this.state.routeLeaveHook) {
this.state.routeLeaveHook()
}
window.removeEventListener('beforeunload', this.onLeave)
}

// Notify user if they navigate away while the form is modified.
onLeave(e) {
if (this.isChanged()) {
return e.returnValue = 'You have uposted content. Are you sure you want to leave?'
}
}

isChanged() {
const { newPost } = this.state
const hasComment = !_.isUndefined(_.find(this.state.feeds, (feed) => feed.newComment && feed.newComment.length))
const hasThread = (newPost.title && !!newPost.title.trim().length) || ( newPost.content && !!newPost.content.trim().length)
return hasThread || hasComment
}

mapFeed(feed, showAll = false) {
const { allMembers } = this.props
const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error'])
Expand Down Expand Up @@ -99,6 +130,12 @@ class FeedView extends React.Component {
})
}

onNewPostChange(title, content) {
this.setState({
newPost: {title, content}
})
}

onNewPost({title, content}) {
const { project } = this.props
const newFeed = {
Expand Down Expand Up @@ -194,6 +231,7 @@ class FeedView extends React.Component {
isCreating={ isCreatingFeed }
hasError={ error }
heading="NEW STATUS POST"
onNewPostChange={this.onNewPostChange}
titlePlaceholder="Share the latest project updates with the team"
/>
}
Expand All @@ -203,7 +241,7 @@ class FeedView extends React.Component {
}
}
const enhance = spinnerWhileLoading(props => !props.isLoading)
const EnhancedFeedView = enhance(FeedView)
const EnhancedFeedView = withRouter(enhance(FeedView))


class FeedContainer extends React.Component {
Expand Down
92 changes: 88 additions & 4 deletions src/projects/detail/containers/MessagesContainer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import _ from 'lodash'
import React from 'react'
import { withRouter } from 'react-router'
import { connect } from 'react-redux'
import update from 'react-addons-update'
import MessageList from '../../../components/MessageList/MessageList'
Expand Down Expand Up @@ -30,12 +31,30 @@ class MessagesView extends React.Component {

constructor(props) {
super(props)
this.state = { threads : [], activeThreadId : null, showEmptyState : true, showAll: []}
this.state = {
threads : [],
activeThreadId : null,
showEmptyState : true,
showAll: [],
newPost: {}
}
this.onThreadSelect = this.onThreadSelect.bind(this)
this.onShowAllComments = this.onShowAllComments.bind(this)
this.onAddNewMessage = this.onAddNewMessage.bind(this)
this.onNewMessageChange = this.onNewMessageChange.bind(this)
this.onNewThread = this.onNewThread.bind(this)
this.onLeave = this.onLeave.bind(this)
this.isChanged = this.isChanged.bind(this)
this.onNewPostChange = this.onNewPostChange.bind(this)
this.changeThread = this.changeThread.bind(this)
this.onNewThreadClick = this.onNewThreadClick.bind(this)
this.showNewThreadForm = this.showNewThreadForm.bind(this)
}

componentDidMount() {
const routeLeaveHook = this.props.router.setRouteLeaveHook(this.props.route, this.onLeave)
window.addEventListener('beforeunload', this.onLeave)
this.setState({ routeLeaveHook })
}

componentWillMount() {
Expand All @@ -46,6 +65,27 @@ class MessagesView extends React.Component {
this.init(nextProps)
}

componentWillUnmount() {
window.removeEventListener('beforeunload', this.onLeave)
if (this.state.routeLeaveHook) {
this.state.routeLeaveHook()
}
}

// Notify user if they navigate away while the form is modified.
onLeave(e) {
if (this.isChanged()) {
return e.returnValue = 'You have uposted content. Are you sure you want to leave?'
}
}

isChanged() {
const { newPost } = this.state
const hasMessage = !_.isUndefined(_.find(this.state.threads, (thread) => thread.newMessage && thread.newMessage.length))
const hasThread = (newPost.title && !!newPost.title.trim().length) || ( newPost.content && !!newPost.content.trim().length)
return hasThread || hasMessage
}

mapFeed(feed, isActive, showAll = false) {
const { allMembers } = this.props
const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error'])
Expand Down Expand Up @@ -137,15 +177,28 @@ class MessagesView extends React.Component {
}

onThreadSelect(thread) {
const unsavedContentMsg = this.onLeave({})
if (unsavedContentMsg) {
const changeConfirmed = confirm(unsavedContentMsg)
if (changeConfirmed) {
this.changeThread(thread)
}
} else {
this.changeThread(thread)
}
}

changeThread(thread) {
this.setState({
isCreateNewMessage: false,
newPost: {},
activeThreadId: thread.id,
threads: this.state.threads.map((item) => {
if (item.isActive) {
if (item.id === thread.id) {
return item
}
return {...item, isActive: false, messages: item.messages.map((msg) => ({...msg, unread: false}))}
return {...item, isActive: false, newMessage: '', messages: item.messages.map((msg) => ({...msg, unread: false}))}
}
if (item.id === thread.id) {
return {...item, isActive: true, unreadCount: 0}
Expand All @@ -155,6 +208,36 @@ class MessagesView extends React.Component {
})
}

onNewPostChange(title, content) {
this.setState({
newPost: {title, content}
})
}

onNewThreadClick() {
const unsavedContentMsg = this.onLeave({})
if (unsavedContentMsg) {
const changeConfirmed = confirm(unsavedContentMsg)
if (changeConfirmed) {
this.showNewThreadForm()
}
} else {
this.showNewThreadForm()
}
}

showNewThreadForm() {
this.setState({
isCreateNewMessage: true,
threads: this.state.threads.map((item) => {
if (item.isActive) {
return {...item, newMessage: ''}
}
return item
})
})
}

onNewMessageChange(content) {
this.setState({
threads: this.state.threads.map((item) => {
Expand Down Expand Up @@ -200,6 +283,7 @@ class MessagesView extends React.Component {
<NewPost
currentUser={currentUser}
onPost={this.onNewThread}
onNewPostChange={ this.onNewPostChange }
isCreating={isCreatingFeed}
hasError={error}
heading="New Discussion Post"
Expand Down Expand Up @@ -227,7 +311,7 @@ class MessagesView extends React.Component {
<div className="messages-container">
<div className="left-area">
<MessageList
onAdd={() => this.setState({isCreateNewMessage: true})}
onAdd={ this.onNewThreadClick }
threads={threads}
onSelect={this.onThreadSelect}
showAddButton={ !!currentMemberRole }
Expand All @@ -251,7 +335,7 @@ class MessagesView extends React.Component {
}

const enhance = spinnerWhileLoading(props => !props.isLoading)
const EnhancedMessagesView = enhance(MessagesView)
const EnhancedMessagesView = withRouter(enhance(MessagesView))

class MessagesContainer extends React.Component {
constructor(props) {
Expand Down