import { useState, useCallback, useMemo, useEffect } from 'react'; import debounce from 'lodash/debounce'; import { useRecoilValue } from 'recoil'; import { TrashIcon, ArchiveRestore, ArrowUp, ArrowDown, ArrowUpDown } from 'lucide-react'; import { Button, OGDialog, OGDialogContent, OGDialogHeader, OGDialogTitle, Label, TooltipAnchor, Spinner, DataTable, useToastContext, useMediaQuery, } from '@librechat/client'; import type { ConversationListParams, TConversation } from 'librechat-data-provider'; import { useArchiveConvoMutation, useConversationsInfiniteQuery, useDeleteConversationMutation, } from '~/data-provider'; import { MinimalIcon } from '~/components/Endpoints'; import { NotificationSeverity } from '~/common'; import { useLocalize } from '~/hooks'; import { formatDate } from '~/utils'; import store from '~/store'; const DEFAULT_PARAMS: ConversationListParams = { isArchived: true, sortBy: 'createdAt', sortDirection: 'desc', search: '', }; export default function ArchivedChatsTable({ onOpenChange, }: { onOpenChange: (isOpen: boolean) => void; }) { const localize = useLocalize(); const isSmallScreen = useMediaQuery('(max-width: 768px)'); const { showToast } = useToastContext(); const isSearchEnabled = useRecoilValue(store.search); const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [queryParams, setQueryParams] = useState(DEFAULT_PARAMS); const [deleteConversation, setDeleteConversation] = useState(null); const { data, fetchNextPage, hasNextPage, isFetchingNextPage, refetch, isLoading } = useConversationsInfiniteQuery(queryParams, { staleTime: 0, cacheTime: 5 * 60 * 1000, refetchOnWindowFocus: false, refetchOnMount: false, }); const handleSort = useCallback((sortField: string, sortOrder: 'asc' | 'desc') => { setQueryParams((prev) => ({ ...prev, sortBy: sortField as 'title' | 'createdAt', sortDirection: sortOrder, })); }, []); const handleFilterChange = useCallback((value: string) => { const encodedValue = encodeURIComponent(value.trim()); setQueryParams((prev) => ({ ...prev, search: encodedValue, })); }, []); const debouncedFilterChange = useMemo( () => debounce(handleFilterChange, 300), [handleFilterChange], ); useEffect(() => { return () => { debouncedFilterChange.cancel(); }; }, [debouncedFilterChange]); const allConversations = useMemo(() => { if (!data?.pages) { return []; } return data.pages.flatMap((page) => page?.conversations?.filter(Boolean) ?? []); }, [data?.pages]); const deleteMutation = useDeleteConversationMutation({ onSuccess: async () => { setIsDeleteOpen(false); await refetch(); showToast({ message: localize('com_ui_convo_delete_success'), severity: NotificationSeverity.SUCCESS, showIcon: true, }); }, onError: (error: unknown) => { showToast({ message: localize('com_ui_archive_delete_error') as string, severity: NotificationSeverity.ERROR, }); }, }); const unarchiveMutation = useArchiveConvoMutation({ onSuccess: async () => { await refetch(); }, onError: (error: unknown) => { showToast({ message: localize('com_ui_unarchive_error') as string, severity: NotificationSeverity.ERROR, }); }, }); const handleFetchNextPage = useCallback(async () => { if (!hasNextPage || isFetchingNextPage) { return; } await fetchNextPage(); }, [fetchNextPage, hasNextPage, isFetchingNextPage]); const columns = useMemo( () => [ { accessorKey: 'title', header: () => { const isSorted = queryParams.sortBy === 'title'; const sortDirection = queryParams.sortDirection; return ( ); }, cell: ({ row }) => { const { conversationId, title } = row.original; return ( ); }, meta: { size: isSmallScreen ? '70%' : '50%', mobileSize: '70%', }, }, { accessorKey: 'createdAt', header: () => { const isSorted = queryParams.sortBy === 'createdAt'; const sortDirection = queryParams.sortDirection; return ( ); }, cell: ({ row }) => formatDate(row.original.createdAt?.toString() ?? '', isSmallScreen), meta: { size: isSmallScreen ? '30%' : '35%', mobileSize: '30%', }, }, { accessorKey: 'actions', header: () => ( ), cell: ({ row }) => { const conversation = row.original; return (
unarchiveMutation.mutate({ conversationId: conversation.conversationId, isArchived: false, }) } title={localize('com_ui_unarchive')} disabled={unarchiveMutation.isLoading} > {unarchiveMutation.isLoading ? ( ) : (
); }, meta: { size: '15%', mobileSize: '25%', }, }, ], [handleSort, isSmallScreen, localize, queryParams, unarchiveMutation], ); return ( <> {localize('com_ui_delete_confirm')} {deleteConversation?.title}
); }