'use client'; import React, { useEffect, useRef, useState, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Send, FileText, Film, Music, Archive, File, ZoomIn, ZoomOut } from 'lucide-react'; interface FilePreviewModalProps { file: File | null; onConfirm: (file: File, caption: string) => Promise; onCancel: () => void; } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } function getFileIcon(type: string) { if (type.startsWith('video/')) return ; if (type.startsWith('audio/')) return ; if (type.includes('pdf') || type.includes('document') || type.includes('word')) return ; if (type.includes('zip') || type.includes('compressed') || type.includes('tar')) return ; return ; } function getFileLabel(type: string): string { if (type.startsWith('image/')) return 'Imagem'; if (type.startsWith('video/')) return 'Vídeo'; if (type.startsWith('audio/')) return 'Áudio'; if (type.includes('pdf')) return 'PDF'; return 'Arquivo'; } function ModalContent({ file, onConfirm, onCancel }: FilePreviewModalProps & { file: File }) { const [caption, setCaption] = useState(''); const [sending, setSending] = useState(false); const [objectUrl, setObjectUrl] = useState(null); const [zoomed, setZoomed] = useState(false); // Posição do mouse como % dentro da área da imagem (para o zoom seguir o cursor) const [mouseOrigin, setMouseOrigin] = useState({ x: 50, y: 50 }); const captionRef = useRef(null); const previewAreaRef = useRef(null); const isImage = file.type.startsWith('image/'); const isVideo = file.type.startsWith('video/'); useEffect(() => { const url = URL.createObjectURL(file); setObjectUrl(url); setCaption(''); setSending(false); setZoomed(false); setMouseOrigin({ x: 50, y: 50 }); setTimeout(() => captionRef.current?.focus(), 250); return () => URL.revokeObjectURL(url); }, [file]); useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onCancel(); }; document.addEventListener('keydown', onKey); return () => document.removeEventListener('keydown', onKey); }, [onCancel]); const handleSend = useCallback(async () => { if (sending) return; setSending(true); try { await onConfirm(file, caption.trim()); } finally { setSending(false); } }, [file, caption, sending, onConfirm]); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); handleSend(); } }; // Atualiza a origem do zoom conforme o mouse se move na área de preview const handleMouseMove = useCallback((e: React.MouseEvent) => { if (!isImage) return; const rect = e.currentTarget.getBoundingClientRect(); const x = ((e.clientX - rect.left) / rect.width) * 100; const y = ((e.clientY - rect.top) / rect.height) * 100; setMouseOrigin({ x, y }); }, [isImage]); const toggleZoom = useCallback(() => setZoomed(z => !z), []); return ( {/* ── Top bar ── */}
{/* Info do arquivo — lado esquerdo */}

{file.name}

{getFileLabel(file.type)} · {formatFileSize(file.size)}

{/* Botões — lado direito: zoom (se imagem) → fechar */}
{isImage && ( )}
{/* ── Preview area ── */}
{isImage && objectUrl && ( )} {isVideo && objectUrl && ( )} {!isImage && !isVideo && (
{getFileIcon(file.type)}

{file.name}

{formatFileSize(file.size)}

)}
{/* ── Caption + Send bar ── */}
setCaption(e.target.value)} onKeyDown={handleKeyDown} disabled={sending} maxLength={1024} className="flex-1 bg-[#2a3942] text-[#e9edef] placeholder:text-[#8696a0] text-sm rounded-full px-5 py-2.5 outline-none border-none focus:ring-0 disabled:opacity-50 transition-opacity" />
); } export default function FilePreviewModal({ file, onConfirm, onCancel }: FilePreviewModalProps) { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); if (!mounted) return null; return createPortal( {file && ( )} , document.body ); }