Refactor modal provider to better use its own state

This commit is contained in:
Igor 2019-11-14 14:56:01 -03:00
parent bdb9af5c4b
commit fe687cd2f9
3 changed files with 74 additions and 58 deletions

View File

@ -8,6 +8,8 @@
* UI Modal
*
* @typedef {Object} ModalProps
* @property {string} [header=null] -
* @property {string} [footer=null] -
* @property {string} [backdrop=false] -
* @property {string} [keyboard=false] -
* @property {number} [show=true] -
@ -36,10 +38,12 @@ function createUIModalService() {
* Show a new UI modal;
*
* @param {Modal} component React component
* @param {ModalProps} props { backdrop, keyboard, show, closeButton, title, customClassName }
* @param {ModalProps} props { header, footer, backdrop, keyboard, show, closeButton, title, customClassName }
*/
function show(component, props) {
const {
header = null,
footer = null,
backdrop = false,
keyboard = false,
show = true,
@ -48,6 +52,8 @@ function show(component, props) {
customClassName = null,
} = props;
return uiModalServiceImplementation._show(component, {
header,
footer,
backdrop,
keyboard,
show,

View File

@ -2,20 +2,22 @@ import React, {
useState,
createContext,
useContext,
useCallback,
useEffect,
useCallback,
} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
const ModalContext = createContext(null);
const { Provider, Consumer } = ModalContext;
const { Provider } = ModalContext;
export const useModal = () => useContext(ModalContext);
const ModalProvider = ({ children, modal: Modal, service }) => {
const DEFAULT_OPTIONS = {
component: null /* The component instance inside the modal. */,
header: null /* The content inside the modal header. */,
footer: null /* The content inside the modal footer. */,
backdrop: false /* Should the modal render a backdrop overlay. */,
keyboard: false /* Modal is dismissible via the esc key. */,
show: true /* Make the Modal visible or hidden. */,
@ -42,8 +44,10 @@ const ModalProvider = ({ children, modal: Modal, service }) => {
*
* @returns void
*/
const show = useCallback((component, props = {}) =>
setOptions(Object.assign({}, options, props, { component }))
const show = useCallback(
(component, props = {}) =>
setOptions(Object.assign({}, options, props, { component })),
[options]
);
/**
@ -51,30 +55,30 @@ const ModalProvider = ({ children, modal: Modal, service }) => {
*
* @returns void
*/
const hide = useCallback(() => setOptions(DEFAULT_OPTIONS));
const hide = useCallback(() => setOptions(DEFAULT_OPTIONS), [
DEFAULT_OPTIONS,
]);
return (
<Provider value={{ ...options, show, hide }}>
<Consumer>
{props => {
const { component, footer, header, customClassName } = props;
return component ? (
<Modal
className={classNames(customClassName, component.className)}
backdrop={options.backdrop}
keyboard={options.keyboard}
show={options.show}
title={options.title}
closeButton={options.closeButton}
onHide={hide}
footer={footer}
header={header}
>
{component}
</Modal>
) : null;
}}
</Consumer>
<Provider value={{ show, hide }}>
{options.component && (
<Modal
className={classNames(
options.customClassName,
options.component.className
)}
backdrop={options.backdrop}
keyboard={options.keyboard}
show={options.show}
title={options.title}
closeButton={options.closeButton}
onHide={hide}
footer={options.footer}
header={options.header}
>
{options.component}
</Modal>
)}
{children}
</Provider>
);

View File

@ -38,45 +38,51 @@ const SnackbarProvider = ({ children, service }) => {
}
}, [service, hide, show]);
const show = useCallback(options => {
if (!options || (!options.title && !options.message)) {
console.warn(
'Snackbar cannot be rendered without required parameters: title | message'
);
const show = useCallback(
options => {
if (!options || (!options.title && !options.message)) {
console.warn(
'Snackbar cannot be rendered without required parameters: title | message'
);
return null;
}
return null;
}
const newItem = {
...DEFAULT_OPTIONS,
...options,
id: count,
visible: true,
};
const newItem = {
...DEFAULT_OPTIONS,
...options,
id: count,
visible: true,
};
setSnackbarItems(state => [...state, newItem]);
setCount(count + 1);
});
setSnackbarItems(state => [...state, newItem]);
setCount(count + 1);
},
[count, DEFAULT_OPTIONS]
);
const hide = useCallback(id => {
const hideItem = items => {
const newItems = items.map(item => {
if (item.id === id) {
item.visible = false;
}
const hide = useCallback(
id => {
const hideItem = items => {
const newItems = items.map(item => {
if (item.id === id) {
item.visible = false;
}
return item;
});
return item;
});
return newItems;
};
return newItems;
};
setSnackbarItems(state => hideItem(state));
setSnackbarItems(state => hideItem(state));
setTimeout(() => {
setSnackbarItems(state => [...state.filter(item => item.id !== id)]);
}, 1000);
});
setTimeout(() => {
setSnackbarItems(state => [...state.filter(item => item.id !== id)]);
}, 1000);
},
[setSnackbarItems]
);
const hideAll = () => {
// reset count