ultisuite-client/lib/hooks/use-inline-cid-urls.ts
2026-05-25 13:52:40 +02:00

68 lines
2.0 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import { useAuthStore } from "@/lib/api/auth-store"
function attachmentInlineUrl(attachmentId: string): string {
const base = process.env.NEXT_PUBLIC_API_URL ?? "/api/v1"
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base
return `${normalizedBase}/mail/attachments/${encodeURIComponent(attachmentId)}/inline`
}
function normalizeCidKey(raw: string): string {
const trimmed = raw.trim()
if (trimmed.toLowerCase().startsWith("cid:")) {
return trimmed.slice(4).trim()
}
return trimmed
}
/** Fetches inline attachment blobs and exposes blob: URLs keyed by cid (with or without cid: prefix). */
export function useInlineCidUrls(cidMap: Record<string, string> | undefined) {
const accessToken = useAuthStore((s) => s.accessToken)
const [urls, setUrls] = useState<Record<string, string>>({})
useEffect(() => {
if (!accessToken || !cidMap || Object.keys(cidMap).length === 0) {
setUrls({})
return
}
let cancelled = false
const objectUrls: string[] = []
void (async () => {
const next: Record<string, string> = {}
for (const [contentId, attachmentId] of Object.entries(cidMap)) {
if (!attachmentId) continue
try {
const res = await fetch(attachmentInlineUrl(attachmentId), {
headers: { Authorization: `Bearer ${accessToken}` },
})
if (!res.ok) continue
const blob = await res.blob()
const blobUrl = URL.createObjectURL(blob)
objectUrls.push(blobUrl)
const key = normalizeCidKey(contentId)
next[key] = blobUrl
next[`cid:${key}`] = blobUrl
} catch {
// skip broken inline parts
}
}
if (!cancelled) {
setUrls(next)
} else {
for (const u of objectUrls) URL.revokeObjectURL(u)
}
})()
return () => {
cancelled = true
for (const u of objectUrls) URL.revokeObjectURL(u)
}
}, [accessToken, cidMap])
return urls
}