fix and update
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
extractFilesFromDataTransfer,
|
||||
useChatMediaComposer
|
||||
} from '@/components/chat/chat-media-compose-dialog';
|
||||
import { ChatImageLightbox } from '@/components/chat/chat-image-lightbox';
|
||||
import { ChatEmojiContent } from '@/components/chat/chat-emoji-content';
|
||||
import { ChatMessageContextMenu, ChatSelectionContextMenu, SelectableMessageWrapper } from '@/components/chat/chat-message-context-menu';
|
||||
import { ChatPinnedMessageBanner } from '@/components/chat/chat-pinned-message-banner';
|
||||
@@ -28,6 +29,7 @@ import { scrollToChatMessage } from '@/components/chat/replied-message-preview';
|
||||
import { useFamilyOverlay } from '@/components/family/family-overlay-provider';
|
||||
import { useAuth } from '@/components/id/auth-provider';
|
||||
import { UserAvatar } from '@/components/id/user-avatar';
|
||||
import { MediaImageSkeleton } from '@/components/ui/media-image-skeleton';
|
||||
import { useToast } from '@/components/id/toast-provider';
|
||||
import { useRealtime } from '@/components/notifications/realtime-provider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -74,6 +76,8 @@ import { shouldShowChatDateSeparator } from '@/lib/chat-date-utils';
|
||||
import { encryptE2EBlob, e2eKindFromMessageType } from '@/lib/e2e-chat';
|
||||
import { findMemberRoom, findOrCreateMemberChat, roomDisplayLabel } from '@/lib/family-chat';
|
||||
import { getE2EMessageText, useE2EChat } from '@/hooks/use-e2e-chat';
|
||||
import { useChatRoomMedia } from '@/hooks/use-chat-room-media';
|
||||
import { collectChatImageMessages } from '@/lib/chat-media-album';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface PresignedUploadResponse {
|
||||
@@ -87,7 +91,7 @@ function formatMessageTime(value: string) {
|
||||
return new Intl.DateTimeFormat('ru-RU', { hour: '2-digit', minute: '2-digit' }).format(new Date(value));
|
||||
}
|
||||
|
||||
function MiniChatImageMessage({ message, token }: { message: ChatMessage; token: string }) {
|
||||
function MiniChatEncryptedImageMessage({ message, token, onOpen }: { message: ChatMessage; token: string; onOpen?: () => void }) {
|
||||
const [src, setSrc] = useState<string | null>(null);
|
||||
const [failed, setFailed] = useState(false);
|
||||
const metadata = parseMessageMetadata(message.metadataJson) as { fileName?: string; width?: number; height?: number };
|
||||
@@ -146,12 +150,19 @@ function MiniChatImageMessage({ message, token }: { message: ChatMessage; token:
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
src={src}
|
||||
alt={message.content?.trim() || metadata.fileName || 'Фото в чате'}
|
||||
className="max-h-[260px] w-[190px] rounded-2xl object-cover shadow-sm"
|
||||
style={{ aspectRatio: metadata.width && metadata.height ? `${metadata.width} / ${metadata.height}` : undefined }}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="block overflow-hidden rounded-2xl shadow-sm"
|
||||
onClick={onOpen}
|
||||
disabled={!onOpen}
|
||||
>
|
||||
<img
|
||||
src={src}
|
||||
alt={message.content?.trim() || metadata.fileName || 'Фото в чате'}
|
||||
className="max-h-[260px] w-[190px] object-cover"
|
||||
style={{ aspectRatio: metadata.width && metadata.height ? `${metadata.width} / ${metadata.height}` : undefined }}
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -202,6 +213,7 @@ export function MiniFamilyChat() {
|
||||
const [chatToolsOpen, setChatToolsOpen] = useState(false);
|
||||
const [chatToolsTab, setChatToolsTab] = useState<ChatToolsTab>('search');
|
||||
const [mediaDropVisible, setMediaDropVisible] = useState(false);
|
||||
const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
|
||||
const mediaComposer = useChatMediaComposer();
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const autoScrollStateRef = useRef<{ id: string | null; count: number }>({ id: null, count: 0 });
|
||||
@@ -213,6 +225,13 @@ export function MiniFamilyChat() {
|
||||
() => messages.filter((message) => !message.isDeleted),
|
||||
[messages]
|
||||
);
|
||||
const chatImageMessages = useMemo(() => collectChatImageMessages(visibleMessages), [visibleMessages]);
|
||||
const { mediaUrls } = useChatRoomMedia(token, activeRoom?.id ?? null, visibleMessages);
|
||||
|
||||
function openImageLightbox(message: ChatMessage) {
|
||||
const index = chatImageMessages.findIndex((item) => item.id === message.id);
|
||||
if (index >= 0) setLightboxIndex(index);
|
||||
}
|
||||
const pinnedMessage = useMemo(
|
||||
() =>
|
||||
visibleMessages
|
||||
@@ -361,6 +380,7 @@ export function MiniFamilyChat() {
|
||||
setMessages([]);
|
||||
setBotMessages([]);
|
||||
setDraft('');
|
||||
setLightboxIndex(null);
|
||||
exitSelectionMode();
|
||||
setEmojiOpen(false);
|
||||
setPollOpen(false);
|
||||
@@ -1173,9 +1193,58 @@ export function MiniFamilyChat() {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : message.storageKey && message.type === 'IMAGE' && message.isEncrypted && token ? (
|
||||
<div className="space-y-1">
|
||||
<MiniChatEncryptedImageMessage
|
||||
message={message}
|
||||
token={token}
|
||||
onOpen={() => openImageLightbox(message)}
|
||||
/>
|
||||
{visibleText?.trim() ? (
|
||||
<div className="whitespace-pre-wrap break-words text-sm leading-relaxed">
|
||||
<ChatEmojiContent content={visibleText} size={18} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : message.storageKey && message.type === 'IMAGE' && token ? (
|
||||
<div className="space-y-1">
|
||||
<MiniChatImageMessage message={message} token={token} />
|
||||
{(() => {
|
||||
const media = message.storageKey ? mediaUrls[message.storageKey] : undefined;
|
||||
const meta = parseMessageMetadata(message.metadataJson) as {
|
||||
fileName?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
};
|
||||
if (!media?.blobUrl || media.status === 'loading') {
|
||||
const ratio =
|
||||
meta.width && meta.height
|
||||
? Math.max(0.65, Math.min(1.35, meta.height / meta.width))
|
||||
: 0.72;
|
||||
return (
|
||||
<div className="w-[190px]" style={{ height: Math.round(190 * ratio) }}>
|
||||
<MediaImageSkeleton className="h-full w-full min-h-0" rounded="2xl" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="block overflow-hidden rounded-2xl shadow-sm"
|
||||
onClick={() => openImageLightbox(message)}
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={media.blobUrl}
|
||||
alt={message.content?.trim() || meta.fileName || 'Фото в чате'}
|
||||
className="max-h-[260px] w-[190px] object-cover"
|
||||
style={{
|
||||
aspectRatio:
|
||||
meta.width && meta.height ? `${meta.width} / ${meta.height}` : undefined
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
})()}
|
||||
{visibleText?.trim() ? (
|
||||
<div className="whitespace-pre-wrap break-words text-sm leading-relaxed">
|
||||
<ChatEmojiContent content={visibleText} size={18} />
|
||||
@@ -1494,6 +1563,14 @@ export function MiniFamilyChat() {
|
||||
authToken={token}
|
||||
onClose={() => setMiniAppUrl(null)}
|
||||
/>
|
||||
<ChatImageLightbox
|
||||
open={lightboxIndex !== null}
|
||||
images={chatImageMessages}
|
||||
index={lightboxIndex ?? 0}
|
||||
mediaUrls={mediaUrls}
|
||||
onClose={() => setLightboxIndex(null)}
|
||||
onIndexChange={setLightboxIndex}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user