import { DownloadIcon, FileIcon, Maximize2Icon, PaperclipIcon, PlayIcon } from "lucide-react"; import { useMemo } from "react"; import MetadataSection from "@/components/MemoMetadata/MetadataSection"; import { cn } from "@/lib/utils"; import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb"; import { getAttachmentUrl } from "@/utils/attachment"; import AttachmentCard from "./AttachmentCard"; import AudioAttachmentItem from "./AudioAttachmentItem"; import { getAttachmentMetadata, isImageAttachment, isVideoAttachment, separateAttachments } from "./attachmentHelpers"; interface AttachmentListViewProps { attachments: Attachment[]; onImagePreview?: (urls: string[], index: number) => void; } const AttachmentMeta = ({ attachment }: { attachment: Attachment }) => { const { fileTypeLabel, fileSizeLabel } = getAttachmentMetadata(attachment); return (
{fileTypeLabel} {fileSizeLabel && ( <> {fileSizeLabel} )}
); }; const DocumentItem = ({ attachment }: { attachment: Attachment }) => { return (
{attachment.filename}
); }; interface VisualItemProps { attachment: Attachment; featured?: boolean; } const ImageItem = ({ attachment, onImageClick, featured = false }: VisualItemProps & { onImageClick?: (url: string) => void }) => { const handleClick = () => { onImageClick?.(getAttachmentUrl(attachment)); }; return ( ); }; const ImageGallery = ({ attachments, onImageClick }: { attachments: Attachment[]; onImageClick?: (url: string) => void }) => { if (attachments.length === 1) { return (
); } return (
{attachments.map((attachment) => ( ))}
); }; const VideoItem = ({ attachment }: VisualItemProps) => (
{attachment.filename}
); const VideoList = ({ attachments }: { attachments: Attachment[] }) => (
{attachments.map((attachment) => ( ))}
); const VisualSection = ({ attachments, onImageClick }: { attachments: Attachment[]; onImageClick?: (url: string) => void }) => { const images = attachments.filter(isImageAttachment); const videos = attachments.filter(isVideoAttachment); return (
{images.length > 0 && } {videos.length > 0 && (
{images.length > 0 && }
)}
); }; const AudioList = ({ attachments }: { attachments: Attachment[] }) => (
{attachments.map((attachment) => ( ))}
); const DocsList = ({ attachments }: { attachments: Attachment[] }) => (
{attachments.map((attachment) => ( ))}
); const Divider = () =>
; const AttachmentListView = ({ attachments, onImagePreview }: AttachmentListViewProps) => { const { visual, audio, docs } = useMemo(() => separateAttachments(attachments), [attachments]); const imageAttachments = useMemo(() => visual.filter(isImageAttachment), [visual]); const imageUrls = useMemo(() => imageAttachments.map(getAttachmentUrl), [imageAttachments]); const hasVisual = visual.length > 0; const hasAudio = audio.length > 0; const hasDocs = docs.length > 0; const sectionCount = [hasVisual, hasAudio, hasDocs].filter(Boolean).length; if (attachments.length === 0) { return null; } const handleImageClick = (imgUrl: string) => { const index = imageUrls.findIndex((url) => url === imgUrl); onImagePreview?.(imageUrls, index >= 0 ? index : 0); }; return ( {hasVisual && } {hasVisual && sectionCount > 1 && } {hasAudio && } {hasAudio && hasDocs && } {hasDocs && } ); }; export default AttachmentListView;