refactor(component): convert TextDismissableBar from class to function component (#27955)
* refactor(component): convert TextDismissableBar from class to function component * perf:Code optimized * refactor(component):props vertically formatted, getDismissed function moved outside * Update webapp/channels/src/components/announcement_bar/text_dismissable_bar.tsx Co-authored-by: Daniel Espino García <larkox@gmail.com> * refactor:setDismissed formatted vertically * test(text_dismissable_bar):snapshot test updated * refactor: remove type from shallow rendering in TextDismissableBar test --------- Co-authored-by: Daniel Espino García <larkox@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -20,7 +20,6 @@ exports[`components/TextDismissableBar should match snapshot 1`] = `
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
onDismissal={[MockFunction]}
|
|
||||||
showCloseButton={true}
|
showCloseButton={true}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
@@ -45,7 +44,6 @@ exports[`components/TextDismissableBar should match snapshot, with an internal a
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
onDismissal={[MockFunction]}
|
|
||||||
showCloseButton={true}
|
showCloseButton={true}
|
||||||
siteURL="http://testurl.com"
|
siteURL="http://testurl.com"
|
||||||
/>
|
/>
|
||||||
@@ -71,7 +69,6 @@ exports[`components/TextDismissableBar should match snapshot, with an internal u
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
onDismissal={[MockFunction]}
|
|
||||||
showCloseButton={true}
|
showCloseButton={true}
|
||||||
siteURL="http://testurl.com"
|
siteURL="http://testurl.com"
|
||||||
/>
|
/>
|
||||||
@@ -97,7 +94,6 @@ exports[`components/TextDismissableBar should match snapshot, with ean external
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
onDismissal={[MockFunction]}
|
|
||||||
showCloseButton={true}
|
showCloseButton={true}
|
||||||
siteURL="http://testurl.com"
|
siteURL="http://testurl.com"
|
||||||
/>
|
/>
|
||||||
@@ -123,7 +119,6 @@ exports[`components/TextDismissableBar should match snapshot, with link but with
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
onDismissal={[MockFunction]}
|
|
||||||
showCloseButton={true}
|
showCloseButton={true}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -16,45 +16,35 @@ describe('components/TextDismissableBar', () => {
|
|||||||
|
|
||||||
test('should match snapshot', () => {
|
test('should match snapshot', () => {
|
||||||
const props = baseProps;
|
const props = baseProps;
|
||||||
const wrapper = shallow<TextDismissableBar>(
|
const wrapper = shallow(<TextDismissableBar {...props}/>);
|
||||||
<TextDismissableBar {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, with link but without siteURL', () => {
|
test('should match snapshot, with link but without siteURL', () => {
|
||||||
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/)'};
|
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/)'};
|
||||||
const wrapper = shallow<TextDismissableBar>(
|
const wrapper = shallow(<TextDismissableBar {...props}/>);
|
||||||
<TextDismissableBar {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, with an internal url', () => {
|
test('should match snapshot, with an internal url', () => {
|
||||||
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/) with an internal url', siteURL: 'http://testurl.com'};
|
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/) with an internal url', siteURL: 'http://testurl.com'};
|
||||||
const wrapper = shallow<TextDismissableBar>(
|
const wrapper = shallow(<TextDismissableBar {...props}/>);
|
||||||
<TextDismissableBar {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, with ean external url', () => {
|
test('should match snapshot, with ean external url', () => {
|
||||||
const props = {...baseProps, text: 'A [link](http://otherurl.com/admin_console/) with an external url', siteURL: 'http://testurl.com'};
|
const props = {...baseProps, text: 'A [link](http://otherurl.com/admin_console/) with an external url', siteURL: 'http://testurl.com'};
|
||||||
const wrapper = shallow<TextDismissableBar>(
|
const wrapper = shallow(<TextDismissableBar {...props}/>);
|
||||||
<TextDismissableBar {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, with an internal and an external link', () => {
|
test('should match snapshot, with an internal and an external link', () => {
|
||||||
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/) with an internal url and a [link](http://other-url.com/admin_console/) with an external url', siteURL: 'http://testurl.com'};
|
const props = {...baseProps, text: 'A [link](http://testurl.com/admin_console/) with an internal url and a [link](http://other-url.com/admin_console/) with an external url', siteURL: 'http://testurl.com'};
|
||||||
const wrapper = shallow<TextDismissableBar>(
|
const wrapper = shallow(<TextDismissableBar {...props}/>);
|
||||||
<TextDismissableBar {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
|
|
||||||
import {trackEvent} from 'actions/telemetry_actions.jsx';
|
import {trackEvent} from 'actions/telemetry_actions.jsx';
|
||||||
|
|
||||||
@@ -20,67 +20,58 @@ interface Props extends Partial<AnnouncementBarProps> {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
const options = {
|
||||||
dismissed: boolean;
|
singleline: true,
|
||||||
}
|
mentionHighlight: false,
|
||||||
|
};
|
||||||
|
|
||||||
export default class TextDismissableBar extends React.PureComponent<Props, State> {
|
const getDismissed = (text?: React.ReactNode) => localStorage.getItem(localStoragePrefix + text?.toString()) === 'true';
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
const TextDismissableBar = ({
|
||||||
dismissed: true,
|
allowDismissal,
|
||||||
};
|
text,
|
||||||
}
|
onDismissal,
|
||||||
|
...extraProps
|
||||||
|
}: Props) => {
|
||||||
|
const [dismissed, setDismissed] = useState<boolean>(() => getDismissed(text));
|
||||||
|
|
||||||
static getDerivedStateFromProps(props: Props) {
|
useEffect(() => {
|
||||||
const dismissed = localStorage.getItem(localStoragePrefix + props.text?.toString());
|
setDismissed(getDismissed(text));
|
||||||
return {
|
}, [text]);
|
||||||
dismissed: (dismissed === 'true'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDismiss = () => {
|
const handleDismiss = useCallback(() => {
|
||||||
if (!this.props.allowDismissal) {
|
if (!allowDismissal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trackEvent('signup', 'click_dismiss_bar');
|
trackEvent('signup', 'click_dismiss_bar');
|
||||||
|
|
||||||
localStorage.setItem(localStoragePrefix + this.props.text?.toString(), 'true');
|
localStorage.setItem(localStoragePrefix + text?.toString(), 'true');
|
||||||
this.setState({
|
setDismissed(true);
|
||||||
dismissed: true,
|
onDismissal?.();
|
||||||
});
|
}, [allowDismissal, onDismissal, text]);
|
||||||
if (this.props.onDismissal) {
|
|
||||||
this.props.onDismissal();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
if (dismissed) {
|
||||||
if (this.state.dismissed) {
|
return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const {allowDismissal, text, ...extraProps} = this.props;
|
|
||||||
return (
|
|
||||||
<AnnouncementBar
|
|
||||||
{...extraProps}
|
|
||||||
showCloseButton={allowDismissal}
|
|
||||||
handleClose={this.handleDismiss}
|
|
||||||
message={
|
|
||||||
<>
|
|
||||||
<i className='icon icon-information-outline'/>
|
|
||||||
{typeof text === 'string' ? (
|
|
||||||
<Markdown
|
|
||||||
message={text}
|
|
||||||
options={{
|
|
||||||
singleline: true,
|
|
||||||
mentionHighlight: false,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : text}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnnouncementBar
|
||||||
|
{...extraProps}
|
||||||
|
showCloseButton={allowDismissal}
|
||||||
|
handleClose={handleDismiss}
|
||||||
|
message={
|
||||||
|
<>
|
||||||
|
<i className='icon icon-information-outline'/>
|
||||||
|
{typeof text === 'string' ? (
|
||||||
|
<Markdown
|
||||||
|
message={text}
|
||||||
|
options={options}
|
||||||
|
/>
|
||||||
|
) : text}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TextDismissableBar;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user