refactor(copilot): Extract DeleteChatDialog to own component

Move delete confirmation dialog from ChatSidebar to reusable component:
- Create DeleteChatDialog under app/copilot/components
- Clean props interface: session, isDeleting, onConfirm, onCancel
- Update ChatSidebar to use new component
- All existing tests pass
This commit is contained in:
Otto
2026-02-17 04:37:33 +00:00
parent 1681a84c2f
commit 5f55e1cd7c
3 changed files with 74 additions and 42 deletions

View File

@@ -7,8 +7,8 @@ import {
import { Button } from "@/components/atoms/Button/Button";
import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
import { Text } from "@/components/atoms/Text/Text";
import { Dialog } from "@/components/molecules/Dialog/Dialog";
import { toast } from "@/components/molecules/Toast/use-toast";
import { DeleteChatDialog } from "../DeleteChatDialog";
import {
Sidebar,
SidebarContent,
@@ -262,47 +262,12 @@ export function ChatSidebar() {
)}
</Sidebar>
<Dialog
title="Delete chat"
controlled={{
isOpen: !!sessionToDelete,
set: async (open) => {
if (!open && !isDeleting) {
setSessionToDelete(null);
}
},
}}
onClose={handleCancelDelete}
>
<Dialog.Content>
<p className="text-neutral-600">
Are you sure you want to delete{" "}
<span className="font-medium">
&quot;{sessionToDelete?.title || "Untitled chat"}&quot;
</span>
? This action cannot be undone.
</p>
<Dialog.Footer>
<Button
variant="ghost"
size="small"
onClick={handleCancelDelete}
disabled={isDeleting}
>
Cancel
</Button>
<Button
variant="primary"
size="small"
onClick={handleConfirmDelete}
loading={isDeleting}
className="bg-red-600 hover:bg-red-700"
>
Delete
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog>
<DeleteChatDialog
session={sessionToDelete}
isDeleting={isDeleting}
onConfirm={handleConfirmDelete}
onCancel={handleCancelDelete}
/>
</>
);
}

View File

@@ -0,0 +1,66 @@
"use client";
import { Button } from "@/components/atoms/Button/Button";
import { Dialog } from "@/components/molecules/Dialog/Dialog";
interface DeleteChatDialogProps {
/** The session to delete, or null if dialog should be closed */
session: { id: string; title: string | null | undefined } | null;
/** Whether deletion is in progress */
isDeleting: boolean;
/** Called when user confirms deletion */
onConfirm: () => void;
/** Called when user cancels (only works when not deleting) */
onCancel: () => void;
}
export function DeleteChatDialog({
session,
isDeleting,
onConfirm,
onCancel,
}: DeleteChatDialogProps) {
return (
<Dialog
title="Delete chat"
controlled={{
isOpen: !!session,
set: async (open) => {
if (!open && !isDeleting) {
onCancel();
}
},
}}
onClose={onCancel}
>
<Dialog.Content>
<p className="text-neutral-600">
Are you sure you want to delete{" "}
<span className="font-medium">
&quot;{session?.title || "Untitled chat"}&quot;
</span>
? This action cannot be undone.
</p>
<Dialog.Footer>
<Button
variant="ghost"
size="small"
onClick={onCancel}
disabled={isDeleting}
>
Cancel
</Button>
<Button
variant="primary"
size="small"
onClick={onConfirm}
loading={isDeleting}
className="bg-red-600 hover:bg-red-700"
>
Delete
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog>
);
}

View File

@@ -0,0 +1 @@
export { DeleteChatDialog } from "./DeleteChatDialog";