Skip to content

Commit e6ec54f

Browse files
author
vikasrohit
authored
Merge pull request #592 from appirio-tech/dev
Promoting to prod
2 parents f55983a + 61b0518 commit e6ec54f

18 files changed

+240
-42
lines changed

src/components/Feed/Feed.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ const Feed = (props) => {
3636
<div className="card-body draftjs-post" dangerouslySetInnerHTML={{__html: html}} />
3737
</div>
3838
</Panel.Body>
39-
{allowComments &&
4039
<FeedComments
40+
allowComments={ allowComments }
4141
totalComments={totalComments}
4242
hasMoreComments={hasMoreComments}
4343
onLoadMoreComments={onLoadMoreComments}
@@ -49,7 +49,7 @@ const Feed = (props) => {
4949
avatarUrl={currentUser.photoURL}
5050
comments={comments}
5151
isAddingComment={ isAddingComment }
52-
/>}
52+
/>
5353
{children}
5454
</ActionCard>
5555
)

src/components/Feed/FeedComments.jsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class FeedComments extends React.Component {
2525
render() {
2626
const {
2727
comments, currentUser, totalComments, onLoadMoreComments, isLoadingComments, hasMoreComments, onAdd,
28-
onChange, content, avatarUrl, isAddingComment
28+
onChange, content, avatarUrl, isAddingComment, allowComments
2929
} = this.props
3030
let authorName = currentUser.firstName
3131
if (authorName && currentUser.lastName) {
@@ -77,6 +77,7 @@ class FeedComments extends React.Component {
7777
<div dangerouslySetInnerHTML={{__html: item.content}} />
7878
</Comment>
7979
)}
80+
{allowComments &&
8081
<AddComment
8182
placeholder="Create a new comment..."
8283
onAdd={onAdd}
@@ -85,7 +86,7 @@ class FeedComments extends React.Component {
8586
avatarUrl={avatarUrl}
8687
authorName={ authorName }
8788
isAdding={ isAddingComment }
88-
/>
89+
/>}
8990
</div>
9091
)
9192
}

src/components/Feed/NewPost.jsx

+22-7
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,29 @@ 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+
// NOTE: uses getPlainText method to avoid newline character for empty content
132+
this.props.onNewPostChange(this.refs.title.value, editorState.getCurrentContent().getPlainText())
133+
}
129134
}
130135

131-
onNewPostChange() {
136+
validateSubmitState() {
137+
const { editorState } = this.state
132138
this.setState({
133-
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && this.state.editorState.getCurrentContent().hasText()
139+
canSubmit: this.refs.title && !!this.refs.title.value.trim().length && editorState.getCurrentContent().hasText()
134140
})
135141
}
136142

143+
onTitleChange() {
144+
const { editorState } = this.state
145+
this.validateSubmitState()
146+
if (this.props.onNewPostChange) {
147+
// NOTE: uses getPlainText method to avoid newline character for empty content
148+
this.props.onNewPostChange(this.refs.title.value, editorState.getCurrentContent().getPlainText())
149+
}
150+
}
151+
137152
render() {
138153
const {currentUser, titlePlaceholder, isCreating} = this.props
139154
const {editorState, canSubmit} = this.state
@@ -191,7 +206,7 @@ class NewPost extends React.Component {
191206
ref="title"
192207
className="new-post-title"
193208
type="text"
194-
onChange={this.onNewPostChange}
209+
onChange={this.onTitleChange}
195210
placeholder={ titlePlaceholder || 'Title of the post'}
196211
/>
197212
<div className="draftjs-editor tc-textarea">

src/components/Footer/Footer.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Footer = () => {
99
const otherNavigationItems = [
1010
{img: '', text: 'About', link: 'https://www.topcoder.com/about-topcoder/', target: '_blank'},
1111
{img: '', text: 'Contact', link: 'https://www.topcoder.com/about-topcoder/contact/', target: '_blank'},
12-
{img: '', text: 'Help', link: 'https://help.topcoder.com/hc/en-us', target: '_blank'},
12+
{img: '', text: 'Help', link: 'https://help.topcoder.com/hc/en-us/articles/225540188-Topcoder-Connect-FAQs', target: '_blank'},
1313
{img: '', text: 'Privacy', link: 'https://www.topcoder.com/community/how-it-works/privacy-policy/', target: '_blank'},
1414
{img: '', text: 'Terms', link: 'https://connect.topcoder.com/terms'}
1515
]

src/components/FooterV2/FooterV2.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const FooterV2 = () => (
66
<ul className="footer-links">
77
<li><a href="https://www.topcoder.com/about-topcoder/" target="_blank">About</a></li>
88
<li><a href="https://www.topcoder.com/about-topcoder/contact/" target="_blank">Contact</a></li>
9-
<li><a href="https://help.topcoder.com/hc/en-us" target="_blank">Help</a></li>
9+
<li><a href="https://help.topcoder.com/hc/en-us/articles/225540188-Topcoder-Connect-FAQs" target="_blank">Help</a></li>
1010
<li><a href="https://www.topcoder.com/community/how-it-works/privacy-policy/" target="_blank">Privacy</a></li>
1111
<li><a href="https://connect.topcoder.com/terms">Terms</a></li>
1212
</ul>

src/components/MessageList/MessageList.jsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ class MessageList extends Component {
5757
componentDidMount() {
5858
const { scrollPosition } = this.props
5959
const panelMessages = this.refs.panelMessages
60-
// 145 = 60 for topbar + 45 for panel title + 20px for margin between topbar and left panel + 10px padding
61-
panelMessages.style.height = (window.innerHeight - 145) + 'px'
60+
// 215 = 60 for topbar + 45 for panel title + 20px for margin between topbar and left panel + 10px padding
61+
// + 60px footer + 10px margin bw footer and left panel
62+
panelMessages.style.height = (window.innerHeight - 215) + 'px'
6263
if (scrollPosition) {
6364
// We use requestAnimationFrame because this function may be executed before
6465
// the DOM elements are actually drawn.

src/components/TeamManagement/TeamManagement.scss

+4
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ $tc-body-extra-small : 12px;
214214
}
215215
}
216216

217+
input::-ms-clear {
218+
display: none;
219+
}
220+
217221
.modal-inline-form{
218222
display: flex;
219223
margin-bottom: $base-unit*2;

src/components/TopBar/TopBar.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import cn from 'classnames'
66
import _ from 'lodash'
77
import { UserDropdown, Icons } from 'appirio-tech-react-components'
88

9-
const { ConnectLogoBeta } = Icons
9+
const { ConnectLogo } = Icons
1010
import { SearchBar } from 'appirio-tech-react-components'
1111
import Filters from './Filters'
1212
import ProjectToolBar from './ProjectToolBar'
@@ -67,7 +67,7 @@ class TopBar extends Component {
6767
]
6868
const logo = (
6969
<div className="logo-wrapper">
70-
<Link className="logo" to={logoTargetUrl} target="_self"><ConnectLogoBeta /></Link>
70+
<Link className="logo" to={logoTargetUrl} target="_self"><ConnectLogo /></Link>
7171
</div>
7272
)
7373
const avatar = (

src/projects/detail/Dashboard.jsx

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import React from 'react'
2+
import { connect } from 'react-redux'
23
import ProjectInfoContainer from './containers/ProjectInfoContainer'
34
import FeedContainer from './containers/FeedContainer'
45
import Sticky from 'react-stickynode'
6+
import spinnerWhileLoading from '../../components/LoadingSpinner'
57

68
require('./Dashboard.scss')
79

8-
const Dashboard = ({project, currentMemberRole}) => (
10+
const DashboardView = ({project, currentMemberRole, route}) => (
911
<div>
1012
<div className="dashboard-container">
1113
<div className="left-area">
@@ -16,10 +18,29 @@ const Dashboard = ({project, currentMemberRole}) => (
1618
</Sticky>
1719
</div>
1820
<div className="right-area">
19-
<FeedContainer currentMemberRole={currentMemberRole} project={project} />
21+
<FeedContainer currentMemberRole={currentMemberRole} project={project} route={route} />
2022
</div>
2123
</div>
2224
</div>
2325
)
2426

25-
export default Dashboard
27+
const enhance = spinnerWhileLoading(props => !props.isLoading)
28+
const EnhancedDashboardView = enhance(DashboardView)
29+
30+
class Dashboard extends React.Component {
31+
constructor(props) {
32+
super(props)
33+
}
34+
35+
render() {
36+
return <EnhancedDashboardView {...this.props} />
37+
}
38+
}
39+
40+
const mapStateToProps = ({ projectState }) => {
41+
return {
42+
isLoading : projectState.isLoading
43+
}
44+
}
45+
46+
export default connect(mapStateToProps)(Dashboard)

src/projects/detail/Messages.jsx

+7-2
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/Messages.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
@include flexBox;
1919
max-width: 1110px;
2020
margin: 20px auto;
21-
height: calc(100% - 20px);// 20px is for bottom margin
21+
height: calc(100% - 80px);// 20px is for bottom margin, 60px for footer
2222

2323
.left-area {
2424
@include flexWidth(1);
2525
max-width: 360px;
2626
z-index: 14;/* Don't know the exact reason, but it needs explicit z-index to get behind the topbar*/
27+
transform: translate3d(0px, 0px, 0px);
2728
}
2829
.right-area {
2930
@include flexWidth(2);

src/projects/detail/containers/FeedContainer.js

+50-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { PropTypes } from 'react'
2+
import { withRouter } from 'react-router'
23
import _ from 'lodash'
34
import {
45
THREAD_MESSAGES_PAGE_SIZE,
@@ -36,7 +37,16 @@ class FeedView extends React.Component {
3637
this.onNewCommentChange = this.onNewCommentChange.bind(this)
3738
this.onShowAllComments = this.onShowAllComments.bind(this)
3839
this.onAddNewComment = this.onAddNewComment.bind(this)
39-
this.state = { feeds : [], showAll: [] }
40+
this.onLeave = this.onLeave.bind(this)
41+
this.isChanged = this.isChanged.bind(this)
42+
this.onNewPostChange = this.onNewPostChange.bind(this)
43+
this.state = { feeds : [], showAll: [], newPost: {} }
44+
}
45+
46+
componentDidMount() {
47+
const routeLeaveHook = this.props.router.setRouteLeaveHook(this.props.route, this.onLeave)
48+
window.addEventListener('beforeunload', this.onLeave)
49+
this.setState({ routeLeaveHook })
4050
}
4151

4252
componentWillMount() {
@@ -47,7 +57,28 @@ class FeedView extends React.Component {
4757
this.init(nextProps)
4858
}
4959

50-
mapFeed(feed, showAll = false) {
60+
componentWillUnmount() {
61+
if (this.state.routeLeaveHook) {
62+
this.state.routeLeaveHook()
63+
}
64+
window.removeEventListener('beforeunload', this.onLeave)
65+
}
66+
67+
// Notify user if they navigate away while the form is modified.
68+
onLeave(e) {
69+
if (this.isChanged()) {
70+
return e.returnValue = 'You have uposted content. Are you sure you want to leave?'
71+
}
72+
}
73+
74+
isChanged() {
75+
const { newPost } = this.state
76+
const hasComment = !_.isUndefined(_.find(this.state.feeds, (feed) => feed.newComment && feed.newComment.length))
77+
const hasThread = (newPost.title && !!newPost.title.trim().length) || ( newPost.content && !!newPost.content.trim().length)
78+
return hasThread || hasComment
79+
}
80+
81+
mapFeed(feed, showAll = false, resetNewComment = false) {
5182
const { allMembers } = this.props
5283
const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error'])
5384
if (isSystemUser(item.userId)) {
@@ -72,20 +103,27 @@ class FeedView extends React.Component {
72103
author: isSystemUser(p.userId) ? SYSTEM_USER : allMembers[p.userId]
73104
}
74105
}
106+
const validPost = (post) => {
107+
return post.type === 'post' && (post.body && post.body.trim().length || !isSystemUser(post.userId))
108+
}
75109
if (showAll) {
76110
// if we are showing all comments, just iterate through the entire array
77111
_.forEach(_.slice(feed.posts, 1), p => {
78-
p.type === 'post' ? item.comments.push(_toComment(p)) : item.totalComments--
112+
validPost(p) ? item.comments.push(_toComment(p)) : item.totalComments--
79113
})
80114
} else {
81115
// otherwise iterate from right and add to the beginning of the array
82116
_.forEachRight(_.slice(feed.posts, 1), (p) => {
83-
p.type === 'post' ? item.comments.unshift(_toComment(p)) : item.totalComments--
117+
validPost(p) ? item.comments.unshift(_toComment(p)) : item.totalComments--
84118
if (!feed.showAll && item.comments.length === THREAD_MESSAGES_PAGE_SIZE)
85119
return false
86120
})
87121
}
88122
item.newComment = ''
123+
if (!resetNewComment) {
124+
const feedFromState = _.find(this.state.feeds, f => feed.id === f.id)
125+
item.newComment = feedFromState ? feedFromState.newComment : ''
126+
}
89127
item.hasMoreComments = item.comments.length !== item.totalComments
90128
return item
91129
}
@@ -99,6 +137,12 @@ class FeedView extends React.Component {
99137
})
100138
}
101139

140+
onNewPostChange(title, content) {
141+
this.setState({
142+
newPost: {title, content}
143+
})
144+
}
145+
102146
onNewPost({title, content}) {
103147
const { project } = this.props
104148
const newFeed = {
@@ -194,6 +238,7 @@ class FeedView extends React.Component {
194238
isCreating={ isCreatingFeed }
195239
hasError={ error }
196240
heading="NEW STATUS POST"
241+
onNewPostChange={this.onNewPostChange}
197242
titlePlaceholder="Share the latest project updates with the team"
198243
/>
199244
}
@@ -203,7 +248,7 @@ class FeedView extends React.Component {
203248
}
204249
}
205250
const enhance = spinnerWhileLoading(props => !props.isLoading)
206-
const EnhancedFeedView = enhance(FeedView)
251+
const EnhancedFeedView = withRouter(enhance(FeedView))
207252

208253

209254
class FeedContainer extends React.Component {

0 commit comments

Comments
 (0)