-
Notifications
You must be signed in to change notification settings - Fork 3
/
ConfirmProvider.tsx
134 lines (120 loc) · 3.41 KB
/
ConfirmProvider.tsx
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
import {
ConfirmProviderProps,
ConfirmState,
ConfirmationDialogOptions
} from "./ConfirmProvider.types";
import React, { Fragment, useCallback, useState } from "react";
import ConfirmContext from "./ConfirmContext";
import ConfirmationDialog from "./ConfirmationDialog";
import { Theme } from "@mui/material/styles";
// define default props
const DEFAULT_OPTIONS: ConfirmationDialogOptions = {
cancellationText: "Cancel",
confirmationText: "Ok",
content: null,
description: "Test Description",
title: "Are you sure?"
};
const buildOptions = (
defaultOptions: Partial<ConfirmationDialogOptions>,
options: Partial<ConfirmationDialogOptions>
) => {
const confirmationButtonProps = {
...(defaultOptions.confirmationButtonProps ||
DEFAULT_OPTIONS.confirmationButtonProps),
...(options.confirmationButtonProps || {})
};
return {
...DEFAULT_OPTIONS,
...defaultOptions,
...options,
confirmationButtonProps
};
};
let confirmGlobal: (
options: Partial<ConfirmationDialogOptions>
) => Promise<void>;
const ConfirmProvider: React.FC<ConfirmProviderProps> = ({
children,
defaultOptions = {
cancellationText: "No",
confirmationButtonProps: {
sx: {
bgcolor: (theme: Theme) =>
theme.palette.mode === "light" ? "" : "#87a5d2"
},
variant: "contained"
},
confirmationText: "Yes",
description: "Would you like to continue?",
title: "Dialog Title"
}
}) => {
// state that we clear on close (to avoid dangling references to resolve and
// reject). If this is null, the dialog is closed.
const [state, setState] = useState<ConfirmState | null>(null);
// options for rendering the dialog, which aren't reset on close so that we
// keep rendering the same modal during close animation
const [options, setOptions] = useState({});
const [key, setKey] = useState(0);
const confirmBase = useCallback(
(
parentId: string,
options: Partial<ConfirmationDialogOptions> = {}
): Promise<void> => {
return new Promise<void>((resolve, reject) => {
setKey(key => key + 1);
setOptions(options);
setState({ parentId, reject, resolve: () => resolve() }); // Ensure resolve is void
});
},
[]
);
const closeOnParentUnmount = useCallback((parentId: string) => {
setState(state => {
if (state && state.parentId === parentId) {
return null;
} else {
return state;
}
});
}, []);
const handleClose = useCallback(() => {
setState(null);
}, []);
const handleCancel = useCallback(() => {
setState(state => {
state && state.reject();
return null;
});
}, []);
const handleConfirm = useCallback(() => {
setState(state => {
state && state.resolve();
return null;
});
}, []);
confirmGlobal = useCallback(
(options?: Partial<ConfirmationDialogOptions>) => {
return confirmBase("global", options);
},
[confirmBase]
);
return (
<Fragment>
<ConfirmContext.Provider value={{ closeOnParentUnmount, confirmBase }}>
{children}
</ConfirmContext.Provider>
<ConfirmationDialog
key={key}
open={state !== null}
options={buildOptions(defaultOptions, options)}
onClose={handleClose}
onCancel={handleCancel}
onConfirm={handleConfirm}
/>
</Fragment>
);
};
export default ConfirmProvider;
export { confirmGlobal as confirm };