Files
kandev/apps/web/components/task/task-reset-env-confirm-dialog.tsx
T

111 lines
3.8 KiB
TypeScript

"use client";
import { useState } from "react";
import { IconLoader } from "@tabler/icons-react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@kandev/ui/alert-dialog";
import { Checkbox } from "@kandev/ui/checkbox";
import { useTranslation } from "react-i18next";
export type TaskResetEnvConfirmDialogProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
hasWorktreePath: boolean;
isResetting?: boolean;
onConfirm: (opts: { pushBranch: boolean }) => void;
};
export function TaskResetEnvConfirmDialog({
open,
onOpenChange,
hasWorktreePath,
isResetting,
onConfirm,
}: TaskResetEnvConfirmDialogProps) {
const { t } = useTranslation();
const [acknowledged, setAcknowledged] = useState(false);
const [pushBranch, setPushBranch] = useState(false);
const handleOpenChange = (next: boolean) => {
if (!next) {
// reset local state when closing
setAcknowledged(false);
setPushBranch(false);
}
onOpenChange(next);
};
return (
<AlertDialog open={open} onOpenChange={handleOpenChange}>
<AlertDialogContent onClick={(e) => e.stopPropagation()}>
<AlertDialogHeader>
<AlertDialogTitle>{t("task:resetEnvironment")}</AlertDialogTitle>
<AlertDialogDescription asChild>
<div className="min-w-0 space-y-2 text-left">
<p>{t("task:thisTearsDownTheCurrentContainer")}</p>
<p className="text-destructive">{t("task:anyUncommittedOrUnpushedChangesIn")}</p>
</div>
</AlertDialogDescription>
</AlertDialogHeader>
<div className="space-y-3 py-1">
{hasWorktreePath && (
<label className="flex items-start gap-2 text-sm cursor-pointer">
<Checkbox
checked={pushBranch}
onCheckedChange={(v) => setPushBranch(v === true)}
disabled={isResetting}
/>
<span>
{t("task:pushCurrentBranchBeforeResetting")}
<span className="block text-xs text-muted-foreground">
{t("task:helpsPreserveCommittedWorkUncommittedChanges")}
</span>
</span>
</label>
)}
<label className="flex items-start gap-2 text-sm cursor-pointer">
<Checkbox
checked={acknowledged}
onCheckedChange={(v) => setAcknowledged(v === true)}
disabled={isResetting}
/>
<span>{t("task:iUnderstandAnyUncommittedChangesWill")}</span>
</label>
</div>
<AlertDialogFooter>
<AlertDialogCancel className="cursor-pointer">{t("common:cancel")}</AlertDialogCancel>
<AlertDialogAction
disabled={isResetting || !acknowledged}
className="cursor-pointer bg-destructive text-destructive-foreground hover:bg-destructive/90"
data-testid="reset-env-confirm"
onClick={(e) => {
// Radix's AlertDialogAction auto-closes the dialog on click,
// which would dismiss it before the async reset completes — the
// user never sees the loading spinner, and the dialog closes
// even on failure. Block the auto-close so the parent owns the
// close decision via `onOpenChange` after the promise settles.
e.preventDefault();
if (isResetting || !acknowledged) return;
onConfirm({ pushBranch });
}}
>
{isResetting ? <IconLoader className="mr-2 h-4 w-4 animate-spin" /> : null}
{t("task:resetEnvironment2")}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}