fix and update

This commit is contained in:
lendry
2026-07-01 19:19:27 +03:00
parent f423f512f8
commit 7e54cec361
16 changed files with 1093 additions and 150 deletions

View File

@@ -0,0 +1,113 @@
'use client';
import { useCallback, useEffect, useRef, useState } from 'react';
import { AdminChatMessage, ChatMessage, fetchChatMediaUrl } from '@/lib/api';
import { createBlobObjectUrl, fetchAuthenticatedMediaBlob, revokeBlobObjectUrl } from '@/lib/authenticated-media';
import { parseChatMediaMetadata } from '@/lib/chat-media-album';
export type AdminChatMediaEntry = {
blobUrl?: string;
fileName?: string;
mimeType?: string;
status?: 'loading' | 'ready' | 'error';
errorMessage?: string;
};
export function adminMessageToChatMessage(message: AdminChatMessage, roomId: string): ChatMessage {
return {
id: message.id,
roomId: message.roomId ?? roomId,
senderId: message.senderId,
senderName: message.senderName,
senderHasAvatar: false,
type: message.type,
content: message.content ?? undefined,
storageKey: message.storageKey,
mimeType: message.mimeType,
metadataJson: message.metadataJson,
createdAt: message.createdAt,
editedAt: message.editedAt,
isDeleted: message.isDeleted,
isEncrypted: message.isEncrypted
};
}
export function useAdminChatMedia(token: string | null, roomId: string | null, messages: AdminChatMessage[]) {
const [mediaUrls, setMediaUrls] = useState<Record<string, AdminChatMediaEntry>>({});
const mediaUrlsRef = useRef<Record<string, AdminChatMediaEntry>>({});
const inFlightRef = useRef(new Set<string>());
useEffect(() => {
mediaUrlsRef.current = mediaUrls;
}, [mediaUrls]);
const loadMedia = useCallback(
async (message: AdminChatMessage, force = false) => {
if (!token || !roomId || !message.storageKey || message.isEncrypted || message.isDeleted) return;
const storageKey = message.storageKey;
const existing = mediaUrlsRef.current[storageKey];
if (!force && existing?.status === 'ready' && existing.blobUrl) {
return;
}
if (inFlightRef.current.has(storageKey) && !force) {
return;
}
inFlightRef.current.add(storageKey);
setMediaUrls((current) => ({
...current,
[storageKey]: { ...current[storageKey], status: 'loading', errorMessage: undefined }
}));
const meta = parseChatMediaMetadata(message.metadataJson);
const fileName = meta.fileName || message.content || undefined;
try {
const access = await fetchChatMediaUrl(roomId, storageKey, token, fileName);
const blob = await fetchAuthenticatedMediaBlob(access.accessUrl, token, message.mimeType);
const blobUrl = createBlobObjectUrl(blob);
setMediaUrls((current) => {
revokeBlobObjectUrl(current[storageKey]?.blobUrl);
return {
...current,
[storageKey]: {
blobUrl,
fileName,
mimeType: message.mimeType,
status: 'ready'
}
};
});
} catch (error) {
setMediaUrls((current) => ({
...current,
[storageKey]: {
...current[storageKey],
status: 'error',
errorMessage: error instanceof Error ? error.message : 'Не удалось загрузить файл'
}
}));
} finally {
inFlightRef.current.delete(storageKey);
}
},
[roomId, token]
);
useEffect(() => {
if (!token || !roomId) return;
messages.forEach((message) => {
if (message.storageKey && message.type === 'IMAGE') {
void loadMedia(message);
}
});
}, [loadMedia, messages, roomId, token]);
useEffect(() => {
return () => {
Object.values(mediaUrlsRef.current).forEach((entry) => revokeBlobObjectUrl(entry.blobUrl));
};
}, []);
return { mediaUrls, loadMedia };
}