Skip to content

Commit 83d020f

Browse files
committed
Add the ability to launch multiple modals with useModal hook
1 parent 2222e76 commit 83d020f

File tree

2 files changed

+79
-4
lines changed

2 files changed

+79
-4
lines changed

Diff for: dynamic-demo-plugin/src/components/Modals/ModalPage.tsx

+44
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,36 @@ export const TestModal: React.FC<{ closeModal: () => void }> = (props) => {
3232
);
3333
};
3434

35+
const TEST_ID_1 = 'TEST_ID_1';
36+
const TestComponentWithID1 = ({ closeModal }) => (
37+
<div style={{
38+
backgroundColor: 'gray',
39+
position: 'absolute',
40+
right: '5rem',
41+
top: '5rem',
42+
width: '20rem',
43+
zIndex: 100,
44+
}}>
45+
<p>Test Modal with ID "{TEST_ID_1}"</p>
46+
<Button onClick={closeModal}>Close</Button>
47+
</div>
48+
);
49+
50+
const TEST_ID_2 = 'TEST_ID_2';
51+
const TestComponentWithID2 = ({ closeModal, ...rest }) => (
52+
<div style={{
53+
backgroundColor: 'gray',
54+
bottom: '5rem',
55+
position: 'absolute',
56+
right: '5rem',
57+
width: '20rem',
58+
zIndex: 100,
59+
}}>
60+
<p>Test Modal with ID "{TEST_ID_2}" and testProp "{rest.testProp}"</p>
61+
<Button onClick={closeModal}>Close</Button>
62+
</div>
63+
);
64+
3565
const LoadingComponent: React.FC = () => {
3666
const { t } = useTranslation();
3767

@@ -70,6 +100,14 @@ export const TestModalPage: React.FC<{ closeComponent: any }> = () => {
70100
};
71101

72102
const onClick = React.useCallback(() => launchModal(TestComponent, {}), [launchModal]);
103+
const onClickWithID1 = React.useCallback(
104+
() => launchModal(TestComponentWithID1, {}, TEST_ID_1),
105+
[launchModal],
106+
);
107+
const onClickWithID2 = React.useCallback(
108+
() => launchModal(TestComponentWithID2, { testProp: 'abc' }, TEST_ID_2),
109+
[launchModal],
110+
);
73111
const onAsyncClick = React.useCallback(() => launchModal(AsyncTestComponent, {}), [launchModal]);
74112

75113
return (
@@ -81,6 +119,12 @@ export const TestModalPage: React.FC<{ closeComponent: any }> = () => {
81119
className="demo-modal__page"
82120
>
83121
<Button onClick={onClick}>{t('plugin__console-demo-plugin~Launch Modal')}</Button>
122+
<Button onClick={onClickWithID1}>
123+
{t('plugin__console-demo-plugin~Launch Modal with ID 1')}
124+
</Button>
125+
<Button onClick={onClickWithID2}>
126+
{t('plugin__console-demo-plugin~Launch Modal with ID 2')}
127+
</Button>
84128
<Button onClick={onAsyncClick}>
85129
{t('plugin__console-demo-plugin~Launch Modal Asynchronously')}
86130
</Button>

Diff for: frontend/packages/console-dynamic-plugin-sdk/src/app/modal-support/ModalProvider.tsx

+35-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import * as React from 'react';
2+
import * as _ from 'lodash';
23

34
type CloseModal = () => void;
45

56
type UnknownProps = { [key: string]: unknown };
67
export type ModalComponent<P = UnknownProps> = React.FC<P & { closeModal: CloseModal }>;
78

8-
export type LaunchModal = <P = UnknownProps>(component: ModalComponent<P>, extraProps: P) => void;
9+
export type LaunchModal = <P = UnknownProps>(
10+
component: ModalComponent<P>,
11+
extraProps: P,
12+
id?: string,
13+
) => void;
914

1015
type ModalContextValue = {
1116
launchModal: LaunchModal;
@@ -17,24 +22,50 @@ export const ModalContext = React.createContext<ModalContextValue>({
1722
closeModal: () => {},
1823
});
1924

25+
type ComponentMap = {
26+
[key: string]: {
27+
Component: ModalComponent<UnknownProps>;
28+
props: { [key: string]: any };
29+
};
30+
};
31+
2032
export const ModalProvider: React.FC = ({ children }) => {
2133
const [isOpen, setOpen] = React.useState(false);
2234
const [Component, setComponent] = React.useState<ModalComponent>();
2335
const [componentProps, setComponentProps] = React.useState({});
36+
const [componentsMap, setComponentsMap] = React.useState<ComponentMap>({});
2437

2538
const launchModal = React.useCallback<LaunchModal>(
26-
(component, compProps) => {
27-
setComponent(() => component);
39+
(component, compProps, id = undefined) => {
40+
if (id) {
41+
setComponentsMap((components) => ({
42+
...components,
43+
[id]: { Component: component, props: compProps },
44+
}));
45+
} else {
46+
setComponent(() => component);
47+
}
2848
setComponentProps(compProps);
2949
setOpen(true);
3050
},
3151
[setOpen, setComponent, setComponentProps],
3252
);
33-
const closeModal = React.useCallback<CloseModal>(() => setOpen(false), [setOpen]);
53+
54+
const closeModal = React.useCallback<CloseModal>(() => {
55+
setOpen(false);
56+
setComponent(undefined);
57+
}, [setOpen]);
58+
59+
const closeModalWithID = React.useCallback<(id: string) => void>((id) => {
60+
setComponentsMap((components) => _.omit(components, id));
61+
}, []);
3462

3563
return (
3664
<ModalContext.Provider value={{ launchModal, closeModal }}>
3765
{isOpen && !!Component && <Component {...componentProps} closeModal={closeModal} />}
66+
{_.map(componentsMap, (c, id) => (
67+
<c.Component {...c.props} key={id} closeModal={() => closeModalWithID(id)} />
68+
))}
3869
{children}
3970
</ModalContext.Provider>
4071
);

0 commit comments

Comments
 (0)