[MM-57717] Convert SubMenuModal from Class Component to Function Component (#26902)
* Convert SubMenuModal from Class Component to Function Component * Style fixes * Review fixes * Review fix --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -33,6 +33,7 @@ exports[`components/submenu_modal should match snapshot 1`] = `
|
||||
<ModalBody
|
||||
bsClass="modal-body"
|
||||
componentClass="div"
|
||||
data-testid="SubMenuModalBody"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<MenuWrapper
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {fireEvent, waitForElementToBeRemoved} from '@testing-library/react';
|
||||
import {shallow} from 'enzyme';
|
||||
import React from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
|
||||
import {withIntl} from 'tests/helpers/intl-test-helper';
|
||||
import {render, screen, userEvent} from 'tests/react_testing_utils';
|
||||
|
||||
import SubMenuModal from './submenu_modal';
|
||||
@@ -55,14 +57,20 @@ describe('components/submenu_modal', () => {
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match state when onHide is called', () => {
|
||||
const wrapper = shallow<SubMenuModal>(
|
||||
test('should hide on modal body click', async () => {
|
||||
const view = render(withIntl(
|
||||
<SubMenuModal {...baseProps}/>,
|
||||
);
|
||||
));
|
||||
|
||||
wrapper.setState({show: true});
|
||||
wrapper.instance().onHide();
|
||||
expect(wrapper.state('show')).toEqual(false);
|
||||
screen.getByText('Text A');
|
||||
screen.getByText('Text B');
|
||||
screen.getByText('Text C');
|
||||
|
||||
fireEvent.click(view.getByTestId('SubMenuModalBody'));
|
||||
|
||||
await waitForElementToBeRemoved(() => screen.getByText('Text A'));
|
||||
expect(screen.queryAllByText('Text B').length).toBe(0);
|
||||
expect(screen.queryAllByText('Text C').length).toBe(0);
|
||||
});
|
||||
|
||||
test('should have called click function when button is clicked', async () => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import React, {useCallback, useMemo, useState} from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
|
||||
import * as Utils from 'utils/utils';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
import Menu from '../../menu';
|
||||
import type SubMenuItem from '../../menu_items/submenu_item';
|
||||
@@ -17,63 +16,61 @@ type Props = {
|
||||
onExited: () => void;
|
||||
}
|
||||
|
||||
type State = {
|
||||
show: boolean;
|
||||
}
|
||||
const SubMenuModal = ({
|
||||
elements,
|
||||
onExited,
|
||||
}: Props) => {
|
||||
const [show, setShow] = useState(true);
|
||||
const intl = useIntl();
|
||||
|
||||
export default class SubMenuModal extends React.PureComponent<Props, State> {
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
show: true,
|
||||
};
|
||||
}
|
||||
const onHide = useCallback(() => {
|
||||
setShow(false);
|
||||
}, []);
|
||||
|
||||
public onHide = () => { //public because it is used on tests
|
||||
this.setState({show: false});
|
||||
};
|
||||
|
||||
public render() {
|
||||
let SubMenuItems;
|
||||
if (this.props.elements) {
|
||||
SubMenuItems = this.props.elements.map((element) => {
|
||||
return (
|
||||
<Menu.ItemSubMenu
|
||||
key={element.id}
|
||||
id={element.id}
|
||||
text={element.text}
|
||||
subMenu={element.subMenu}
|
||||
action={element.action}
|
||||
filter={element.filter}
|
||||
root={false}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const subMenuItems = useMemo(() => {
|
||||
if (!elements) {
|
||||
return undefined;
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
dialogClassName={'SubMenuModal a11y__modal mobile-sub-menu'}
|
||||
show={this.state.show}
|
||||
onHide={this.onHide}
|
||||
onExited={this.props.onExited}
|
||||
enforceFocus={false}
|
||||
id='submenuModal'
|
||||
role='dialog'
|
||||
>
|
||||
<Modal.Body
|
||||
onClick={this.onHide}
|
||||
>
|
||||
<MenuWrapper>
|
||||
<Menu
|
||||
openLeft={true}
|
||||
ariaLabel={Utils.localizeMessage('post_info.submenu.mobile', 'mobile submenu').toLowerCase()}
|
||||
>
|
||||
{SubMenuItems}
|
||||
</Menu>
|
||||
<div/>
|
||||
</MenuWrapper>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
return elements.map(
|
||||
(element) => (
|
||||
<Menu.ItemSubMenu
|
||||
key={element.id}
|
||||
id={element.id}
|
||||
text={element.text}
|
||||
subMenu={element.subMenu}
|
||||
action={element.action}
|
||||
filter={element.filter}
|
||||
root={false}
|
||||
/>),
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [elements]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
dialogClassName={'SubMenuModal a11y__modal mobile-sub-menu'}
|
||||
show={show}
|
||||
onHide={onHide}
|
||||
onExited={onExited}
|
||||
enforceFocus={false}
|
||||
id='submenuModal'
|
||||
role='dialog'
|
||||
>
|
||||
<Modal.Body
|
||||
data-testid={'SubMenuModalBody'}
|
||||
onClick={onHide}
|
||||
>
|
||||
<MenuWrapper>
|
||||
<Menu
|
||||
openLeft={true}
|
||||
ariaLabel={intl.formatMessage({id: 'post_info.submenu.mobile', defaultMessage: 'mobile submenu'})}
|
||||
>
|
||||
{subMenuItems}
|
||||
</Menu>
|
||||
<div/>
|
||||
</MenuWrapper>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SubMenuModal);
|
||||
|
||||
Ссылка в новой задаче
Block a user