import { useState, useId, useRef, memo, useCallback, useMemo } from 'react'; import * as Menu from '@ariakit/react/menu'; import { useParams, useNavigate } from 'react-router-dom'; import { DropdownPopup, Spinner, useToastContext } from '@librechat/client'; import { Ellipsis, Share2, CopyPlus, Archive, Pen, Trash } from 'lucide-react'; import type { MouseEvent } from 'react'; import { useDuplicateConversationMutation, useGetStartupConfig, useArchiveConvoMutation, } from '~/data-provider'; import { useLocalize, useNavigateToConvo, useNewConvo } from '~/hooks'; import { NotificationSeverity } from '~/common'; import { useChatContext } from '~/Providers'; import DeleteButton from './DeleteButton'; import ShareButton from './ShareButton'; import { cn } from '~/utils'; function ConvoOptions({ conversationId, title, retainView, renameHandler, isPopoverActive, setIsPopoverActive, isActiveConvo, }: { conversationId: string | null; title: string | null; retainView: () => void; renameHandler: (e: MouseEvent) => void; isPopoverActive: boolean; setIsPopoverActive: React.Dispatch>; isActiveConvo: boolean; }) { const localize = useLocalize(); const { index } = useChatContext(); const { data: startupConfig } = useGetStartupConfig(); const { navigateToConvo } = useNavigateToConvo(index); const { showToast } = useToastContext(); const navigate = useNavigate(); const { conversationId: currentConvoId } = useParams(); const { newConversation } = useNewConvo(); const shareButtonRef = useRef(null); const deleteButtonRef = useRef(null); const [showShareDialog, setShowShareDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const archiveConvoMutation = useArchiveConvoMutation(); const duplicateConversation = useDuplicateConversationMutation({ onSuccess: (data) => { navigateToConvo(data.conversation); showToast({ message: localize('com_ui_duplication_success'), status: 'success', }); setIsPopoverActive(false); }, onMutate: () => { showToast({ message: localize('com_ui_duplication_processing'), status: 'info', }); }, onError: () => { showToast({ message: localize('com_ui_duplication_error'), status: 'error', }); }, }); const isDuplicateLoading = duplicateConversation.isLoading; const isArchiveLoading = archiveConvoMutation.isLoading; const handleShareClick = useCallback(() => { setShowShareDialog(true); }, []); const handleDeleteClick = useCallback(() => { setShowDeleteDialog(true); }, []); const handleArchiveClick = useCallback(async () => { const convoId = conversationId ?? ''; if (!convoId) { return; } archiveConvoMutation.mutate( { conversationId: convoId, isArchived: true }, { onSuccess: () => { if (currentConvoId === convoId || currentConvoId === 'new') { newConversation(); navigate('/c/new', { replace: true }); } retainView(); setIsPopoverActive(false); }, onError: () => { showToast({ message: localize('com_ui_archive_error'), severity: NotificationSeverity.ERROR, showIcon: true, }); }, }, ); }, [ conversationId, currentConvoId, archiveConvoMutation, navigate, newConversation, retainView, setIsPopoverActive, showToast, localize, ]); const handleDuplicateClick = useCallback(() => { duplicateConversation.mutate({ conversationId: conversationId ?? '', }); }, [conversationId, duplicateConversation]); const dropdownItems = useMemo( () => [ { label: localize('com_ui_share'), onClick: handleShareClick, icon: