"use client" import { memo, useState, useCallback } from "react" import { Pencil, Trash2, Circle, CircleAlert, CircleCheck, CircleDashed, CircleX, Download, Plus, type LucideIcon, } from "lucide-react" import { useTranslations } from "next-intl" import type { DbConversationSummary, ConversationStatus } from "@/lib/types" import { STATUS_ORDER } from "@/lib/types" import { cn } from "@/lib/utils" 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" import { SidebarStatusIcon, conversationStatusToBead, } from "./sidebar-status-icon" const STATUS_ICONS: Record = { in_progress: CircleDashed, pending_review: CircleAlert, completed: CircleCheck, cancelled: CircleX, } const STATUS_ICON_COLORS: Record = { in_progress: "text-blue-500", pending_review: "text-orange-500", completed: "text-green-500", cancelled: "text-red-500", } interface SidebarConversationCardProps { conversation: DbConversationSummary isSelected: boolean timeLabel?: string 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, timeLabel, onSelect, onDoubleClick, onRename, onDelete, onStatusChange, onNewConversation, onImport, importing, }: SidebarConversationCardProps) { const t = useTranslations("Folder.conversationCard") const tSidebar = useTranslations("Folder.sidebar") const tStatus = useTranslations("Folder.statusLabels") const [renameOpen, setRenameOpen] = useState(false) const [deleteOpen, setDeleteOpen] = useState(false) const [renameValue, setRenameValue] = useState("") 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]) const status = conversation.status as ConversationStatus const beadStatus = conversationStatusToBead(conversation.status) const isRunning = status === "in_progress" const isFailed = status === "cancelled" return ( <>
{onNewConversation && ( <> {t("newConversation")} )} {t("rename")} {t("status")} {STATUS_ORDER.filter((s) => s !== conversation.status).map( (s) => { const StatusIcon = STATUS_ICONS[s] return ( 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")} ) })