"use client" import { memo, useState, useCallback } from "react" import { formatDistanceToNow } from "date-fns" import { enUS, zhCN, zhTW } from "date-fns/locale" import { GitBranch, Pencil, Trash2, Circle, Download, Plus } from "lucide-react" import { useLocale, useTranslations } from "next-intl" import type { DbConversationSummary, ConversationStatus } from "@/lib/types" import { STATUS_COLORS } from "@/lib/types" import { cn } from "@/lib/utils" import { AgentIcon } from "@/components/agent-icon" import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuSeparator, } from "@/components/ui/context-menu" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" const ALL_STATUSES: ConversationStatus[] = [ "in_progress", "pending_review", "completed", "cancelled", ] interface SidebarConversationCardProps { conversation: DbConversationSummary isSelected: boolean onSelect: (id: number, agentType: string) => void onDoubleClick?: (id: number, agentType: string) => void onRename: (id: number, newTitle: string) => Promise onDelete: (id: number, agentType: string) => Promise onStatusChange: (id: number, status: ConversationStatus) => Promise onNewConversation?: () => void onImport?: () => void importing?: boolean } export const SidebarConversationCard = memo(function SidebarConversationCard({ conversation, isSelected, onSelect, onDoubleClick, onRename, onDelete, onStatusChange, onNewConversation, onImport, importing, }: SidebarConversationCardProps) { const t = useTranslations("Folder.conversationCard") const tStatus = useTranslations("Folder.statusLabels") const locale = useLocale() const dateFnsLocale = locale === "zh-CN" ? zhCN : locale === "zh-TW" ? zhTW : enUS const [renameOpen, setRenameOpen] = useState(false) const [deleteOpen, setDeleteOpen] = useState(false) const [renameValue, setRenameValue] = useState("") const timeAgo = formatDistanceToNow(new Date(conversation.updated_at), { addSuffix: true, locale: dateFnsLocale, }) const handleClick = useCallback(() => { onSelect(conversation.id, conversation.agent_type) }, [onSelect, conversation.id, conversation.agent_type]) const handleDblClick = useCallback(() => { onDoubleClick?.(conversation.id, conversation.agent_type) }, [onDoubleClick, conversation.id, conversation.agent_type]) const handleRenameOpen = useCallback(() => { setRenameValue(conversation.title || "") setRenameOpen(true) }, [conversation.title]) const handleRenameConfirm = useCallback(async () => { const trimmed = renameValue.trim() if (trimmed && trimmed !== conversation.title) { await onRename(conversation.id, trimmed) } setRenameOpen(false) }, [renameValue, conversation.id, conversation.title, onRename]) const handleDeleteConfirm = useCallback(async () => { await onDelete(conversation.id, conversation.agent_type) setDeleteOpen(false) }, [conversation.id, conversation.agent_type, onDelete]) return ( <> {onNewConversation && ( <> {t("newConversation")} )} {t("rename")} {t("status")} {ALL_STATUSES.filter((s) => s !== conversation.status).map( (s) => ( onStatusChange(conversation.id, s)} > {tStatus(s)} ) )} setDeleteOpen(true)} > {t("delete")} {onImport && ( <> {importing ? t("importing") : t("importLocalSessions")} )} {t("renameConversation")} setRenameValue(e.target.value)} onKeyDown={(e) => { if (e.nativeEvent.isComposing || e.key === "Process") return if (e.key === "Enter") handleRenameConfirm() }} autoFocus /> {t("deleteConversationTitle")} {t("deleteConversationDescription", { title: conversation.title || t("untitledConversation"), })} {t("cancel")} {t("delete")} ) })