"use client"; import { type ColumnDef } from "@tanstack/react-table"; import { FileArchive, Eye, ChevronRight, Layers, Ungroup, Send, ImagePlus, GitMerge } from "lucide-react"; import { DataTableColumnHeader } from "@/components/shared/data-table-column-header"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { SendToTelegramButton } from "./send-to-telegram-button"; export interface PackageRow { id: string; fileName: string; fileSize: string; contentHash: string; archiveType: "ZIP" | "RAR" | "SEVEN_Z" | "DOCUMENT"; fileCount: number; isMultipart: boolean; hasPreview: boolean; creator: string | null; tags: string[]; indexedAt: string; sourceChannel: { id: string; title: string; }; matchedFileCount: number; matchedByContent: boolean; packageGroupId?: string | null; } export interface GroupHeaderRow { _rowType: "group"; id: string; name: string; hasPreview: boolean; totalFileSize: string; totalFileCount: number; packageCount: number; combinedTags: string[]; archiveTypes: ("ZIP" | "RAR" | "SEVEN_Z" | "DOCUMENT")[]; latestIndexedAt: string; sourceChannel: { id: string; title: string }; _expanded: boolean; } export interface PackageTableRow extends PackageRow { _rowType: "package"; _groupId: string | null; _isGroupMember: boolean; } export type StlTableRow = GroupHeaderRow | PackageTableRow; function isGroupRow(row: StlTableRow): row is GroupHeaderRow { return row._rowType === "group"; } interface PackageColumnsProps { onViewFiles: (pkg: PackageRow) => void; onSetCreator: (pkg: PackageRow) => void; onSetTags: (pkg: PackageRow) => void; searchTerm: string; onToggleGroup: (groupId: string) => void; onRenameGroup: (groupId: string, currentName: string) => void; onDissolveGroup: (groupId: string) => void; onSendAllInGroup: (groupId: string) => void; onRemoveFromGroup: (packageId: string) => void; onGroupPreviewUpload: (groupId: string) => void; selectedPackages: Set; onToggleSelect: (packageId: string) => void; mergeSourceId: string | null; onStartMerge: (groupId: string) => void; onCompleteMerge: (targetGroupId: string) => void; } export function formatBytes(bytesStr: string): string { const bytes = Number(bytesStr); if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`; } function PreviewCell({ pkg }: { pkg: PackageRow }) { if (pkg.hasPreview) { return ( ); } return (
); } function GroupPreviewCell({ group, onUpload, }: { group: GroupHeaderRow; onUpload: (groupId: string) => void; }) { if (group.hasPreview) { return ( ); } return ( ); } export function getPackageColumns({ onViewFiles, onSetCreator, onSetTags, searchTerm, onToggleGroup, onRenameGroup, onDissolveGroup, onSendAllInGroup, onRemoveFromGroup, onGroupPreviewUpload, selectedPackages, onToggleSelect, mergeSourceId, onStartMerge, onCompleteMerge, }: PackageColumnsProps): ColumnDef[] { return [ { id: "select", header: "", cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) return null; return ( onToggleSelect(data.id)} aria-label="Select package" className="translate-y-[2px]" /> ); }, enableHiding: false, enableSorting: false, size: 32, }, { id: "preview", header: "", cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) { return (
); } return (
); }, enableHiding: false, enableSorting: false, size: 72, }, { accessorKey: "fileName", header: ({ column }) => , cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) { return (
{data.packageCount} pkg{data.packageCount !== 1 ? "s" : ""}
); } return (
{data.fileName} {data.isMultipart && ( Multi )}
{searchTerm && data.matchedByContent && ( )}
); }, enableHiding: false, }, { accessorKey: "archiveType", header: ({ column }) => , cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) { const types = data.archiveTypes; if (types.length === 1) { return ( {types[0]} ); } return ( Mixed ); } return ( {data.archiveType} ); }, }, { accessorKey: "fileSize", header: ({ column }) => , cell: ({ row }) => { const data = row.original; const size = isGroupRow(data) ? data.totalFileSize : data.fileSize; return ( {formatBytes(size)} ); }, }, { accessorKey: "fileCount", header: ({ column }) => , cell: ({ row }) => { const data = row.original; const count = isGroupRow(data) ? data.totalFileCount : data.fileCount; return ( {count.toLocaleString()} ); }, }, { accessorKey: "creator", header: ({ column }) => , cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) { return {"\u2014"}; } return ( ); }, }, { id: "tags", header: ({ column }) => , cell: ({ row }) => { const data = row.original; const tags = isGroupRow(data) ? data.combinedTags : data.tags; if (tags.length === 0) { if (isGroupRow(data)) { return {"\u2014"}; } return ( ); } const clickHandler = isGroupRow(data) ? undefined : () => onSetTags(data as PackageTableRow); return ( ); }, accessorFn: (row) => { if (isGroupRow(row)) return row.combinedTags.join(", "); return row.tags.join(", "); }, }, { id: "channel", header: ({ column }) => , cell: ({ row }) => ( {row.original.sourceChannel.title} ), accessorFn: (row) => row.sourceChannel.title, }, { accessorKey: "indexedAt", header: ({ column }) => , cell: ({ row }) => { const data = row.original; const date = isGroupRow(data) ? data.latestIndexedAt : data.indexedAt; return ( {new Date(date).toLocaleDateString()} ); }, }, { id: "actions", cell: ({ row }) => { const data = row.original; if (isGroupRow(data)) { const isMergeSource = mergeSourceId === data.id; const canMergeHere = mergeSourceId !== null && mergeSourceId !== data.id; return (
{canMergeHere && ( )}
); } return (
{data._isGroupMember && ( )}
); }, enableHiding: false, }, ]; }