mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
Adjusted
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// ─── components/ArchiveDialog.jsx ────────────────────────────────────────────
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
/**
|
||||
* Generic archive dialog — works for any entity (users, groups, etc.)
|
||||
*
|
||||
* Single: <ArchiveDialog entity={rowObject} getName={(r) => r.name} ... />
|
||||
* Bulk: <ArchiveDialog ids={[1, 2, 3]} entityLabel="Group" ... />
|
||||
*
|
||||
* @param {Function} onArchive (id | { ids }) => Promise — called with single id or { ids }
|
||||
* @param {Function} getName (entity) => string — how to display the entity name
|
||||
* @param {string} entityLabel e.g. "User", "Group"
|
||||
* @param {boolean} loading from whichever context the parent uses
|
||||
*/
|
||||
export function ArchiveDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
entity,
|
||||
ids,
|
||||
entityLabel = "Item",
|
||||
getName,
|
||||
onArchive,
|
||||
loading,
|
||||
onSuccess,
|
||||
}) {
|
||||
const isBulk = Array.isArray(ids) && ids.length > 0;
|
||||
const count = isBulk ? ids.length : 1;
|
||||
|
||||
const displayName = isBulk
|
||||
? `${count} selected ${entityLabel.toLowerCase()}${count !== 1 ? "s" : ""}`
|
||||
: (getName?.(entity) ?? entity?.name ?? entity?.email ?? "this item");
|
||||
|
||||
const handleArchive = async () => {
|
||||
const res = isBulk
|
||||
? await onArchive({ ids })
|
||||
: await onArchive(entity);
|
||||
|
||||
if (res) {
|
||||
onOpenChange(false);
|
||||
onSuccess?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
Archive {isBulk ? `${count} ${entityLabel}${count !== 1 ? "s" : ""}` : entityLabel}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to archive{" "}
|
||||
<span className="font-medium text-foreground">{displayName}</span>?{" "}
|
||||
{isBulk
|
||||
? "They will be deactivated and lose access immediately."
|
||||
: "This will deactivate the record immediately."}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel disabled={loading}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={handleArchive}
|
||||
disabled={loading}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{loading && <Spinner className="size-4 mr-2" />}
|
||||
Archive{isBulk ? ` ${count} ${entityLabel}${count !== 1 ? "s" : ""}` : ""}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// ─── components/RestoreDialog.jsx ────────────────────────────────────────────
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
/**
|
||||
* Generic restore dialog — works for any entity (users, groups, etc.)
|
||||
*
|
||||
* Single: <RestoreDialog entity={rowObject} getName={(r) => r.name} ... />
|
||||
* Bulk: <RestoreDialog ids={[1, 2, 3]} entityLabel="Group" ... />
|
||||
*
|
||||
* @param {Function} onRestore (id | { ids }) => Promise — called with single id or { ids }
|
||||
* @param {Function} getName (entity) => string — how to display the entity name
|
||||
* @param {string} entityLabel e.g. "User", "Group"
|
||||
* @param {boolean} loading from whichever context the parent uses
|
||||
*/
|
||||
export function RestoreDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
entity,
|
||||
ids,
|
||||
entityLabel = "Item",
|
||||
getName,
|
||||
onRestore,
|
||||
loading,
|
||||
onSuccess,
|
||||
}) {
|
||||
const isBulk = Array.isArray(ids) && ids.length > 0;
|
||||
const count = isBulk ? ids.length : 1;
|
||||
|
||||
const displayName = isBulk
|
||||
? `${count} selected ${entityLabel.toLowerCase()}${count !== 1 ? "s" : ""}`
|
||||
: (getName?.(entity) ?? entity?.name ?? entity?.email ?? "this item");
|
||||
|
||||
const handleRestore = async () => {
|
||||
const res = isBulk
|
||||
? await onRestore({ ids })
|
||||
: await onRestore(entity);
|
||||
|
||||
if (res) {
|
||||
onOpenChange(false);
|
||||
onSuccess?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
Restore {isBulk ? `${count} ${entityLabel}${count !== 1 ? "s" : ""}` : entityLabel}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to restore{" "}
|
||||
<span className="font-medium text-foreground">{displayName}</span>?{" "}
|
||||
{isBulk
|
||||
? "They will regain access to their accounts immediately."
|
||||
: "This will reactivate the record immediately."}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel disabled={loading}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={handleRestore}
|
||||
disabled={loading}
|
||||
className="bg-emerald-600 text-white hover:bg-emerald-700"
|
||||
>
|
||||
{loading && <Spinner className="size-4 mr-2" />}
|
||||
Restore{isBulk ? ` ${count} ${entityLabel}${count !== 1 ? "s" : ""}` : ""}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user