fix and update
This commit is contained in:
113
apps/frontend/components/admin/use-admin-chat-media.ts
Normal file
113
apps/frontend/components/admin/use-admin-chat-media.ts
Normal 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 };
|
||||
}
|
||||
Reference in New Issue
Block a user