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

View File

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

View File

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