financial-data-analyst/components/FilePreview.tsx (82 lines of code) (raw):

import React from "react"; import { X, FileText } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import Image from "next/image"; interface FilePreviewProps { file: { base64: string; fileName: string; mediaType: string; isText?: boolean; }; onRemove?: () => void; size?: "small" | "large"; } const FilePreview: React.FC<FilePreviewProps> = ({ file, onRemove, size = "large", }) => { const isImage = file.mediaType.startsWith("image/"); const fileExtension = file.fileName.split(".").pop()?.toLowerCase() || ""; const truncatedName = file.fileName.length > 7 ? `${file.fileName.slice(0, 7)}...${file.fileName.slice( file.fileName.lastIndexOf("."), )}` : file.fileName; const imageUrl = isImage ? `data:${file.mediaType};base64,${file.base64}` : ""; if (size === "small") { return ( <Badge variant="secondary" className="gap-2 py-1 px-3"> {isImage ? ( <div className="relative w-4 h-4"> <Image src={imageUrl} alt={file.fileName} className="object-cover rounded" fill sizes="16px" unoptimized /> </div> ) : ( <FileText className="w-4 h-4" /> )} <span className="text-xs">{truncatedName}</span> </Badge> ); } return ( <div className="relative inline-flex items-center rounded-lg border bg-card text-card-foreground shadow-sm w-16 h-16"> {isImage ? ( <div className="relative w-full h-full"> <Image src={imageUrl} alt={file.fileName} className="object-cover rounded-lg" fill sizes="64px" unoptimized /> </div> ) : ( <div className="w-full h-full flex flex-col items-center justify-center bg-muted rounded-lg"> <FileText className="w-6 h-6 mb-1" /> <span className="text-xs font-medium uppercase">{fileExtension}</span> </div> )} {onRemove && ( <button onClick={(e) => { e.preventDefault(); onRemove(); }} className="absolute -top-2 -right-2 rounded-full bg-destructive p-1 text-destructive-foreground hover:bg-destructive/90" > <X className="h-3 w-3" /> </button> )} </div> ); }; export default FilePreview;