[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
|
<ModalBody
|
||||||
bsClass="modal-body"
|
bsClass="modal-body"
|
||||||
componentClass="div"
|
componentClass="div"
|
||||||
|
data-testid="SubMenuModalBody"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<MenuWrapper
|
<MenuWrapper
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
// 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 {fireEvent, waitForElementToBeRemoved} from '@testing-library/react';
|
||||||
import {shallow} from 'enzyme';
|
import {shallow} from 'enzyme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
|
|
||||||
|
import {withIntl} from 'tests/helpers/intl-test-helper';
|
||||||
import {render, screen, userEvent} from 'tests/react_testing_utils';
|
import {render, screen, userEvent} from 'tests/react_testing_utils';
|
||||||
|
|
||||||
import SubMenuModal from './submenu_modal';
|
import SubMenuModal from './submenu_modal';
|
||||||
@@ -55,14 +57,20 @@ describe('components/submenu_modal', () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should match state when onHide is called', () => {
|
test('should hide on modal body click', async () => {
|
||||||
const wrapper = shallow<SubMenuModal>(
|
const view = render(withIntl(
|
||||||
<SubMenuModal {...baseProps}/>,
|
<SubMenuModal {...baseProps}/>,
|
||||||
);
|
));
|
||||||
|
|
||||||
wrapper.setState({show: true});
|
screen.getByText('Text A');
|
||||||
wrapper.instance().onHide();
|
screen.getByText('Text B');
|
||||||
expect(wrapper.state('show')).toEqual(false);
|
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 () => {
|
test('should have called click function when button is clicked', async () => {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// 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, useMemo, useState} from 'react';
|
||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
import * as Utils from 'utils/utils';
|
|
||||||
|
|
||||||
import Menu from '../../menu';
|
import Menu from '../../menu';
|
||||||
import type SubMenuItem from '../../menu_items/submenu_item';
|
import type SubMenuItem from '../../menu_items/submenu_item';
|
||||||
@@ -17,63 +16,61 @@ type Props = {
|
|||||||
onExited: () => void;
|
onExited: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
const SubMenuModal = ({
|
||||||
show: boolean;
|
elements,
|
||||||
}
|
onExited,
|
||||||
|
}: Props) => {
|
||||||
|
const [show, setShow] = useState(true);
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
export default class SubMenuModal extends React.PureComponent<Props, State> {
|
const onHide = useCallback(() => {
|
||||||
public constructor(props: Props) {
|
setShow(false);
|
||||||
super(props);
|
}, []);
|
||||||
this.state = {
|
|
||||||
show: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public onHide = () => { //public because it is used on tests
|
const subMenuItems = useMemo(() => {
|
||||||
this.setState({show: false});
|
if (!elements) {
|
||||||
};
|
return undefined;
|
||||||
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return (
|
return elements.map(
|
||||||
<Modal
|
(element) => (
|
||||||
dialogClassName={'SubMenuModal a11y__modal mobile-sub-menu'}
|
<Menu.ItemSubMenu
|
||||||
show={this.state.show}
|
key={element.id}
|
||||||
onHide={this.onHide}
|
id={element.id}
|
||||||
onExited={this.props.onExited}
|
text={element.text}
|
||||||
enforceFocus={false}
|
subMenu={element.subMenu}
|
||||||
id='submenuModal'
|
action={element.action}
|
||||||
role='dialog'
|
filter={element.filter}
|
||||||
>
|
root={false}
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
}
|
}, [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