-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDialogProvider.jsx
155 lines (138 loc) · 5.2 KB
/
DialogProvider.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import React, { useState } from 'react';
import DialogContext from './DialogContext';
import Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import Button from "@mui/material/Button";
import { ErrorBoundary } from 'react-error-boundary';
import MuiAlert from '@mui/material/Alert';
function Title({ label }) {
return <DialogTitle>{label || "Title's default label"}</DialogTitle>;
};
function Description({ message }) {
return (
<DialogContent sx={{ p: 3 }} >
<DialogContentText sx={{ whiteSpace: "pre-line" }}>
{message || "Description's default message"}
</DialogContentText>
</DialogContent>
);
};
function Content({ children }) {
return (
<ErrorBoundary
fallback={(err) =>
<MuiAlert severity='error'>Erro ao apresentar conteúdo do dialogo: {err.message}</MuiAlert>
}
>
{children}
</ErrorBoundary>
);
};
function Action({ children }) {
return (
<DialogActions sx={{ mr: 3, mb: 1 }}>
{children || <MuiAlert severity='warning'>Nenhuma ação disponível.</MuiAlert>}
</DialogActions>
);
};
function NestedDialog({ title, content, actions, options, index, next }) {
const { globalDialogProps } = React.useContext(DialogContext);
return (
<Dialog
key={`${index || "last"}-${title || "custom"}`}
{...options}
{...({ ...globalDialogProps, ...options?.dialogProps })}
open
onClose={options?.onClose}
>
{ next && <NestedDialog {...next} /> }
{title}
{content}
{actions}
</Dialog>
)
};
export default function DialogProvider({ globalDialogProps, children }) {
const { globalDialogProps: currentGlobalDialogProps } = React.useContext(DialogContext);
const [dialogs, setDialogsStack] = useState([]);
const handleClose = React.useCallback(() => setDialogsStack((prev) => { const n = [...prev]; n.pop(); return n; }), [setDialogsStack]);
const setDialog = React.useCallback((title, content, actions, options = {}) =>
setDialogsStack((prev) => { const n = [...prev, { title, content, actions, options }]; return n }), [setDialogsStack]);
/**
* Faz uma seleção genérica dos parâmetros necessários para os diferentes tipos de Dialogo e passa para o método `setDialog` que vai empilhar.
* @param {string} title
* @param {string} message
* @param {array} actions
* @param {object} options
* @param {boolean} reject
* @returns
*/
const setGeneric = React.useCallback((title, message, actions, options, reject) => new Promise((res, rej) =>
setDialog(
title ? <Title label={title} /> : undefined,
<Description message={message} />,
<Action>
{
[actions].flat().map((action, i) =>
<Button
key={i}
onClick={() =>
handleClose() |
res(action?.value === undefined ? action?.label : action?.value)
}
{...options?.buttonProps}
>
{action?.label}
</Button>
)
}
</Action>,
{ onClose: () => handleClose() | reject ? rej("dialog closed") : res(), ...options }
)), [setDialog]);
const setAlert = React.useCallback((message, options) =>
setGeneric(
options?.title,
message,
{ label: options?.label || "Confirmar" },
options
), [setGeneric]);
const setConfirm = React.useCallback((message, title, options) =>
setGeneric(
title,
message,
[
{ label: options?.confirmLabel || "Confirmar", value: true },
{ label: options?.cancelLabel || "Cancelar", value: false }
],
options,
true
), [setGeneric]);
const setCustom = React.useCallback((content, options) =>
content ? setDialog(
null,
<Content>{content}</Content>,
null,
options
) : handleClose(), [handleClose, setDialog]);
const shared = React.useMemo(() => ({
globalDialogProps: { ...currentGlobalDialogProps, ...globalDialogProps },
setDialog: setCustom,
setConfirm,
setAlert,
handleClose
}), [currentGlobalDialogProps, globalDialogProps, setCustom, setConfirm, setAlert, handleClose]);
return (
<DialogContext.Provider value={shared}>
{
children
}
{
dialogs?.length > 0 &&
<NestedDialog { ...dialogs.reduceRight((a,b,c) => ({ ...b, next: { ...a, index: c } })) } />
}
</DialogContext.Provider>
);
};