Skip to content

Commit 396cd01

Browse files
author
Vikas Agarwal
committed
Github #166, Messaging: unposted content alert
-- Implemented the required behaviour with Discussions page. Took liberty to implement the same behaviour when user has unposted content and tries to change the thread from the left panel of thread list.
1 parent 9fc4a7a commit 396cd01

File tree

3 files changed

+84
-12
lines changed

3 files changed

+84
-12
lines changed

src/components/Feed/NewPost.jsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ class NewPost extends React.Component {
4141
constructor(props) {
4242
super(props)
4343
this.state = {editorState: EditorState.createEmpty(), expandedEditor: false, canSubmit: false}
44+
this.onTitleChange = this.onTitleChange.bind(this)
4445
this.onEditorChange = this.onEditorChange.bind(this)
4546
this.handleKeyCommand = this.handleKeyCommand.bind(this)
4647
this.toggleBlockType = this.toggleBlockType.bind(this)
4748
this.toggleInlineStyle = this.toggleInlineStyle.bind(this)
4849
this.onClickOutside = this.onClickOutside.bind(this)
49-
this.onNewPostChange = this.onNewPostChange.bind(this)
50+
this.validateSubmitState = this.validateSubmitState.bind(this)
5051
}
5152

5253
componentDidMount() {
@@ -59,11 +60,11 @@ class NewPost extends React.Component {
5960
}
6061

6162
componentWillReceiveProps(nextProps) {
62-
if (!(nextProps.isCreating || nextProps.hasError && !nextProps.isCreating)) {
63+
if (nextProps.isCreating !== this.props.isCreating && !nextProps.isCreating && !nextProps.hasError) {
6364
this.setState({editorState: EditorState.createEmpty()})
6465
this.refs.title.value = ''
6566
}
66-
this.onNewPostChange()
67+
this.validateSubmitState()
6768
}
6869

6970
onClickOutside(evt) {
@@ -125,15 +126,27 @@ class NewPost extends React.Component {
125126

126127
onEditorChange(editorState) {
127128
this.setState({editorState})
128-
this.onNewPostChange()
129+
this.validateSubmitState()
130+
if (this.props.onNewPostChange) {
131+
this.props.onNewPostChange(this.refs.title.value, stateToMarkdown(editorState.getCurrentContent()))
132+
}
129133
}
130134

131-
onNewPostChange() {
135+
validateSubmitState() {
136+
const { editorState } = this.state
132137
this.setState({
133-
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && this.state.editorState.getCurrentContent().hasText()
138+
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && editorState.getCurrentContent().hasText()
134139
})
135140
}
136141

142+
onTitleChange() {
143+
const { editorState } = this.state
144+
this.validateSubmitState()
145+
if (this.props.onNewPostChange) {
146+
this.props.onNewPostChange(this.refs.title.value, stateToMarkdown(editorState.getCurrentContent()))
147+
}
148+
}
149+
137150
render() {
138151
const {currentUser, titlePlaceholder, isCreating} = this.props
139152
const {editorState, canSubmit} = this.state
@@ -191,7 +204,7 @@ class NewPost extends React.Component {
191204
ref="title"
192205
className="new-post-title"
193206
type="text"
194-
onChange={this.onNewPostChange}
207+
onChange={this.onTitleChange}
195208
placeholder={ titlePlaceholder || 'Title of the post'}
196209
/>
197210
<div className="draftjs-editor tc-textarea">

src/projects/detail/Messages.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import MessagesContainer from './containers/MessagesContainer'
44

55
require('./Messages.scss')
66

7-
const Messages = ({ location, project, currentMemberRole }) => (
8-
<MessagesContainer location={ location } project={ project } currentMemberRole={ currentMemberRole } />
7+
const Messages = ({ location, project, currentMemberRole, route }) => (
8+
<MessagesContainer
9+
location={ location }
10+
project={ project }
11+
currentMemberRole={ currentMemberRole }
12+
route={ route }
13+
/>
914
)
1015
export default Messages

src/projects/detail/containers/MessagesContainer.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import _ from 'lodash'
22
import React from 'react'
3+
import { withRouter } from 'react-router'
34
import { connect } from 'react-redux'
45
import update from 'react-addons-update'
56
import MessageList from '../../../components/MessageList/MessageList'
@@ -30,12 +31,27 @@ class MessagesView extends React.Component {
3031

3132
constructor(props) {
3233
super(props)
33-
this.state = { threads : [], activeThreadId : null, showEmptyState : true, showAll: []}
34+
this.state = {
35+
threads : [],
36+
activeThreadId : null,
37+
showEmptyState : true,
38+
showAll: [],
39+
newPost: {}
40+
}
3441
this.onThreadSelect = this.onThreadSelect.bind(this)
3542
this.onShowAllComments = this.onShowAllComments.bind(this)
3643
this.onAddNewMessage = this.onAddNewMessage.bind(this)
3744
this.onNewMessageChange = this.onNewMessageChange.bind(this)
3845
this.onNewThread = this.onNewThread.bind(this)
46+
this.onLeave = this.onLeave.bind(this)
47+
this.isChanged = this.isChanged.bind(this)
48+
this.onNewPostChange = this.onNewPostChange.bind(this)
49+
this.changeThread = this.changeThread.bind(this)
50+
}
51+
52+
componentDidMount() {
53+
this.props.router.setRouteLeaveHook(this.props.route, this.onLeave)
54+
window.addEventListener('beforeunload', this.onLeave)
3955
}
4056

4157
componentWillMount() {
@@ -46,6 +62,24 @@ class MessagesView extends React.Component {
4662
this.init(nextProps)
4763
}
4864

65+
componentWillUnmount() {
66+
window.removeEventListener('beforeunload', this.onLeave)
67+
}
68+
69+
// Notify user if they navigate away while the form is modified.
70+
onLeave(e) {
71+
if (this.isChanged()) {
72+
return e.returnValue = 'You have uposted content. Are you sure you want to leave?'
73+
}
74+
}
75+
76+
isChanged() {
77+
const { newPost } = this.state
78+
const hasMessage = !_.isUndefined(_.find(this.state.threads, (thread) => thread.newMessage && thread.newMessage.length))
79+
const hasThread = (newPost.title && !!newPost.title.trim().length) || ( newPost.content && !!newPost.content.trim().length)
80+
return hasThread || hasMessage
81+
}
82+
4983
mapFeed(feed, isActive, showAll = false) {
5084
const { allMembers } = this.props
5185
const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error'])
@@ -137,15 +171,28 @@ class MessagesView extends React.Component {
137171
}
138172

139173
onThreadSelect(thread) {
174+
const unsavedContentMsg = this.onLeave({})
175+
if (unsavedContentMsg) {
176+
const changeConfirmed = confirm(unsavedContentMsg)
177+
if (changeConfirmed) {
178+
this.changeThread(thread)
179+
}
180+
} else {
181+
this.changeThread(thread)
182+
}
183+
}
184+
185+
changeThread(thread) {
140186
this.setState({
141187
isCreateNewMessage: false,
188+
newPost: {},
142189
activeThreadId: thread.id,
143190
threads: this.state.threads.map((item) => {
144191
if (item.isActive) {
145192
if (item.id === thread.id) {
146193
return item
147194
}
148-
return {...item, isActive: false, messages: item.messages.map((msg) => ({...msg, unread: false}))}
195+
return {...item, isActive: false, newMessage: '', messages: item.messages.map((msg) => ({...msg, unread: false}))}
149196
}
150197
if (item.id === thread.id) {
151198
return {...item, isActive: true, unreadCount: 0}
@@ -155,6 +202,12 @@ class MessagesView extends React.Component {
155202
})
156203
}
157204

205+
onNewPostChange(title, content) {
206+
this.setState({
207+
newPost: {title, content}
208+
})
209+
}
210+
158211
onNewMessageChange(content) {
159212
this.setState({
160213
threads: this.state.threads.map((item) => {
@@ -200,6 +253,7 @@ class MessagesView extends React.Component {
200253
<NewPost
201254
currentUser={currentUser}
202255
onPost={this.onNewThread}
256+
onNewPostChange={ this.onNewPostChange }
203257
isCreating={isCreatingFeed}
204258
hasError={error}
205259
heading="New Discussion Post"
@@ -251,7 +305,7 @@ class MessagesView extends React.Component {
251305
}
252306

253307
const enhance = spinnerWhileLoading(props => !props.isLoading)
254-
const EnhancedMessagesView = enhance(MessagesView)
308+
const EnhancedMessagesView = withRouter(enhance(MessagesView))
255309

256310
class MessagesContainer extends React.Component {
257311
constructor(props) {

0 commit comments

Comments
 (0)