Skip to content

Commit

Permalink
[MM-24016] - Fix channel header when there is an announcement bar in … (
Browse files Browse the repository at this point in the history
mattermost#5291)

* [MM-24016] - Fix channel header when there is an announcement bar in the page

* Connect announcement bar in order to get the correct top offset

* Fix tests

* Update PR comments

* Fix tests and update utils.jsx

Co-authored-by: Nevyana Angelova <[email protected]>
  • Loading branch information
nevyangelova and Nevyana Angelova committed Apr 9, 2020
1 parent 875a63c commit 32c3e3b
Show file tree
Hide file tree
Showing 18 changed files with 118 additions and 47 deletions.
16 changes: 16 additions & 0 deletions actions/views/announcement_bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {ActionTypes} from 'utils/constants';

export function incrementAnnouncementBarCount() {
return {
type: ActionTypes.TRACK_ANNOUNCEMENT_BAR,
};
}

export function decrementAnnouncementBarCount() {
return {
type: ActionTypes.DISMISS_ANNOUNCEMENT_BAR,
};
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`components/TextDismissableBar should match snapshot 1`] = `
<AnnouncementBar
color=""
<Connect(AnnouncementBar)
extraProp="test"
handleClose={[Function]}
message={
Expand All @@ -18,14 +17,11 @@ exports[`components/TextDismissableBar should match snapshot 1`] = `
}
onDismissal={[MockFunction]}
showCloseButton={true}
textColor=""
type="critical"
/>
`;

exports[`components/TextDismissableBar should match snapshot, with an internal and an external link 1`] = `
<AnnouncementBar
color=""
<Connect(AnnouncementBar)
extraProp="test"
handleClose={[Function]}
message={
Expand All @@ -42,14 +38,11 @@ exports[`components/TextDismissableBar should match snapshot, with an internal a
onDismissal={[MockFunction]}
showCloseButton={true}
siteURL="http:https://testurl.com"
textColor=""
type="critical"
/>
`;

exports[`components/TextDismissableBar should match snapshot, with an internal url 1`] = `
<AnnouncementBar
color=""
<Connect(AnnouncementBar)
extraProp="test"
handleClose={[Function]}
message={
Expand All @@ -66,14 +59,11 @@ exports[`components/TextDismissableBar should match snapshot, with an internal u
onDismissal={[MockFunction]}
showCloseButton={true}
siteURL="http:https://testurl.com"
textColor=""
type="critical"
/>
`;

exports[`components/TextDismissableBar should match snapshot, with ean external url 1`] = `
<AnnouncementBar
color=""
<Connect(AnnouncementBar)
extraProp="test"
handleClose={[Function]}
message={
Expand All @@ -90,14 +80,11 @@ exports[`components/TextDismissableBar should match snapshot, with ean external
onDismissal={[MockFunction]}
showCloseButton={true}
siteURL="http:https://testurl.com"
textColor=""
type="critical"
/>
`;

exports[`components/TextDismissableBar should match snapshot, with link but without siteURL 1`] = `
<AnnouncementBar
color=""
<Connect(AnnouncementBar)
extraProp="test"
handleClose={[Function]}
message={
Expand All @@ -113,7 +100,5 @@ exports[`components/TextDismissableBar should match snapshot, with link but with
}
onDismissal={[MockFunction]}
showCloseButton={true}
textColor=""
type="critical"
/>
`;
5 changes: 4 additions & 1 deletion components/announcement_bar/announcement_bar.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react';
import {shallow} from 'enzyme';
import 'tests/helpers/localstorage.jsx';

import AnnouncementBar from 'components/announcement_bar/announcement_bar.jsx';
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar/announcement_bar.jsx';

describe('components/AnnouncementBar', () => {
const baseProps = {
Expand All @@ -25,8 +25,11 @@ describe('components/AnnouncementBar', () => {
bannerTextColor: 'black',
enableSignUpWithGitLab: false,
message: 'text',
announcementBarCount: 0,
actions: {
sendVerificationEmail: jest.fn(),
incrementAnnouncementBarCount: jest.fn(),
decrementAnnouncementBarCount: jest.fn()
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
import ConfigurationAnnouncementBar from './configuration_bar';
import VersionBar from './version_bar';
import TextDismissableBar from './text_dismissable_bar.jsx';
import AnnouncementBar from './announcement_bar.jsx';
import AnnouncementBar from './default_announcement_bar';

export default class AnnouncementBarController extends React.PureComponent {
static propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {t} from 'utils/i18n';

import FormattedMarkdownMessage from 'components/formatted_markdown_message';

import AnnouncementBar from '../announcement_bar.jsx';
import AnnouncementBar from '../default_announcement_bar';
import TextDismissableBar from '../text_dismissable_bar';

const RENEWAL_LINK = 'https://licensing.mattermost.com/renew';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ export default class AnnouncementBar extends React.PureComponent {
type: PropTypes.string,
message: PropTypes.node.isRequired,
handleClose: PropTypes.func,
announcementBarCount: PropTypes.number.isRequired,
actions: PropTypes.shape({
incrementAnnouncementBarCount: PropTypes.func.isRequired,
decrementAnnouncementBarCount: PropTypes.func.isRequired,
}).isRequired,
}

static defaultProps = {
showCloseButton: false,
color: '',
Expand All @@ -27,23 +33,17 @@ export default class AnnouncementBar extends React.PureComponent {
}

componentDidMount() {
let announcementBarCount = document.body.getAttribute('announcementBarCount') || 0;
announcementBarCount++;
document.body.classList.add('announcement-bar--fixed');
this.props.actions.incrementAnnouncementBarCount();

// keeping a track of mounted AnnouncementBars so that on the last AnnouncementBars unmount we can remove the class on body
document.body.setAttribute('announcementBarCount', announcementBarCount);
document.body.classList.add('announcement-bar--fixed');
}

componentWillUnmount() {
let announcementBarCount = document.body.getAttribute('announcementBarCount');
announcementBarCount--;
document.body.setAttribute('announcementBarCount', announcementBarCount);

// remove the class on body as it is the last announcementBar
if (announcementBarCount === 0) {
if (this.props.announcementBarCount === 1) {
document.body.classList.remove('announcement-bar--fixed');
}

this.props.actions.decrementAnnouncementBarCount();
}

handleClose = (e) => {
Expand Down
27 changes: 27 additions & 0 deletions components/announcement_bar/default_announcement_bar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';

import {incrementAnnouncementBarCount, decrementAnnouncementBarCount} from 'actions/views/announcement_bar';
import {getAnnouncementBarCount} from 'selectors/views/announcement_bar';

import AnnouncementBar from './announcement_bar.jsx';

function mapStateToProps(state) {
return {
announcementBarCount: getAnnouncementBarCount(state)
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
incrementAnnouncementBarCount,
decrementAnnouncementBarCount,
}, dispatch),
};
}

export default connect(mapStateToProps, mapDispatchToProps)(AnnouncementBar);
2 changes: 1 addition & 1 deletion components/announcement_bar/text_dismissable_bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
import Markdown from 'components/markdown';

import AnnouncementBar from './announcement_bar.jsx';
import AnnouncementBar from './default_announcement_bar';

const localStoragePrefix = '__announcement__';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
exports[`components/VersionBar should match snapshot - bar rendered after server version change 1`] = `""`;

exports[`components/VersionBar should match snapshot - bar rendered after server version change 2`] = `
<AnnouncementBar
color=""
handleClose={null}
<Connect(AnnouncementBar)
message={
<React.Fragment>
<FormattedMessage
Expand All @@ -26,8 +24,6 @@ exports[`components/VersionBar should match snapshot - bar rendered after server
.
</React.Fragment>
}
showCloseButton={false}
textColor=""
type="announcement"
/>
`;
2 changes: 1 addition & 1 deletion components/announcement_bar/version_bar/version_bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {FormattedMessage} from 'react-intl';
import {equalServerVersions} from 'utils/server_version';
import {AnnouncementBarTypes} from 'utils/constants';

import AnnouncementBar from '../announcement_bar.jsx';
import AnnouncementBar from '../default_announcement_bar';

export default class VersionBar extends React.PureComponent {
static propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react';
import {shallow} from 'enzyme';

import VersionBar from 'components/announcement_bar/version_bar/version_bar.jsx';
import AnnouncementBar from 'components/announcement_bar/announcement_bar.jsx';
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar';

describe('components/VersionBar', () => {
test('should match snapshot - bar rendered after server version change', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1346,7 +1346,7 @@ exports[`components/ChannelHeader should render properly when populated with cha
style={
Object {
"maxWidth": "0px",
"transform": "translateX(0px)",
"transform": "translate(0px, 0px)",
}
}
>
Expand Down
9 changes: 6 additions & 3 deletions components/channel_header/channel_header.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class ChannelHeader extends React.PureComponent {
teammateNameDisplaySetting: PropTypes.string.isRequired,
currentRelativeTeamUrl: PropTypes.string.isRequired,
newSideBarPreference: PropTypes.bool,
announcementBarCount: PropTypes.number,
};

constructor(props) {
Expand All @@ -94,7 +95,7 @@ class ChannelHeader extends React.PureComponent {
this.headerDescriptionRef = React.createRef();
this.headerPopoverTextMeasurerRef = React.createRef();

this.state = {showSearchBar: ChannelHeader.getShowSearchBar(props), popoverOverlayWidth: 0, showChannelHeaderPopover: false, leftOffset: 0};
this.state = {showSearchBar: ChannelHeader.getShowSearchBar(props), popoverOverlayWidth: 0, showChannelHeaderPopover: false, leftOffset: 0, topOffset: 0};

this.getHeaderMarkdownOptions = memoizeResult((channelNamesMap) => (
{...headerMarkdownOptions, channelNamesMap}
Expand Down Expand Up @@ -263,10 +264,12 @@ class ChannelHeader extends React.PureComponent {
showChannelHeaderPopover = (headerText) => {
const headerDescriptionRect = this.headerDescriptionRef.current.getBoundingClientRect();
const headerPopoverTextMeasurerRect = this.headerPopoverTextMeasurerRef.current.getBoundingClientRect();

const announcementBarSize = 32;
if (headerPopoverTextMeasurerRect.width > headerDescriptionRect.width || headerText.match(/\n{2,}/g)) {
this.setState({showChannelHeaderPopover: true, leftOffset: this.headerDescriptionRef.current.offsetLeft});
}

this.setState({topOffset: (announcementBarSize * this.props.announcementBarCount)});
}

setPopoverOverlayWidth = () => {
Expand Down Expand Up @@ -436,7 +439,7 @@ class ChannelHeader extends React.PureComponent {
id='header-popover'
popoverStyle='info'
popoverSize='lg'
style={{maxWidth: `${this.state.popoverOverlayWidth}px`, transform: `translateX(${this.state.leftOffset}px)`}}
style={{maxWidth: `${this.state.popoverOverlayWidth}px`, transform: `translate(${this.state.leftOffset}px, ${this.state.topOffset}px)`}}
placement='bottom'
className={classNames(['channel-header__popover',
{'chanel-header__popover--lhs_offset': this.props.hasMoreThanOneTeam,
Expand Down
4 changes: 3 additions & 1 deletion components/channel_header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from 'actions/views/rhs';
import {getIsRhsOpen, getRhsState} from 'selectors/rhs';
import {isModalOpen} from 'selectors/views/modals';
import {getAnnouncementBarCount} from 'selectors/views/announcement_bar';
import {ModalIdentifiers} from 'utils/constants';

import ChannelHeader from './channel_header';
Expand Down Expand Up @@ -80,7 +81,8 @@ function makeMapStateToProps() {
hasMoreThanOneTeam,
teammateNameDisplaySetting: getTeammateNameDisplaySetting(state),
currentRelativeTeamUrl: getCurrentRelativeTeamUrl(state),
newSideBarPreference: getNewSidebarPreference(state)
newSideBarPreference: getNewSidebarPreference(state),
announcementBarCount: getAnnouncementBarCount(state)
};
};
}
Expand Down
29 changes: 29 additions & 0 deletions reducers/views/announcement_bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {combineReducers} from 'redux';

import {ActionTypes} from 'utils/constants';

function announcementBarState(state = {announcementBarCount: 0}, action) {
switch (action.type) {
case ActionTypes.TRACK_ANNOUNCEMENT_BAR:
return {
...state,
announcementBarCount: state.announcementBarCount + 1
};

case ActionTypes.DISMISS_ANNOUNCEMENT_BAR:
return {
...state,
announcementBarCount: Math.max(state.announcementBarCount - 1, 0)
};

default:
return state;
}
}

export default combineReducers({
announcementBarState,
});
2 changes: 2 additions & 0 deletions reducers/views/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {combineReducers} from 'redux';

import admin from './admin';
import announcementBar from './announcement_bar';
import browser from './browser';
import channel from './channel';
import rhs from './rhs';
Expand All @@ -23,6 +24,7 @@ import textbox from './textbox';

export default combineReducers({
admin,
announcementBar,
browser,
channel,
rhs,
Expand Down
6 changes: 6 additions & 0 deletions selectors/views/announcement_bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

export function getAnnouncementBarCount(state) {
return state.views.announcementBar.announcementBarState.announcementBarCount;
}
2 changes: 2 additions & 0 deletions utils/constants.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ export const ActionTypes = keyMirror({

SET_UNREAD_FILTER_ENABLED: null,
UPDATE_TOAST_STATUS: null,
TRACK_ANNOUNCEMENT_BAR: null,
DISMISS_ANNOUNCEMENT_BAR: null,
});

export const PostRequestTypes = keyMirror({
Expand Down

0 comments on commit 32c3e3b

Please sign in to comment.