From e6f7a47c99075a39d862308659b904bfaf64a11a Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Fri, 4 Nov 2016 11:21:14 -0400 Subject: PLT-4507 Don't mount modals until opened to make resetting state automatic (#4358) * Don't mount modals until opened to make resetting state automatic * Move dimiss handler to be fired after modal exit animation complete --- webapp/components/access_history_modal.jsx | 38 ++++++++---------- webapp/components/activity_log_modal.jsx | 38 +++++++++--------- webapp/components/channel_header.jsx | 36 ++++++++++++----- webapp/components/channel_info_modal.jsx | 22 +++++----- webapp/components/channel_invite_modal.jsx | 42 +++++++++---------- webapp/components/channel_members_modal.jsx | 49 +++++++++-------------- webapp/components/channel_notifications_modal.jsx | 37 ++++++++--------- webapp/components/delete_channel_modal.jsx | 15 +++++-- webapp/components/edit_channel_header_modal.jsx | 32 +++------------ webapp/components/edit_channel_purpose_modal.jsx | 33 +++++---------- webapp/components/more_direct_channels.jsx | 15 +------ webapp/components/navbar.jsx | 48 ++++++++++++---------- webapp/components/sidebar.jsx | 15 +++++-- webapp/components/sidebar_header_dropdown.jsx | 16 +++++--- webapp/components/sidebar_right_menu.jsx | 2 +- webapp/components/team_members_modal.jsx | 16 +++++--- webapp/components/toggle_modal_button.jsx | 24 ++++++----- 17 files changed, 233 insertions(+), 245 deletions(-) (limited to 'webapp') diff --git a/webapp/components/access_history_modal.jsx b/webapp/components/access_history_modal.jsx index 9c49c3879..4ed2ad9ab 100644 --- a/webapp/components/access_history_modal.jsx +++ b/webapp/components/access_history_modal.jsx @@ -1,8 +1,6 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import $ from 'jquery'; -import {Modal} from 'react-bootstrap'; import LoadingScreen from './loading_screen.jsx'; import AuditTable from './audit_table.jsx'; @@ -11,11 +9,13 @@ import UserStore from 'stores/user_store.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import * as Utils from 'utils/utils.jsx'; -import {intlShape, injectIntl, FormattedMessage} from 'react-intl'; - +import $ from 'jquery'; import React from 'react'; -class AccessHistoryModal extends React.Component { +import {Modal} from 'react-bootstrap'; +import {FormattedMessage} from 'react-intl'; + +export default class AccessHistoryModal extends React.Component { constructor(props) { super(props); @@ -25,45 +25,44 @@ class AccessHistoryModal extends React.Component { const state = this.getStateFromStoresForAudits(); state.moreInfo = []; + state.show = true; this.state = state; } + getStateFromStoresForAudits() { return { audits: UserStore.getAudits() }; } + onShow() { AsyncClient.getAudits(); if (!Utils.isMobile()) { $('.modal-body').perfectScrollbar(); } } + onHide() { - this.setState({moreInfo: []}); - this.props.onHide(); + this.setState({show: false}); } + componentDidMount() { UserStore.addAuditsChangeListener(this.onAuditChange); - - if (this.props.show) { - this.onShow(); - } - } - componentDidUpdate(prevProps) { - if (this.props.show && !prevProps.show) { - this.onShow(); - } + this.onShow(); } + componentWillUnmount() { UserStore.removeAuditsChangeListener(this.onAuditChange); } + onAuditChange() { var newState = this.getStateFromStoresForAudits(); if (!Utils.areObjectsEqual(newState.audits, this.state.audits)) { this.setState(newState); } } + render() { var content; if (this.state.audits.loading) { @@ -80,8 +79,9 @@ class AccessHistoryModal extends React.Component { return ( @@ -101,9 +101,5 @@ class AccessHistoryModal extends React.Component { } AccessHistoryModal.propTypes = { - intl: intlShape.isRequired, - show: React.PropTypes.bool.isRequired, onHide: React.PropTypes.func.isRequired }; - -export default injectIntl(AccessHistoryModal); diff --git a/webapp/components/activity_log_modal.jsx b/webapp/components/activity_log_modal.jsx index 2c093e1d2..b907668f0 100644 --- a/webapp/components/activity_log_modal.jsx +++ b/webapp/components/activity_log_modal.jsx @@ -1,17 +1,18 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import $ from 'jquery'; +import LoadingScreen from './loading_screen.jsx'; + import UserStore from 'stores/user_store.jsx'; + import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; -import {Modal} from 'react-bootstrap'; -import LoadingScreen from './loading_screen.jsx'; import * as Utils from 'utils/utils.jsx'; -import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl'; - +import $ from 'jquery'; import React from 'react'; +import {Modal} from 'react-bootstrap'; +import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl'; export default class ActivityLogModal extends React.Component { constructor(props) { @@ -25,9 +26,11 @@ export default class ActivityLogModal extends React.Component { const state = this.getStateFromStores(); state.moreInfo = []; + state.show = true; this.state = state; } + getStateFromStores() { return { sessions: UserStore.getSessions(), @@ -35,6 +38,7 @@ export default class ActivityLogModal extends React.Component { clientError: null }; } + submitRevoke(altId, e) { e.preventDefault(); var modalContent = $(e.target).closest('.modal-content'); @@ -53,42 +57,40 @@ export default class ActivityLogModal extends React.Component { } ); } + onShow() { AsyncClient.getSessions(); if (!Utils.isMobile()) { $('.modal-body').perfectScrollbar(); } } + onHide() { - this.setState({moreInfo: []}); - this.props.onHide(); + this.setState({show: false}); } + componentDidMount() { UserStore.addSessionsChangeListener(this.onListenerChange); - - if (this.props.show) { - this.onShow(); - } - } - componentDidUpdate(prevProps) { - if (this.props.show && !prevProps.show) { - this.onShow(); - } + this.onShow(); } + componentWillUnmount() { UserStore.removeSessionsChangeListener(this.onListenerChange); } + onListenerChange() { const newState = this.getStateFromStores(); if (!Utils.areObjectsEqual(newState.sessions, this.state.sessions)) { this.setState(newState); } } + handleMoreInfo(index) { const newMoreInfo = this.state.moreInfo; newMoreInfo[index] = true; this.setState({moreInfo: newMoreInfo}); } + render() { const activityList = []; @@ -263,8 +265,9 @@ export default class ActivityLogModal extends React.Component { return ( @@ -290,6 +293,5 @@ export default class ActivityLogModal extends React.Component { } ActivityLogModal.propTypes = { - show: React.PropTypes.bool.isRequired, onHide: React.PropTypes.func.isRequired }; diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx index c7842aaa3..dd0fd5b70 100644 --- a/webapp/components/channel_header.jsx +++ b/webapp/components/channel_header.jsx @@ -450,6 +450,7 @@ export default class ChannelHeader extends React.Component { role='presentation' > ); + let channelMembersModal; + if (this.state.showMembersModal) { + channelMembersModal = ( + this.setState({showMembersModal: false})} + showInviteModal={() => this.refs.channelInviteModalButton.show()} + channel={channel} + isAdmin={isAdmin} + /> + ); + } + + let editPurposeModal; + if (this.state.showEditChannelPurposeModal) { + editPurposeModal = ( + this.setState({showEditChannelPurposeModal: false})} + channel={channel} + /> + ); + } + return (
- this.setState({showEditChannelPurposeModal: false})} - channel={channel} - /> - this.setState({showMembersModal: false})} - channel={channel} - isAdmin={isAdmin} - /> + {editPurposeModal} + {channelMembersModal} @@ -123,7 +124,6 @@ export default class ChannelInfoModal extends React.Component { } ChannelInfoModal.propTypes = { - show: React.PropTypes.bool.isRequired, onHide: React.PropTypes.func.isRequired, channel: React.PropTypes.object.isRequired }; diff --git a/webapp/components/channel_invite_modal.jsx b/webapp/components/channel_invite_modal.jsx index 576a33dc5..29607136c 100644 --- a/webapp/components/channel_invite_modal.jsx +++ b/webapp/components/channel_invite_modal.jsx @@ -26,6 +26,7 @@ export default class ChannelInviteModal extends React.Component { this.onChange = this.onChange.bind(this); this.onStatusChange = this.onStatusChange.bind(this); + this.onHide = this.onHide.bind(this); this.handleInviteError = this.handleInviteError.bind(this); this.nextPage = this.nextPage.bind(this); this.search = this.search.bind(this); @@ -36,34 +37,27 @@ export default class ChannelInviteModal extends React.Component { const teamStats = TeamStore.getCurrentStats(); this.state = { - users: [], + users: null, total: teamStats.member_count - channelStats.member_count, + show: true, search: false, statusChange: false }; } - componentWillReceiveProps(nextProps) { - if (!this.props.show && nextProps.show) { - TeamStore.addStatsChangeListener(this.onChange); - ChannelStore.addStatsChangeListener(this.onChange); - UserStore.addNotInChannelChangeListener(this.onChange); - UserStore.addStatusesChangeListener(this.onStatusChange); - - this.onChange(); - AsyncClient.getProfilesNotInChannel(this.props.channel.id, 0); - AsyncClient.getTeamStats(TeamStore.getCurrentId()); - } else if (this.props.show && !nextProps.show) { - TeamStore.removeStatsChangeListener(this.onChange); - ChannelStore.removeStatsChangeListener(this.onChange); - UserStore.removeNotInChannelChangeListener(this.onChange); - UserStore.removeStatusesChangeListener(this.onStatusChange); - } + componentDidMount() { + TeamStore.addStatsChangeListener(this.onChange); + ChannelStore.addStatsChangeListener(this.onChange); + UserStore.addNotInChannelChangeListener(this.onChange); + UserStore.addStatusesChangeListener(this.onStatusChange); + + AsyncClient.getProfilesNotInChannel(this.props.channel.id, 0); + AsyncClient.getTeamStats(TeamStore.getCurrentId()); } componentWillUnmount() { + TeamStore.removeStatsChangeListener(this.onChange); ChannelStore.removeStatsChangeListener(this.onChange); - ChannelStore.removeChangeListener(this.onChange); UserStore.removeNotInChannelChangeListener(this.onChange); UserStore.removeStatusesChangeListener(this.onStatusChange); } @@ -90,6 +84,10 @@ export default class ChannelInviteModal extends React.Component { }); } + onHide() { + this.setState({show: false}); + } + handleInviteError(err) { if (err) { this.setState({ @@ -159,8 +157,9 @@ export default class ChannelInviteModal extends React.Component { return ( @@ -179,7 +178,7 @@ export default class ChannelInviteModal extends React.Component {
); } } -ChannelMembersModal.defaultProps = { - show: false -}; - ChannelMembersModal.propTypes = { - show: React.PropTypes.bool.isRequired, onModalDismissed: React.PropTypes.func.isRequired, + showInviteModal: React.PropTypes.func.isRequired, channel: React.PropTypes.object.isRequired, isAdmin: React.PropTypes.bool.isRequired }; diff --git a/webapp/components/channel_notifications_modal.jsx b/webapp/components/channel_notifications_modal.jsx index 59ec40d84..ff6e69f70 100644 --- a/webapp/components/channel_notifications_modal.jsx +++ b/webapp/components/channel_notifications_modal.jsx @@ -1,23 +1,23 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import $ from 'jquery'; -import {Modal} from 'react-bootstrap'; -import SettingItemMin from './setting_item_min.jsx'; -import SettingItemMax from './setting_item_max.jsx'; +import SettingItemMin from 'components/setting_item_min.jsx'; +import SettingItemMax from 'components/setting_item_max.jsx'; import Client from 'client/web_client.jsx'; import ChannelStore from 'stores/channel_store.jsx'; -import {FormattedMessage} from 'react-intl'; - +import $ from 'jquery'; import React from 'react'; +import {Modal} from 'react-bootstrap'; +import {FormattedMessage} from 'react-intl'; export default class ChannelNotificationsModal extends React.Component { constructor(props) { super(props); this.updateSection = this.updateSection.bind(this); + this.onHide = this.onHide.bind(this); this.handleSubmitNotifyLevel = this.handleSubmitNotifyLevel.bind(this); this.handleUpdateNotifyLevel = this.handleUpdateNotifyLevel.bind(this); @@ -29,24 +29,23 @@ export default class ChannelNotificationsModal extends React.Component { this.state = { activeSection: '', - notifyLevel: '', - unreadLevel: '' + show: true, + notifyLevel: props.channelMember.notify_props.desktop, + unreadLevel: props.channelMember.notify_props.mark_unread }; } + updateSection(section) { if ($('.section-max').length) { $('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update'); } this.setState({activeSection: section}); } - componentWillReceiveProps(nextProps) { - if (!this.props.show && nextProps.show) { - this.setState({ - notifyLevel: nextProps.channelMember.notify_props.desktop, - unreadLevel: nextProps.channelMember.notify_props.mark_unread - }); - } + + onHide() { + this.setState({show: false}); } + handleSubmitNotifyLevel() { var channelId = this.props.channel.id; var notifyLevel = this.state.notifyLevel; @@ -75,9 +74,11 @@ export default class ChannelNotificationsModal extends React.Component { } ); } + handleUpdateNotifyLevel(notifyLevel) { this.setState({notifyLevel}); } + createNotifyLevelSection(serverError) { // Get glabal user setting for notifications const globalNotifyLevel = this.props.currentUser.notify_props ? this.props.currentUser.notify_props.desktop : 'all'; @@ -380,9 +381,10 @@ export default class ChannelNotificationsModal extends React.Component { return ( @@ -417,7 +419,6 @@ export default class ChannelNotificationsModal extends React.Component { } ChannelNotificationsModal.propTypes = { - show: React.PropTypes.bool.isRequired, onHide: React.PropTypes.func.isRequired, channel: React.PropTypes.object.isRequired, channelMember: React.PropTypes.object.isRequired, diff --git a/webapp/components/delete_channel_modal.jsx b/webapp/components/delete_channel_modal.jsx index 7ad213395..1b642861a 100644 --- a/webapp/components/delete_channel_modal.jsx +++ b/webapp/components/delete_channel_modal.jsx @@ -20,6 +20,9 @@ export default class DeleteChannelModal extends React.Component { super(props); this.handleDelete = this.handleDelete.bind(this); + this.onHide = this.onHide.bind(this); + + this.state = {show: true}; } handleDelete() { @@ -39,6 +42,10 @@ export default class DeleteChannelModal extends React.Component { ); } + onHide() { + this.setState({show: false}); + } + render() { let channelTerm = (

@@ -84,7 +92,7 @@ export default class DeleteChannelModal extends React.Component {