'use client' /** * ChatImagePreviewModal — full-screen-ish preview + download for chat images. * * Purpose * - Opens from `MessageBubble`; uses ConsumerModal. Download URL resolution * stays local (guess filename / trusted upload URL). */ import Image from 'next/image' import { useState } from 'react' import ConsumerButton from '@/components/consumer/ConsumerButton' import CloseIcon from '@/components/icons/CloseIcon' import CloudDownloadIcon from '@/components/icons/CloudDownloadIcon' import ConsumerModal from '@/components/consumer/ConsumerModal' import { withBasePath } from '@/constants/images' import { texts } from '@/texts' import { addToast } from '@/lib/toast' interface ChatImagePreviewModalProps { imageUrl: string | null isOpen: boolean onOpenChange: (open: boolean) => void } const guessFileName = (imageUrl: string) => { try { const pathname = new URL(imageUrl, window.location.origin).pathname const base = pathname.split('/').filter(Boolean).at(-1) if (base && /\.[a-z0-9]{2,5}$/i.test(base)) return decodeURIComponent(base) } catch { // ignore invalid URL } return `chat-image-${Date.now()}.jpg` } const resolveDownloadUrl = (imageUrl: string) => { try { const target = new URL(imageUrl, window.location.origin) if (target.origin === window.location.origin) return target.toString() } catch { return imageUrl } // Cross-origin file hosts (e.g. ghabilee.ir from localhost) often omit CORS // for /uploads — proxy through Next so the browser sees a same-origin blob. return `${withBasePath('/api/download-upload')}?url=${encodeURIComponent(imageUrl)}` } const ChatImagePreviewModal = ({ imageUrl, isOpen, onOpenChange }: ChatImagePreviewModalProps) => { const [isDownloading, setIsDownloading] = useState(false) const handleDownload = async () => { if (!imageUrl || isDownloading) return setIsDownloading(true) try { const response = await fetch(resolveDownloadUrl(imageUrl)) if (!response.ok) throw new Error('download failed') const blob = await response.blob() const objectUrl = URL.createObjectURL(blob) const anchor = document.createElement('a') anchor.href = objectUrl anchor.download = guessFileName(imageUrl) document.body.appendChild(anchor) anchor.click() anchor.remove() URL.revokeObjectURL(objectUrl) } catch { window.open(imageUrl, '_blank', 'noopener,noreferrer') addToast({ title: texts.chats.downloadFallbackToast, color: 'warning' }) } finally { setIsDownloading(false) } } return (
{ onOpenChange(false) }} > : undefined} isLoading={isDownloading} onClick={() => void handleDownload()} > {texts.chats.download}
{imageUrl ? ( {texts.chats.chatAttachmentAlt} ) : null}
) } export default ChatImagePreviewModal