import { getDocumentIconType, getSourceType, } from '../../AttachmentCard/utils/mimeType' /** * Format a byte count as a short human-readable string (`'379.5 KB'`). * Mirrors the meta line shown next to file attachments in the mobile chat * design — `EXT · SIZE`, e.g. `PDF · 379.5 KB`. */ export function formatFileSize(bytes: number): string { if (!Number.isFinite(bytes) || bytes < 0) return '' if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(2)} MB` return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB` } const EXTENSION_LABEL_BY_DOCUMENT_TYPE: Record = { pdf: 'PDF', doc: 'DOC', xls: 'XLS', csv: 'CSV', ppt: 'PPT', zip: 'ZIP', text: 'TXT', markdown: 'MD', } /** * Returns the short uppercase extension label shown in the meta line of * compact document / file attachments. Prefers the filename extension * when present (matches the mobile design which trusts the filename), * and falls back to a label derived from the MIME type. */ export function getFileExtensionLabel( mimeType?: string, filename?: string ): string | undefined { if (filename) { const lastDot = filename.lastIndexOf('.') if (lastDot > 0 && lastDot < filename.length - 1) { const ext = filename.slice(lastDot + 1) if (ext && ext.length <= 5) return ext.toUpperCase() } } if (!mimeType) return undefined const sourceType = getSourceType(mimeType) if (sourceType === 'document') { const docType = getDocumentIconType(mimeType) const docLabel = EXTENSION_LABEL_BY_DOCUMENT_TYPE[docType] if (docLabel) return docLabel if (mimeType === 'application/octet-stream') return undefined } const subtype = mimeType.split('/')[1] if (!subtype || subtype === '*') return undefined return subtype.toUpperCase() } /** * Build the meta line shown under the title in compact document / file * attachments — `EXT · SIZE` (`PDF · 379.5 KB`). Either part is dropped * when not available so audio / generic files still get a useful label. */ export function buildCompactMetaLabel( mimeType?: string, filename?: string, fileSize?: number ): string | undefined { const ext = getFileExtensionLabel(mimeType, filename) const size = typeof fileSize === 'number' && fileSize > 0 ? formatFileSize(fileSize) : undefined return [ext, size].filter(Boolean).join(' · ') || undefined } /** * Derive a sensible filename from a URL — used as the fallback save name * when the attachment has no `filename` set. Returns `'download'` for * URLs we can't parse. */ export function filenameFromUrl(url: string): string { try { const parsed = new URL(url) const last = parsed.pathname.split('/').pop() return last && last.length > 0 ? decodeURIComponent(last) : 'download' } catch { return 'download' } }