forked from Nova-reward/Nova-Rewards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModalContext.js
More file actions
72 lines (61 loc) · 2.06 KB
/
Copy pathModalContext.js
File metadata and controls
72 lines (61 loc) · 2.06 KB
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
'use client';
import { createContext, useContext, useState, useCallback } from 'react';
import AlertDialog from '../components/modal/AlertDialog';
import ConfirmDialog from '../components/modal/ConfirmDialog';
/**
* @typedef {{ type: 'alert'|'confirm', props: object, resolve: (v: any) => void }} ModalEntry
*/
const ModalContext = createContext(null);
/**
* Provides programmatic modal access via `useModal()`.
* Mount once in `_app.js` above all other providers.
*/
export function ModalProvider({ children }) {
const [entry, setEntry] = useState(/** @type {ModalEntry|null} */ (null));
const close = useCallback((value) => {
entry?.resolve(value);
setEntry(null);
}, [entry]);
/**
* Show an alert dialog. Returns a Promise that resolves when dismissed.
* @param {{ title: string, message: React.ReactNode, variant?: string, confirmText?: string }} opts
*/
const alert = useCallback((opts) =>
new Promise((resolve) => setEntry({ type: 'alert', props: opts, resolve })),
[]);
/**
* Show a confirm dialog. Returns a Promise<boolean> (true = confirmed).
* @param {{ title: string, message: React.ReactNode, confirmText?: string, destructive?: boolean }} opts
*/
const confirm = useCallback((opts) =>
new Promise((resolve) => setEntry({ type: 'confirm', props: opts, resolve })),
[]);
return (
<ModalContext.Provider value={{ alert, confirm }}>
{children}
{entry?.type === 'alert' && (
<AlertDialog
isOpen
onClose={() => close(undefined)}
{...entry.props}
/>
)}
{entry?.type === 'confirm' && (
<ConfirmDialog
isOpen
onClose={() => close(false)}
onConfirm={() => close(true)}
{...entry.props}
/>
)}
</ModalContext.Provider>
);
}
/**
* @returns {{ alert: (opts: object) => Promise<void>, confirm: (opts: object) => Promise<boolean> }}
*/
export function useModal() {
const ctx = useContext(ModalContext);
if (!ctx) throw new Error('useModal must be used within ModalProvider');
return ctx;
}