import { useState } from "react"; import { ActionIcon, Box, Group, Loader, Menu, Text, TextInput, } from "@mantine/core"; import { IconDots, IconEdit, IconTrash } from "@tabler/icons-react"; import { modals } from "@mantine/modals"; import { useTranslation } from "react-i18next"; import clsx from "clsx"; import { useAiChatsQuery, useDeleteAiChatMutation, useRenameAiChatMutation, } from "@/features/ai-chat/queries/ai-chat-query.ts"; import { IAiChat } from "@/features/ai-chat/types/ai-chat.types.ts"; import classes from "@/features/ai-chat/components/ai-chat.module.css"; interface ConversationListProps { activeChatId: string | null; onSelect: (chatId: string) => void; } /** * The user's chat history. Selecting a chat opens it; rename is inline; delete * is confirmed. A brand-new (unsaved) chat is not in this list until the server * persists it on the first message. */ export default function ConversationList({ activeChatId, onSelect, }: ConversationListProps) { const { t } = useTranslation(); const { data, isLoading } = useAiChatsQuery(); const renameMutation = useRenameAiChatMutation(); const deleteMutation = useDeleteAiChatMutation(); const [editingId, setEditingId] = useState(null); const [draftTitle, setDraftTitle] = useState(""); const startRename = (chat: IAiChat): void => { setEditingId(chat.id); setDraftTitle(chat.title ?? ""); }; const commitRename = (chatId: string): void => { const title = draftTitle.trim(); setEditingId(null); if (title) renameMutation.mutate({ chatId, title }); }; const confirmDelete = (chatId: string): void => { modals.openConfirmModal({ title: t("Delete this chat?"), centered: true, labels: { confirm: t("Delete"), cancel: t("Cancel") }, confirmProps: { color: "red" }, onConfirm: () => deleteMutation.mutate(chatId), }); }; if (isLoading) { return ( ); } const chats = data?.items ?? []; if (chats.length === 0) { return ( {t("No chats yet.")} ); } return ( {chats.map((chat) => { const isActive = chat.id === activeChatId; if (editingId === chat.id) { return ( setDraftTitle(e.currentTarget.value)} onBlur={() => commitRename(chat.id)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); commitRename(chat.id); } else if (e.key === "Escape") { setEditingId(null); } }} /> ); } return ( onSelect(chat.id)} > {chat.title || t("Untitled chat")} e.stopPropagation()} > e.stopPropagation()}> } onClick={() => startRename(chat)} > {t("Rename")} } onClick={() => confirmDelete(chat.id)} > {t("Delete")} ); })} ); }