68 lines
1.7 KiB
TypeScript
68 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { ConfirmActionDialog } from "@/components/admin/confirm-action-dialog";
|
|
|
|
export type ConfirmActionRequest = {
|
|
title: string;
|
|
description: string;
|
|
confirmLabel?: string;
|
|
cancelLabel?: string;
|
|
confirmVariant?: "default" | "destructive";
|
|
onConfirm: () => void | Promise<void>;
|
|
};
|
|
|
|
export function useConfirmAction() {
|
|
const { t } = useTranslation("common");
|
|
const [pending, setPending] = useState<ConfirmActionRequest | null>(null);
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const request = useCallback((req: ConfirmActionRequest) => {
|
|
setPending(req);
|
|
}, []);
|
|
|
|
const dismiss = useCallback(() => {
|
|
if (!busy) {
|
|
setPending(null);
|
|
}
|
|
}, [busy]);
|
|
|
|
const confirm = useCallback(async () => {
|
|
if (!pending || busy) {
|
|
return;
|
|
}
|
|
setBusy(true);
|
|
try {
|
|
await pending.onConfirm();
|
|
setPending(null);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}, [pending, busy]);
|
|
|
|
const ConfirmDialog = useCallback(
|
|
() => (
|
|
<ConfirmActionDialog
|
|
open={pending !== null}
|
|
onOpenChange={(open) => {
|
|
if (!open) {
|
|
dismiss();
|
|
}
|
|
}}
|
|
title={pending?.title ?? ""}
|
|
description={pending?.description ?? ""}
|
|
confirmLabel={pending?.confirmLabel ?? t("confirm.confirm")}
|
|
cancelLabel={pending?.cancelLabel ?? t("confirm.cancel")}
|
|
confirmVariant={pending?.confirmVariant ?? "destructive"}
|
|
busy={busy}
|
|
onConfirm={() => void confirm()}
|
|
/>
|
|
),
|
|
[pending, busy, dismiss, confirm, t],
|
|
);
|
|
|
|
return { request, dismiss, busy, ConfirmDialog };
|
|
}
|