feat: admin dashboard
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
type ConfirmOpts = {
|
||||
title: string;
|
||||
message?: string;
|
||||
confirmLabel?: string;
|
||||
destructive?: boolean;
|
||||
};
|
||||
|
||||
type ConfirmFn = (opts: ConfirmOpts) => Promise<boolean>;
|
||||
|
||||
const ConfirmContext = createContext<ConfirmFn | null>(null);
|
||||
|
||||
/** Imperative confirm — `if (await confirm({...})) { … }`. Renders a styled
|
||||
* modal instead of the browser's window.confirm. Provided by ConfirmProvider. */
|
||||
export function useConfirm(): ConfirmFn {
|
||||
const fn = useContext(ConfirmContext);
|
||||
if (!fn) throw new Error("useConfirm must be used within a ConfirmProvider");
|
||||
return fn;
|
||||
}
|
||||
|
||||
export function ConfirmProvider({ children }: { children: ReactNode }) {
|
||||
const [pending, setPending] = useState<{
|
||||
opts: ConfirmOpts;
|
||||
resolve: (v: boolean) => void;
|
||||
} | null>(null);
|
||||
|
||||
const confirm = useCallback<ConfirmFn>(
|
||||
(opts) => new Promise<boolean>((resolve) => setPending({ opts, resolve })),
|
||||
[],
|
||||
);
|
||||
|
||||
function settle(value: boolean) {
|
||||
pending?.resolve(value);
|
||||
setPending(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfirmContext.Provider value={confirm}>
|
||||
{children}
|
||||
<Modal
|
||||
open={!!pending}
|
||||
onClose={() => settle(false)}
|
||||
title={pending?.opts.title ?? ""}
|
||||
>
|
||||
{pending ? (
|
||||
<div className="space-y-5">
|
||||
{pending.opts.message ? (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{pending.opts.message}
|
||||
</p>
|
||||
) : null}
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="ghost" onClick={() => settle(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant={pending.opts.destructive ? "destructive" : "primary"}
|
||||
onClick={() => settle(true)}
|
||||
>
|
||||
{pending.opts.confirmLabel ?? "Confirm"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</Modal>
|
||||
</ConfirmContext.Provider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user