mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
fix(coach): delete-with-undo replaces the arm-forever confirm
The history rail + /coach/conversations armed a row on the first tap and only disarmed on a successful delete — no timeout, no outside-click reset — so a row armed minutes earlier deleted on a later stray tap, and there was no way back once it fired. Replace it with the same delayed-commit delete-with-undo the Documents surface already uses: one tap hides the row and schedules the real DELETE a few seconds out; the toast's Undo cancels it. Centralised in useDeleteCoachConversationWithUndo so both surfaces, which carried byte-identical arm/confirm logic, share one implementation.
This commit is contained in:
1 parent
9531bbdcec
commit
8c385b9ac2
9 files changed
+136
-59
No files matched your search
@@ -10,6 +10,7 @@ import {
|
||||
Target,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -18,7 +19,7 @@ import { QueryErrorCard } from "@/components/ui/query-error-card";
|
||||
import { COACH_SCROLLBAR } from "@/components/insights/coach-panel/message-thread";
|
||||
import {
|
||||
useCoachConversations,
|
||||
useDeleteCoachConversation,
|
||||
useDeleteCoachConversationWithUndo,
|
||||
} from "@/components/insights/coach-panel/use-coach";
|
||||
import type { CoachConversationDTO } from "@/lib/ai/coach/types";
|
||||
import { useCoachLaunch } from "@/lib/insights/coach-launch-context";
|
||||
@@ -102,16 +103,17 @@ function CoachConversationsBody() {
|
||||
const router = useRouter();
|
||||
const { conversations, isLoading, isError, refetch } =
|
||||
useCoachConversations();
|
||||
const deleteMutation = useDeleteCoachConversation();
|
||||
const { pendingDeleteIds, requestDelete, undoDelete } =
|
||||
useDeleteCoachConversationWithUndo();
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [confirmId, setConfirmId] = useState<string | null>(null);
|
||||
|
||||
// Mirror the rail's title substring filter.
|
||||
const filtered = useMemo(() => {
|
||||
const q = filter.trim().toLowerCase();
|
||||
if (!q) return conversations;
|
||||
return conversations.filter((c) => c.title.toLowerCase().includes(q));
|
||||
}, [conversations, filter]);
|
||||
const visible = conversations.filter((c) => !pendingDeleteIds.has(c.id));
|
||||
if (!q) return visible;
|
||||
return visible.filter((c) => c.title.toLowerCase().includes(q));
|
||||
}, [conversations, filter, pendingDeleteIds]);
|
||||
|
||||
const groups = useMemo(() => groupByRecency(filtered), [filtered]);
|
||||
|
||||
@@ -120,13 +122,17 @@ function CoachConversationsBody() {
|
||||
router.push(`/coach?c=${id}`);
|
||||
}
|
||||
|
||||
// v1.30.1 M5 — one tap deletes (with an Undo toast); see
|
||||
// `use-coach.ts`'s `useDeleteCoachConversationWithUndo` for the
|
||||
// rationale — this mirrors the rail's identical fix.
|
||||
function handleDeleteRequest(id: string) {
|
||||
if (confirmId === id) {
|
||||
deleteMutation.mutate(id);
|
||||
setConfirmId(null);
|
||||
} else {
|
||||
setConfirmId(id);
|
||||
}
|
||||
requestDelete(id);
|
||||
toast.success(t("insights.coach.historyDeleted"), {
|
||||
action: {
|
||||
label: t("common.undo"),
|
||||
onClick: () => undoDelete(id),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -212,7 +218,6 @@ function CoachConversationsBody() {
|
||||
</h2>
|
||||
<ul className="flex flex-col gap-1">
|
||||
{group.conversations.map((c) => {
|
||||
const isConfirming = confirmId === c.id;
|
||||
return (
|
||||
<li
|
||||
key={c.id}
|
||||
@@ -260,18 +265,9 @@ function CoachConversationsBody() {
|
||||
variant="ghost"
|
||||
size="icon-lg"
|
||||
onClick={() => handleDeleteRequest(c.id)}
|
||||
aria-label={
|
||||
isConfirming
|
||||
? t("insights.coach.historyDeleteConfirm")
|
||||
: t("insights.coach.historyDeleteAria")
|
||||
}
|
||||
aria-label={t("insights.coach.historyDeleteAria")}
|
||||
data-slot="coach-conversations-delete"
|
||||
data-confirming={isConfirming ? "true" : undefined}
|
||||
className={cn(
|
||||
"shrink-0",
|
||||
isConfirming &&
|
||||
"text-destructive hover:text-destructive",
|
||||
)}
|
||||
className="shrink-0"
|
||||
>
|
||||
<Trash2 className="size-4" aria-hidden="true" />
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user