Commit 51cdff4f authored by Joram Wilander's avatar Joram Wilander Committed by Derrick Anderson
Browse files

MM-10541 Update announcement banner immediately without refresh (#1199)

* Update announcement banner immediately without refresh

* Add unit tests

* Add credit for local storage mock
parent 349fd518
......@@ -56,7 +56,17 @@ export default class AnnouncementBar extends React.PureComponent {
this.setInitialError();
this.state = this.getState();
this.state = this.getState(props);
}
componentWillReceiveProps(nextProps) {
if (nextProps.enableBanner !== this.props.enableBanner ||
nextProps.bannerText !== this.props.bannerText ||
nextProps.bannerColor !== this.props.bannerColor ||
nextProps.bannerTextColor !== this.props.bannerTextColor ||
nextProps.allowBannerDismissal !== this.props.allowBannerDismissal) {
this.setState(this.getState(nextProps));
}
}
setInitialError = () => {
......@@ -85,17 +95,17 @@ export default class AnnouncementBar extends React.PureComponent {
}
}
getState() {
getState(props = this.props) {
const error = ErrorStore.getLastError();
if (error && error.message) {
return {message: error.message, color: null, textColor: null, type: error.type, allowDismissal: true};
}
const bannerText = this.props.bannerText || '';
const allowDismissal = this.props.allowBannerDismissal;
const bannerDismissed = localStorage.getItem(StoragePrefixes.ANNOUNCEMENT + this.props.bannerText);
const bannerText = props.bannerText || '';
const allowDismissal = props.allowBannerDismissal;
const bannerDismissed = localStorage.getItem(StoragePrefixes.ANNOUNCEMENT + props.bannerText);
if (this.props.enableBanner &&
if (props.enableBanner &&
bannerText.length > 0 &&
(!bannerDismissed || !allowDismissal)
) {
......@@ -103,8 +113,8 @@ export default class AnnouncementBar extends React.PureComponent {
Utils.removePrefixFromLocalStorage(StoragePrefixes.ANNOUNCEMENT);
return {
message: bannerText,
color: this.props.bannerColor,
textColor: this.props.bannerTextColor,
color: props.bannerColor,
textColor: props.bannerTextColor,
type: BAR_ANNOUNCEMENT_TYPE,
allowDismissal,
};
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/AnnouncementBar should match snapshot, bar not showing 1`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, bar showing 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, bar showing, no dismissal 1`] = `
<div
className="error-bar error-bar--fixed"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, dismissal 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, dismissal 2`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, dismissal 3`] = `<div />`;
exports[`components/AnnouncementBar should match snapshot, dismissal 4`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Some new text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "red",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 1`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "green",
"color": "black",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "black",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 2`] = `
<div
className="error-bar"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
<a
className="error-bar__close"
href="#"
onClick={[Function]}
style={
Object {
"color": "red",
}
}
>
×
</a>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 3`] = `
<div
className="error-bar error-bar--fixed"
style={
Object {
"backgroundColor": "yellow",
"color": "red",
}
}
>
<span>
<span
dangerouslySetInnerHTML={
Object {
"__html": "<p class=\\"markdown__paragraph-inline\\">Banner text</p>",
}
}
/>
</span>
</div>
`;
exports[`components/AnnouncementBar should match snapshot, props change 4`] = `<div />`;
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import 'tests/helpers/localstorage.jsx';
import AnnouncementBar from 'components/announcement_bar/announcement_bar.jsx';
describe('components/AnnouncementBar', () => {
const baseProps = {
isLoggedIn: true,
canViewSystemErrors: false,
canViewAPIv3Banner: false,
licenseId: '',
siteURL: '',
sendEmailNotifications: true,
bannerText: 'Banner text',
allowBannerDismissal: true,
enableBanner: true,
bannerColor: 'green',
bannerTextColor: 'black',
enableSignUpWithGitLab: false,
};
test('should match snapshot, bar showing', () => {
const props = baseProps;
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, bar not showing', () => {
const props = {...baseProps, enableBanner: false};
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, bar showing, no dismissal', () => {
const props = {...baseProps, allowBannerDismissal: false};
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, props change', () => {
const props = baseProps;
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
expect(wrapper).toMatchSnapshot();
const newProps = {...baseProps, bannerColor: 'yellow', bannerTextColor: 'red'};
wrapper.setProps(newProps);
expect(wrapper).toMatchSnapshot();
newProps.allowBannerDismissal = false;
wrapper.setProps(newProps);
expect(wrapper).toMatchSnapshot();
newProps.enableBanner = false;
wrapper.setProps(newProps);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, dismissal', () => {
const props = baseProps;
const wrapper = shallow(
<AnnouncementBar {...props}/>
);
// Banner should show
expect(wrapper).toMatchSnapshot();
// Banner should hide
wrapper.find('a').simulate('click');
expect(wrapper).toMatchSnapshot();
// Banner should remain hidden
const newProps = {...baseProps, bannerColor: 'yellow', bannerTextColor: 'red'};
wrapper.setProps(newProps);
expect(wrapper).toMatchSnapshot();
// Banner should return
newProps.bannerText = 'Some new text';
wrapper.setProps(newProps);
expect(wrapper).toMatchSnapshot();
});
});
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Based on https://stackoverflow.com/a/41434763
class LocalStorageMock {
constructor() {
this.store = {};
}
clear() {
this.store = {};
}
getItem(key) {
return this.store[key] || null;
}
setItem(key, value) {
this.store[key] = value.toString();
}
removeItem(key) {
delete this.store[key];
}
}
global.localStorage = new LocalStorageMock();
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment