diff --git a/src/components/Feed/Feed.jsx b/src/components/Feed/Feed.jsx index 963cbcdfc..168ee7bb5 100644 --- a/src/components/Feed/Feed.jsx +++ b/src/components/Feed/Feed.jsx @@ -36,8 +36,8 @@ const Feed = (props) => {
- {allowComments && { avatarUrl={currentUser.photoURL} comments={comments} isAddingComment={ isAddingComment } - />} + /> {children} ) diff --git a/src/components/Feed/FeedComments.jsx b/src/components/Feed/FeedComments.jsx index d8e93b8fd..ec8da7997 100644 --- a/src/components/Feed/FeedComments.jsx +++ b/src/components/Feed/FeedComments.jsx @@ -25,7 +25,7 @@ class FeedComments extends React.Component { render() { const { comments, currentUser, totalComments, onLoadMoreComments, isLoadingComments, hasMoreComments, onAdd, - onChange, content, avatarUrl, isAddingComment + onChange, content, avatarUrl, isAddingComment, allowComments } = this.props let authorName = currentUser.firstName if (authorName && currentUser.lastName) { @@ -77,6 +77,7 @@ class FeedComments extends React.Component {
)} + {allowComments && + />}
) } diff --git a/src/components/Feed/NewPost.jsx b/src/components/Feed/NewPost.jsx index 653e16c2e..37d5982ce 100644 --- a/src/components/Feed/NewPost.jsx +++ b/src/components/Feed/NewPost.jsx @@ -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() { @@ -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) { @@ -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 @@ -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'} />
diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index 70876b994..7c0b0ddb0 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -9,7 +9,7 @@ const Footer = () => { const otherNavigationItems = [ {img: '', text: 'About', link: 'https://www.topcoder.com/about-topcoder/', target: '_blank'}, {img: '', text: 'Contact', link: 'https://www.topcoder.com/about-topcoder/contact/', target: '_blank'}, - {img: '', text: 'Help', link: 'https://help.topcoder.com/hc/en-us', target: '_blank'}, + {img: '', text: 'Help', link: 'https://help.topcoder.com/hc/en-us/articles/225540188-Topcoder-Connect-FAQs', target: '_blank'}, {img: '', text: 'Privacy', link: 'https://www.topcoder.com/community/how-it-works/privacy-policy/', target: '_blank'}, {img: '', text: 'Terms', link: 'https://connect.topcoder.com/terms'} ] diff --git a/src/components/FooterV2/FooterV2.jsx b/src/components/FooterV2/FooterV2.jsx index 48ef8a26b..1fd5bb273 100644 --- a/src/components/FooterV2/FooterV2.jsx +++ b/src/components/FooterV2/FooterV2.jsx @@ -6,7 +6,7 @@ const FooterV2 = () => ( diff --git a/src/components/MessageList/MessageList.jsx b/src/components/MessageList/MessageList.jsx index cbd89a0c1..cd85229ec 100644 --- a/src/components/MessageList/MessageList.jsx +++ b/src/components/MessageList/MessageList.jsx @@ -57,8 +57,9 @@ class MessageList extends Component { componentDidMount() { const { scrollPosition } = this.props const panelMessages = this.refs.panelMessages - // 145 = 60 for topbar + 45 for panel title + 20px for margin between topbar and left panel + 10px padding - panelMessages.style.height = (window.innerHeight - 145) + 'px' + // 215 = 60 for topbar + 45 for panel title + 20px for margin between topbar and left panel + 10px padding + // + 60px footer + 10px margin bw footer and left panel + panelMessages.style.height = (window.innerHeight - 215) + 'px' if (scrollPosition) { // We use requestAnimationFrame because this function may be executed before // the DOM elements are actually drawn. diff --git a/src/components/TeamManagement/TeamManagement.scss b/src/components/TeamManagement/TeamManagement.scss index d5ad39582..cbab61f3c 100644 --- a/src/components/TeamManagement/TeamManagement.scss +++ b/src/components/TeamManagement/TeamManagement.scss @@ -214,6 +214,10 @@ $tc-body-extra-small : 12px; } } + input::-ms-clear { + display: none; + } + .modal-inline-form{ display: flex; margin-bottom: $base-unit*2; diff --git a/src/components/TopBar/TopBar.jsx b/src/components/TopBar/TopBar.jsx index 12e3779c2..3c73be10a 100644 --- a/src/components/TopBar/TopBar.jsx +++ b/src/components/TopBar/TopBar.jsx @@ -6,7 +6,7 @@ import cn from 'classnames' import _ from 'lodash' import { UserDropdown, Icons } from 'appirio-tech-react-components' -const { ConnectLogoBeta } = Icons +const { ConnectLogo } = Icons import { SearchBar } from 'appirio-tech-react-components' import Filters from './Filters' import ProjectToolBar from './ProjectToolBar' @@ -67,7 +67,7 @@ class TopBar extends Component { ] const logo = (
- +
) const avatar = ( diff --git a/src/projects/detail/Dashboard.jsx b/src/projects/detail/Dashboard.jsx index 45d89c546..277d41e96 100644 --- a/src/projects/detail/Dashboard.jsx +++ b/src/projects/detail/Dashboard.jsx @@ -1,11 +1,13 @@ import React from 'react' +import { connect } from 'react-redux' import ProjectInfoContainer from './containers/ProjectInfoContainer' import FeedContainer from './containers/FeedContainer' import Sticky from 'react-stickynode' +import spinnerWhileLoading from '../../components/LoadingSpinner' require('./Dashboard.scss') -const Dashboard = ({project, currentMemberRole}) => ( +const DashboardView = ({project, currentMemberRole, route}) => (
@@ -16,10 +18,29 @@ const Dashboard = ({project, currentMemberRole}) => (
- +
) -export default Dashboard +const enhance = spinnerWhileLoading(props => !props.isLoading) +const EnhancedDashboardView = enhance(DashboardView) + +class Dashboard extends React.Component { + constructor(props) { + super(props) + } + + render() { + return + } +} + +const mapStateToProps = ({ projectState }) => { + return { + isLoading : projectState.isLoading + } +} + +export default connect(mapStateToProps)(Dashboard) diff --git a/src/projects/detail/Messages.jsx b/src/projects/detail/Messages.jsx index 3086400fa..a1e9f5a2a 100644 --- a/src/projects/detail/Messages.jsx +++ b/src/projects/detail/Messages.jsx @@ -4,7 +4,12 @@ import MessagesContainer from './containers/MessagesContainer' require('./Messages.scss') -const Messages = ({ location, project, currentMemberRole }) => ( - +const Messages = ({ location, project, currentMemberRole, route }) => ( + ) export default Messages diff --git a/src/projects/detail/Messages.scss b/src/projects/detail/Messages.scss index be8e80b37..201dcdfa4 100644 --- a/src/projects/detail/Messages.scss +++ b/src/projects/detail/Messages.scss @@ -18,12 +18,13 @@ @include flexBox; max-width: 1110px; margin: 20px auto; - height: calc(100% - 20px);// 20px is for bottom margin + height: calc(100% - 80px);// 20px is for bottom margin, 60px for footer .left-area { @include flexWidth(1); max-width: 360px; z-index: 14;/* Don't know the exact reason, but it needs explicit z-index to get behind the topbar*/ + transform: translate3d(0px, 0px, 0px); } .right-area { @include flexWidth(2); diff --git a/src/projects/detail/containers/FeedContainer.js b/src/projects/detail/containers/FeedContainer.js index e14298aaf..f621ca219 100644 --- a/src/projects/detail/containers/FeedContainer.js +++ b/src/projects/detail/containers/FeedContainer.js @@ -1,4 +1,5 @@ import React, { PropTypes } from 'react' +import { withRouter } from 'react-router' import _ from 'lodash' import { THREAD_MESSAGES_PAGE_SIZE, @@ -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() { @@ -47,7 +57,28 @@ class FeedView extends React.Component { this.init(nextProps) } - mapFeed(feed, showAll = false) { + 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, resetNewComment = false) { const { allMembers } = this.props const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error']) if (isSystemUser(item.userId)) { @@ -72,20 +103,27 @@ class FeedView extends React.Component { author: isSystemUser(p.userId) ? SYSTEM_USER : allMembers[p.userId] } } + const validPost = (post) => { + return post.type === 'post' && (post.body && post.body.trim().length || !isSystemUser(post.userId)) + } if (showAll) { // if we are showing all comments, just iterate through the entire array _.forEach(_.slice(feed.posts, 1), p => { - p.type === 'post' ? item.comments.push(_toComment(p)) : item.totalComments-- + validPost(p) ? item.comments.push(_toComment(p)) : item.totalComments-- }) } else { // otherwise iterate from right and add to the beginning of the array _.forEachRight(_.slice(feed.posts, 1), (p) => { - p.type === 'post' ? item.comments.unshift(_toComment(p)) : item.totalComments-- + validPost(p) ? item.comments.unshift(_toComment(p)) : item.totalComments-- if (!feed.showAll && item.comments.length === THREAD_MESSAGES_PAGE_SIZE) return false }) } item.newComment = '' + if (!resetNewComment) { + const feedFromState = _.find(this.state.feeds, f => feed.id === f.id) + item.newComment = feedFromState ? feedFromState.newComment : '' + } item.hasMoreComments = item.comments.length !== item.totalComments return item } @@ -99,6 +137,12 @@ class FeedView extends React.Component { }) } + onNewPostChange(title, content) { + this.setState({ + newPost: {title, content} + }) + } + onNewPost({title, content}) { const { project } = this.props const newFeed = { @@ -194,6 +238,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" /> } @@ -203,7 +248,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 { diff --git a/src/projects/detail/containers/MessagesContainer.js b/src/projects/detail/containers/MessagesContainer.js index 83afdb8f6..6b3455a84 100644 --- a/src/projects/detail/containers/MessagesContainer.js +++ b/src/projects/detail/containers/MessagesContainer.js @@ -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' @@ -9,6 +10,7 @@ import NewPost from '../../../components/Feed/NewPost' import { laodProjectMessages, createProjectTopic, loadFeedComments, addFeedComment } from '../../actions/projectTopics' import spinnerWhileLoading from '../../../components/LoadingSpinner' import {FullHeightContainer} from 'appirio-tech-react-components' +import FooterV2 from '../../../components/FooterV2/FooterV2' import { THREAD_MESSAGES_PAGE_SIZE, @@ -30,12 +32,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() { @@ -46,7 +66,28 @@ class MessagesView extends React.Component { this.init(nextProps) } - mapFeed(feed, isActive, showAll = false) { + 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, resetNewMessage = false) { const { allMembers } = this.props const item = _.pick(feed, ['id', 'date', 'read', 'tag', 'title', 'totalPosts', 'userId', 'reference', 'referenceId', 'postIds', 'isAddingComment', 'isLoadingComments', 'error']) item.isActive = isActive @@ -72,20 +113,27 @@ class MessagesView extends React.Component { author: isSystemUser(p.userId) ? SYSTEM_USER : allMembers[p.userId] } } + const validPost = (post) => { + return post.type === 'post' && (post.body && post.body.trim().length || !isSystemUser(post.userId)) + } if (showAll) { // if we are showing all comments, just iterate through the entire array _.forEach(feed.posts, p => { - p.type === 'post' ? item.messages.push(_toComment(p)) : item.totalComments-- + validPost(p) ? item.messages.push(_toComment(p)) : item.totalComments-- }) } else { // otherwise iterate from right and add to the beginning of the array _.forEachRight(feed.posts, (p) => { - p.type === 'post' ? item.messages.unshift(_toComment(p)) : item.totalComments-- + validPost(p) ? item.messages.unshift(_toComment(p)) : item.totalComments-- if (!feed.showAll && item.messages.length === THREAD_MESSAGES_PAGE_SIZE) return false }) } item.newMessage = '' + if (!resetNewMessage) { + const threadFromState = _.find(this.state.threads, t => feed.id === t.id) + item.newMessage = threadFromState ? threadFromState.newMessage : '' + } item.hasMoreMessages = item.messages.length < item.totalComments return item } @@ -137,15 +185,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} @@ -155,6 +216,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) => { @@ -200,6 +291,7 @@ class MessagesView extends React.Component {
this.setState({isCreateNewMessage: true})} + onAdd={ this.onNewThreadClick } threads={threads} onSelect={this.onThreadSelect} showAddButton={ !!currentMemberRole } showEmptyState={ showEmptyState && !threads.length } scrollPosition={ scrollPosition } /> +
{ (showEmptyState && !threads.length) && @@ -251,7 +344,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) { diff --git a/src/projects/detail/containers/ProjectInfoContainer.js b/src/projects/detail/containers/ProjectInfoContainer.js index 36fce9b24..d4220c89b 100644 --- a/src/projects/detail/containers/ProjectInfoContainer.js +++ b/src/projects/detail/containers/ProjectInfoContainer.js @@ -135,7 +135,7 @@ class ProjectInfoContainer extends React.Component { currentMemberRole={currentMemberRole} description={project.description} type={project.type} - devices={project.details.devices || []} + devices={ _.get(project, 'details.devices', []) } status={project.status} onChangeStatus={this.onChangeStatus} duration={duration} budget={budget} diff --git a/src/projects/detail/containers/TeamManagementContainer.jsx b/src/projects/detail/containers/TeamManagementContainer.jsx index 57383841c..edbd5c67e 100644 --- a/src/projects/detail/containers/TeamManagementContainer.jsx +++ b/src/projects/detail/containers/TeamManagementContainer.jsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux' import { withRouter } from 'react-router' import _ from 'lodash' import { - ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, + ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, ROLE_ADMINISTRATOR, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, PROJECT_ROLE_CUSTOMER, AUTOCOMPLETE_TRIGGER_LENGTH } from '../../../config/constants' import TeamManagement from '../../../components/TeamManagement/TeamManagement' @@ -221,13 +221,14 @@ class TeamManagementContainer extends Component { } const mapStateToProps = ({ loadUser, members }) => { + const powerUserRoles = [ROLE_CONNECT_COPILOT, ROLE_CONNECT_MANAGER, ROLE_ADMINISTRATOR] + const managerRoles = [ ROLE_ADMINISTRATOR, ROLE_CONNECT_MANAGER ] return { currentUser: { userId: parseInt(loadUser.user.id), isCopilot: _.indexOf(loadUser.user.roles, ROLE_CONNECT_COPILOT) > -1, - isManager: _.indexOf(loadUser.user.roles, ROLE_CONNECT_MANAGER) > -1, - isCustomer: _.indexOf(loadUser.user.roles, ROLE_CONNECT_MANAGER) === -1 - && _.indexOf(loadUser.user.roles, ROLE_CONNECT_COPILOT) === -1 + isManager: loadUser.user.roles.some((role) => managerRoles.indexOf(role) !== -1), + isCustomer: !loadUser.user.roles.some((role) => powerUserRoles.indexOf(role) !== -1) }, allMembers: _.values(members.members) } diff --git a/src/projects/reducers/project.js b/src/projects/reducers/project.js index 1791b363f..e1523a823 100644 --- a/src/projects/reducers/project.js +++ b/src/projects/reducers/project.js @@ -9,7 +9,8 @@ import { REMOVE_PROJECT_ATTACHMENT_PENDING, REMOVE_PROJECT_ATTACHMENT_SUCCESS, REMOVE_PROJECT_ATTACHMENT_FAILURE, ADD_PROJECT_MEMBER_PENDING, ADD_PROJECT_MEMBER_SUCCESS, ADD_PROJECT_MEMBER_FAILURE, UPDATE_PROJECT_MEMBER_PENDING, UPDATE_PROJECT_MEMBER_SUCCESS, UPDATE_PROJECT_MEMBER_FAILURE, - REMOVE_PROJECT_MEMBER_PENDING, REMOVE_PROJECT_MEMBER_SUCCESS, REMOVE_PROJECT_MEMBER_FAILURE + REMOVE_PROJECT_MEMBER_PENDING, REMOVE_PROJECT_MEMBER_SUCCESS, REMOVE_PROJECT_MEMBER_FAILURE, + GET_PROJECTS_SUCCESS } from '../../config/constants' import _ from 'lodash' import update from 'react-addons-update' @@ -50,6 +51,7 @@ export const projectState = function (state=initialState, action) { }) case CLEAR_LOADED_PROJECT: + case GET_PROJECTS_SUCCESS: return Object.assign({}, state, { project: {} }) diff --git a/src/projects/reducers/projectTopics.js b/src/projects/reducers/projectTopics.js index 27ee4ee96..c3fa25651 100644 --- a/src/projects/reducers/projectTopics.js +++ b/src/projects/reducers/projectTopics.js @@ -157,6 +157,7 @@ export const projectTopics = function (state=initialState, action) { posts: { $push: payload.posts }, isLoadingComments: { $set : false } }) + updatedFeed.posts = _.sortBy(updatedFeed.posts, ['id']) const feedUpdateQuery = {} feedUpdateQuery[tag] = { topics: { $splice: [[feedIndex, 1, updatedFeed]] } } // update the state diff --git a/src/routes.jsx b/src/routes.jsx index 67ebc1384..d30c7a702 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -17,6 +17,14 @@ const LoginRedirect = withProps({ redirectTo: `${ACCOUNTS_APP_LOGIN_URL}?retUrl=${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}` })(RedirectComponent) +const redirectToConnect = (nextState, replace, callback) => { + if(window.location.hostname.indexOf('connectv2') === 0) { + window.location.assign(window.location.href.replace('connectv2', 'connect')) + return + } + callback() +} + const redirectToProject = (nextState, replace, callback) => { const feedId = nextState.params.feedId getFreshToken().then(() => { @@ -50,7 +58,7 @@ const redirectToProject = (nextState, replace, callback) => { } export default ( - window.scrollTo(0, 0)} component={ App }> + window.scrollTo(0, 0)} component={ App } onEnter={ redirectToConnect }>