"use client"; import { type TelegramFile } from "@/lib/types"; import { FileCard } from "./file-card"; import React, { memo, type ReactNode, useEffect, useMemo, useRef, useState, } from "react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Download, FileAudioIcon, FileIcon, ImageIcon, LoaderPinwheel, VideoIcon, } from "lucide-react"; import { useFiles } from "@/hooks/use-files"; import { FileFilters } from "@/components/file-filters"; import { getRowHeightTailwindClass, useRowHeightLocalStorage, } from "@/components/table-row-height-switch"; import { type Column } from "@/components/table-column-filter"; import { cn } from "@/lib/utils"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import PhotoPreview from "@/components/photo-preview"; import SpoiledWrapper from "@/components/spoiled-wrapper"; import Image from "next/image"; import FileControl from "@/components/file-control"; import prettyBytes from "pretty-bytes"; import FileProgress from "@/components/file-progress"; import FileNotFount from "@/components/file-not-found"; import FileExtra from "@/components/file-extra"; import useIsMobile from "@/hooks/use-is-mobile"; import FileStatus from "@/components/file-status"; interface FileListProps { accountId: string; chatId: string; } const COLUMNS: Column[] = [ { id: "content", label: "Content", isVisible: true }, { id: "type", label: "Type", isVisible: true, className: "w-16 text-center" }, { id: "size", label: "Size", isVisible: true, className: "w-20 max-w-20 text-center", }, { id: "status", label: "Status", isVisible: true, className: "w-16 text-center", }, { id: "extra", label: "Extra", isVisible: true }, { id: "actions", label: "Actions", isVisible: true, className: "text-center w-40 min-w-40", }, ]; const PhotoColumnImage = memo(function PhotoColumnImage({ thumbnail, name, wh, }: { thumbnail: string; name: string; wh: string; }) { return ( {name ); }); export function FileList({ accountId, chatId }: FileListProps) { const isMobile = useIsMobile(); const [selectedFiles, setSelectedFiles] = useState>(new Set()); const observerTarget = useRef(null); const [columns, setColumns] = useState(COLUMNS); const [rowHeight, setRowHeight] = useRowHeightLocalStorage( "telegramFileList", "m", ); const { filters, handleFilterChange, isLoading, files, handleLoadMore } = useFiles(accountId, chatId); useEffect(() => { const observer = new IntersectionObserver( (entries) => { if (entries[0]?.isIntersecting) { void handleLoadMore(); } }, { threshold: 0.1 }, ); if (observerTarget.current) { observer.observe(observerTarget.current); } return () => observer.disconnect(); }, [handleLoadMore]); const contentWH = useMemo(() => { switch (rowHeight) { case "s": return "h-6 w-6"; case "m": return "h-20 w-20"; case "l": return "h-60 w-60"; } }, [rowHeight]); const contentCellWidth = useMemo(() => { switch (rowHeight) { case "s": return "w-6"; case "m": return "w-24"; case "l": return "w-64"; } }, [rowHeight]); if (isMobile) { return (
{files.map((file, index) => ( ))}
); } const handleSelectAll = () => { if (selectedFiles.size === files.length) { setSelectedFiles(new Set()); } else { setSelectedFiles(new Set(files.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); }; const getFileIcon = (type: TelegramFile["type"]) => { let icon; switch (type) { case "photo": icon = ; break; case "video": icon = ; break; case "audio": icon = ; break; default: icon = ; } return (
{icon}
); }; const columnRenders: Record< string, (file: TelegramFile, index: number) => ReactNode > = { content: (file: TelegramFile) => (
{file.type === "photo" || file.type === "video" ? ( file.thumbnail ? ( ) : ( getFileIcon(file.type) ) ) : ( getFileIcon(file.type) )}
), type: (file: TelegramFile) => (
{file.type} {file.id}
), size: (file: TelegramFile) => {prettyBytes(file.size)}, status: (file: TelegramFile) => , extra: (file: TelegramFile) => ( ), actions: (file: TelegramFile) => , }; return ( <>
{selectedFiles.size > 0 && (
{selectedFiles.size} {selectedFiles.size === 1 ? "file" : "files"}{" "} selected
)}
{columns.map((col) => col.isVisible ? ( {col.label} ) : null, )} {files.map((file, index) => ( handleSelectFile(file.id)} /> {columns.map((col) => col.isVisible ? ( {columnRenders[col.id]!(file, index)} ) : null, )} ))} {!isLoading && files.length === 0 && ( )}
{isLoading && (
)}
); }