"use client"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Download, LoaderCircle, LoaderPinwheel } from "lucide-react"; import { useFiles } from "@/hooks/use-files"; import { FileFilters } from "@/components/file-filters"; import { getRowHeightPX, useRowHeightLocalStorage, } from "@/components/table-row-height-switch"; import { type Column } from "@/components/table-column-filter"; import { cn } from "@/lib/utils"; import FileNotFount from "@/components/file-not-found"; import useSWRMutation from "swr/mutation"; import { POST } from "@/lib/api"; import FileRow from "@/components/file-row"; import { useVirtualizer } from "@tanstack/react-virtual"; import { type TelegramFile } from "@/lib/types"; import FileViewer from "@/components/file-viewer"; const COLUMNS: Column[] = [ { id: "content", label: "Content", isVisible: true, className: "text-center", }, { id: "type", label: "Type", isVisible: true, className: "w-16 text-center" }, { id: "size", label: "Size", isVisible: true, className: "w-20 text-center", }, { id: "status", label: "Status", isVisible: true, className: "w-32 text-center", }, { id: "extra", label: "Extra", isVisible: true, className: "flex-1" }, { id: "actions", label: "Actions", isVisible: true, className: "text-center w-40 min-w-40", }, ]; interface FileTableProps { accountId: string; chatId: string; } export function FileTable({ accountId, chatId }: FileTableProps) { const [selectedFiles, setSelectedFiles] = useState>(new Set()); const tableParentRef = useRef(null); const [columns, setColumns] = useState(COLUMNS); const [rowHeight, setRowHeight] = useRowHeightLocalStorage( "telegramFileList", "m", ); const useFilesProps = useFiles(accountId, chatId); const { filters, handleFilterChange, isLoading, files, handleLoadMore } = useFilesProps; const [currentViewFile, setCurrentViewFile] = useState(); const [viewerOpen, setViewerOpen] = useState(false); const { trigger: startDownloadMultiple, isMutating: startDownloadMultipleMutating, } = useSWRMutation( `/${accountId}/file/start-download-multiple`, ( key, { arg, }: { arg: { chatId: number; files: Array<{ messageId: number; fileId: number }>; }; }, ) => POST(key, arg), { onSuccess: () => { setSelectedFiles(new Set()); }, }, ); const rowVirtual = useVirtualizer({ count: files.length, getScrollElement: () => tableParentRef.current, estimateSize: (index) => { const file = files[index]!; const height = getRowHeightPX(rowHeight); if ( file.downloadStatus === "idle" || file.downloadStatus === "completed" || file.size === 0 ) { return height; } return height + 8; }, paddingStart: 1, paddingEnd: 1, }); useEffect(() => { rowVirtual.measure(); }, [rowHeight, rowVirtual]); useEffect(() => { const [lastItem] = [...rowVirtual.getVirtualItems()].reverse(); if (!lastItem) { return; } if (lastItem.index >= files.length - 1) { void handleLoadMore(); } //eslint-disable-next-line }, [files.length, handleLoadMore, rowVirtual.getVirtualItems()]); useEffect(() => { if (files.length === 0 || !currentViewFile) { return; } const index = files.findIndex((f) => f.id === currentViewFile.id); if (index === -1) { setCurrentViewFile(undefined); return; } const file = files[index]!; if (currentViewFile.next === undefined && file.next !== undefined) { setCurrentViewFile(file); } }, [currentViewFile, files]); const dynamicClass = useMemo(() => { switch (rowHeight) { case "s": return { content: "h-6 w-6", contentCell: "w-16", }; case "m": return { content: "h-20 w-20", contentCell: "w-24", }; case "l": return { content: "h-60 w-60", contentCell: "w-64", }; } }, [rowHeight]); const handleSelectAll = () => { if (selectedFiles.size === files.length) { setSelectedFiles(new Set()); } else { setSelectedFiles( new Set( files .filter((file) => file.downloadStatus === "idle") .map((file) => file.id), ), ); } }; const handleSelectFile = (fileId: number) => { const newSelected = new Set(selectedFiles); if (newSelected.has(fileId)) { newSelected.delete(fileId); } else { newSelected.add(fileId); } setSelectedFiles(newSelected); }; return ( <> {currentViewFile && ( )}
{selectedFiles.size > 0 && (
{selectedFiles.size} {selectedFiles.size === 1 ? "file" : "files"}{" "} selected
)}
{columns.map((col) => col.isVisible ? (
{col.label}
) : null, )}
{files.length === 0 && isLoading && (
)}
{files.length !== 0 && rowVirtual.getVirtualItems().map((virtualRow) => { const file = files[virtualRow.index]!; return ( handleSelectFile(file.id)} onFileClick={() => { setCurrentViewFile(file); setViewerOpen(true); }} properties={{ rowHeight: rowHeight, dynamicClass, columns, }} key={`${file.messageId}-${file.uniqueId}-${virtualRow.index}`} /> ); })}
{!isLoading && files.length === 0 && }
); }