Добавлен компонент Lightbox для просмотра изображений в мессенджере. Реализована логика обработки кликов по изображениям для открытия их в Lightbox. Обновлен интерфейс отображения вложений с улучшенной поддержкой изображений и добавлены подсказки для пользователей. Оптимизирован код для лучшей читаемости.
This commit is contained in:
@ -8,6 +8,7 @@ import { Card } from '@/components/ui/card'
|
|||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
import { ImageLightbox } from '@/components/ui/image-lightbox'
|
||||||
import {
|
import {
|
||||||
FileText,
|
FileText,
|
||||||
Image,
|
Image,
|
||||||
@ -51,6 +52,7 @@ interface MessengerAttachmentsProps {
|
|||||||
export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps) {
|
export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps) {
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
const [activeTab, setActiveTab] = useState('all')
|
const [activeTab, setActiveTab] = useState('all')
|
||||||
|
const [lightboxImage, setLightboxImage] = useState<{ url: string; fileName: string; fileSize?: number } | null>(null)
|
||||||
|
|
||||||
// Загружаем все сообщения для получения вложений
|
// Загружаем все сообщения для получения вложений
|
||||||
const { data: messagesData, loading } = useQuery(GET_MESSAGES, {
|
const { data: messagesData, loading } = useQuery(GET_MESSAGES, {
|
||||||
@ -117,6 +119,14 @@ export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps
|
|||||||
document.body.removeChild(link)
|
document.body.removeChild(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleImageClick = (imageUrl: string, fileName?: string, fileSize?: number) => {
|
||||||
|
setLightboxImage({
|
||||||
|
url: imageUrl,
|
||||||
|
fileName: fileName || 'Изображение',
|
||||||
|
fileSize
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const renderFileIcon = (fileType?: string) => {
|
const renderFileIcon = (fileType?: string) => {
|
||||||
if (!fileType) return <FileText className="h-4 w-4" />
|
if (!fileType) return <FileText className="h-4 w-4" />
|
||||||
|
|
||||||
@ -166,18 +176,34 @@ export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps
|
|||||||
|
|
||||||
{/* Содержимое вложения */}
|
{/* Содержимое вложения */}
|
||||||
<div className="flex items-center justify-between bg-white/5 rounded-lg p-3">
|
<div className="flex items-center justify-between bg-white/5 rounded-lg p-3">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3 flex-1 min-w-0">
|
||||||
<div className="flex items-center justify-center w-10 h-10 bg-white/10 rounded-lg">
|
{/* Превью изображения или иконка */}
|
||||||
{message.type === 'IMAGE' ? (
|
{message.type === 'IMAGE' && message.fileUrl ? (
|
||||||
<Image className="h-5 w-5 text-blue-400" />
|
<div
|
||||||
) : message.type === 'VOICE' ? (
|
className="relative w-12 h-12 rounded-lg overflow-hidden cursor-pointer hover:opacity-80 transition-opacity"
|
||||||
<Music className="h-5 w-5 text-green-400" />
|
onClick={() => handleImageClick(message.fileUrl!, message.fileName, message.fileSize)}
|
||||||
) : (
|
>
|
||||||
renderFileIcon(message.fileType)
|
<img
|
||||||
)}
|
src={message.fileUrl}
|
||||||
</div>
|
alt={message.fileName || 'Изображение'}
|
||||||
<div>
|
className="w-full h-full object-cover"
|
||||||
<p className="text-white text-sm font-medium">
|
/>
|
||||||
|
<div className="absolute inset-0 bg-black/20 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
|
||||||
|
<Image className="h-4 w-4 text-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center w-10 h-10 bg-white/10 rounded-lg flex-shrink-0">
|
||||||
|
{message.type === 'VOICE' ? (
|
||||||
|
<Music className="h-5 w-5 text-green-400" />
|
||||||
|
) : (
|
||||||
|
renderFileIcon(message.fileType)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-white text-sm font-medium truncate">
|
||||||
{message.fileName ||
|
{message.fileName ||
|
||||||
(message.type === 'VOICE' ? 'Голосовое сообщение' :
|
(message.type === 'VOICE' ? 'Голосовое сообщение' :
|
||||||
message.type === 'IMAGE' ? 'Изображение' : 'Файл')}
|
message.type === 'IMAGE' ? 'Изображение' : 'Файл')}
|
||||||
@ -189,13 +215,17 @@ export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps
|
|||||||
{message.voiceDuration && (
|
{message.voiceDuration && (
|
||||||
<span>{Math.floor(message.voiceDuration / 60)}:{(message.voiceDuration % 60).toString().padStart(2, '0')}</span>
|
<span>{Math.floor(message.voiceDuration / 60)}:{(message.voiceDuration % 60).toString().padStart(2, '0')}</span>
|
||||||
)}
|
)}
|
||||||
|
{message.type === 'IMAGE' && (
|
||||||
|
<span className="text-blue-300">• Нажмите для просмотра</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDownload(message.fileUrl!, message.fileName || 'file')}
|
onClick={() => handleDownload(message.fileUrl!, message.fileName || 'file')}
|
||||||
className="flex items-center justify-center w-8 h-8 bg-white/10 hover:bg-white/20 rounded-lg transition-colors"
|
className="flex items-center justify-center w-8 h-8 bg-white/10 hover:bg-white/20 rounded-lg transition-colors flex-shrink-0 ml-2"
|
||||||
|
title="Скачать файл"
|
||||||
>
|
>
|
||||||
<Download className="h-4 w-4 text-white/70" />
|
<Download className="h-4 w-4 text-white/70" />
|
||||||
</button>
|
</button>
|
||||||
@ -273,7 +303,36 @@ export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
{imageMessages.map(renderAttachmentCard)}
|
{/* Сетка изображений для быстрого просмотра */}
|
||||||
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 mb-6">
|
||||||
|
{imageMessages.map((msg) => (
|
||||||
|
<div
|
||||||
|
key={`grid-${msg.id}`}
|
||||||
|
className="relative aspect-square rounded-lg overflow-hidden cursor-pointer hover:opacity-80 transition-opacity group"
|
||||||
|
onClick={() => handleImageClick(msg.fileUrl!, msg.fileName, msg.fileSize)}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={msg.fileUrl!}
|
||||||
|
alt={msg.fileName || 'Изображение'}
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-colors flex items-center justify-center">
|
||||||
|
<Image className="h-6 w-6 text-white opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||||
|
</div>
|
||||||
|
<div className="absolute bottom-2 left-2 right-2">
|
||||||
|
<div className="text-white text-xs truncate bg-black/50 px-2 py-1 rounded">
|
||||||
|
{formatDate(msg.createdAt)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Детальный список карточек */}
|
||||||
|
<div className="border-t border-white/10 pt-4">
|
||||||
|
<h4 className="text-white/80 text-sm font-medium mb-3">Детальная информация</h4>
|
||||||
|
{imageMessages.map(renderAttachmentCard)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
@ -310,6 +369,17 @@ export function MessengerAttachments({ counterparty }: MessengerAttachmentsProps
|
|||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Lightbox для просмотра изображений */}
|
||||||
|
{lightboxImage && (
|
||||||
|
<ImageLightbox
|
||||||
|
imageUrl={lightboxImage.url}
|
||||||
|
fileName={lightboxImage.fileName}
|
||||||
|
fileSize={lightboxImage.fileSize}
|
||||||
|
isOpen={true}
|
||||||
|
onClose={() => setLightboxImage(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
Reference in New Issue
Block a user