ultisuite-client/lib/attachment-display.ts
R3D347HR4Y 6ec95262af Add OnlyOffice integration and update project configurations
- Updated .env.example to include configuration for OnlyOffice Document Server.
- Modified the workspace configuration to remove the drive-suite path.
- Adjusted TypeScript environment imports for consistency.
- Enhanced Next.js configuration to disable canvas in Webpack.
- Updated package.json to include new dependencies for OnlyOffice and PDF.js.
- Added global styles for OnlyOffice theme integration in the CSS.
- Created new layout and page components for the Drive feature, including public sharing and editing functionalities.
- Updated metadata handling across various layouts to reflect the new app structure.
2026-06-07 15:49:21 +02:00

117 lines
4.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Email, EmailAttachment, EmailAttachmentKind } from "@/lib/email-data"
/** Pièce jointe calendrier (invitation) — masquée dans la liste des messages. */
export function isCalendarInvitationAttachment(name: string): boolean {
return name.toLowerCase().endsWith(".ics")
}
/** PJ visibles dans la liste (hors fichiers .ics dinvitation). */
export function attachmentsForEmailList(
email: Pick<Email, "attachments" | "hasAttachment" | "hasInvitation">
): EmailAttachment[] {
if (email.attachments?.length) {
return email.attachments.filter((a) => !isCalendarInvitationAttachment(a.name))
}
if (email.hasAttachment && email.hasInvitation !== true) {
return [{ name: "Pièce jointe", kind: "other" }]
}
return []
}
/** Aperçu message : uniquement des PJ avec métadonnées réelles (jamais de chip générique). */
export function resolvePreviewAttachments(
email: Pick<Email, "attachments" | "hasAttachment" | "hasInvitation">,
fetched: EmailAttachment[] | undefined,
fetchState: "idle" | "loading" | "done"
): EmailAttachment[] {
if (email.attachments?.length) {
return attachmentsForEmailList(email)
}
if (fetched?.length) {
return attachmentsForEmailList({ ...email, attachments: fetched })
}
if (email.hasAttachment && fetchState === "loading") {
return []
}
return []
}
/** Liste : noms réels si fetch OK ; pas de chip générique pendant le chargement. */
export function resolveListRowAttachments(
email: Pick<Email, "attachments" | "hasAttachment" | "hasInvitation">,
fetched: EmailAttachment[] | undefined,
fetchState: "idle" | "loading" | "done"
): EmailAttachment[] {
if (email.attachments?.length) {
return attachmentsForEmailList(email)
}
if (fetched?.length) {
return attachmentsForEmailList({ ...email, attachments: fetched })
}
if (email.hasAttachment && fetchState === "loading") {
return []
}
return attachmentsForEmailList(email)
}
/** Fichiers « riches » (cartes type Gmail) : PDF, images, vidéos, bureautique. */
const RICH_PREVIEW_EXT =
/\.(mp4|mpe?g|webm|mov|avi|mkv|m4v|wmv|flv|xls|xlsx|xlsm|ods|numbers|ppt|pptx|key|odp|doc|docx|odt|rtf)$/i
/** Seuil « petit fichier » pour la rangée en pills (aperçu message uniquement). */
export const ATTACHMENT_PILL_MAX_BYTES = 2 * 1024 * 1024
export function resolveAttachmentKind(
name: string,
kind?: EmailAttachment["kind"]
): EmailAttachmentKind {
if (kind) return kind
const lower = name.toLowerCase()
if (lower.endsWith(".pdf")) return "pdf"
if (/\.(png|jpe?g|gif|webp|svg|avif|bmp|heic)$/.test(lower)) return "image"
return "other"
}
export function isRichPreviewAttachment(name: string, kind?: EmailAttachment["kind"]): boolean {
const resolved = resolveAttachmentKind(name, kind)
if (resolved === "pdf" || resolved === "image") return true
return RICH_PREVIEW_EXT.test(name.toLowerCase())
}
export function isSmallEnoughForPillRow(sizeBytes?: number): boolean {
if (sizeBytes === undefined) return true
return sizeBytes >= 0 && sizeBytes <= ATTACHMENT_PILL_MAX_BYTES
}
/** Tous les fichiers simples + petits → UI pills dans laperçu message. */
export function shouldUseAttachmentPillsInPreview(attachments: EmailAttachment[]): boolean {
if (attachments.length === 0) return false
return attachments.every(
(a) => !isRichPreviewAttachment(a.name, a.kind) && isSmallEnoughForPillRow(a.sizeBytes)
)
}
function decFr(n: number): string {
return String(n).replace(".", ",")
}
export function formatAttachmentSize(sizeBytes: number): string {
if (!Number.isFinite(sizeBytes) || sizeBytes < 0) return "—"
if (sizeBytes < 1000) {
return `${Math.round(sizeBytes)}\u00a0o`
}
const kb = sizeBytes / 1024
if (kb < 1024) {
const v = kb >= 10 ? Math.round(kb) : Math.round(kb * 10) / 10
return `${decFr(v)}\u00a0Ko`
}
const mb = kb / 1024
const v = mb >= 10 ? Math.round(mb) : Math.round(mb * 10) / 10
return `${decFr(v)}\u00a0Mo`
}
export function attachmentPreviewTooltip(name: string, sizeBytes?: number): string {
if (sizeBytes === undefined) return name
return `${name}\n${formatAttachmentSize(sizeBytes)}`
}