"use client" import dynamic from "next/dynamic" import Link from "next/link" import { useRouter } from "next/navigation" import { useEffect, useState, type ReactNode } from "react" import { ChevronRight, Download, FolderOpen, Loader2, Lock } from "lucide-react" import { toast } from "sonner" import { PublicShareFolderView } from "@/components/drive/public-share-folder-view" import { FilePreviewDialog } from "@/components/drive/file-preview-dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { fetchPublicShareBlob, publicShareDownloadApiPath, publicShareHref, publicShareOwnerLabel, type PublicShareView, } from "@/lib/api/public-share" import type { DriveFileInfo } from "@/lib/api/types" import { drivePreviewKind, isSvgFile } from "@/lib/drive/drive-preview" import { SvgPreviewViewer } from "@/components/drive/svg-preview-viewer" import { PUBLIC_SHARE_INSET_X } from "@/lib/drive/drive-chrome-classes" import { shouldOpenInOnlyOffice, shouldOpenInRichTextEditor } from "@/lib/drive/drive-preview" import { sharePermCanEdit, } from "@/lib/drive/drive-share-permissions" import { buildPublicShareEditHref, persistPublicShareRootType } from "@/lib/drive/public-share-url" import { suitePublicAsset } from "@/lib/suite/suite-public-asset" import { SuiteThemeShell } from "@/components/suite/suite-theme-shell" import { cn } from "@/lib/utils" import { filterHiddenDriveSidecars } from "@/lib/drive/drive-hidden-files" const PdfPreviewViewer = dynamic( () => import("@/components/drive/pdf-preview-viewer").then((m) => m.PdfPreviewViewer), { ssr: false } ) function PublicShareBreadcrumb({ token, rootShareName, path, }: { token: string rootShareName: string path: string }) { const parts = path.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean) const crumbs: { label: string; href: string }[] = [ { label: rootShareName || "Partage", href: publicShareHref(token) }, ] let acc = "" for (const part of parts) { acc += `/${part}` crumbs.push({ label: part, href: publicShareHref(token, acc) }) } return ( ) } function usePublicShareRootName(token: string, path: string, currentName: string) { const storageKey = `public-share-root:${token}` const [rootName, setRootName] = useState(currentName) useEffect(() => { if (typeof window === "undefined") return if (path === "/" && currentName) { sessionStorage.setItem(storageKey, currentName) setRootName(currentName) return } const stored = sessionStorage.getItem(storageKey) if (stored) setRootName(stored) }, [token, path, currentName, storageKey]) return rootName } function PublicFilePreview({ token, file, password, }: { token: string file: DriveFileInfo password?: string }) { const [blobUrl, setBlobUrl] = useState(null) const [textContent, setTextContent] = useState(null) const [svgMarkup, setSvgMarkup] = useState(null) const [loading, setLoading] = useState(true) const kind = drivePreviewKind(file) const isSvg = isSvgFile(file) useEffect(() => { let cancelled = false let objectUrl: string | null = null setLoading(true) void fetchPublicShareBlob(token, file, password) .then(async (blob) => { if (cancelled) return if (kind === "text") { setTextContent(await blob.text()) setBlobUrl(null) setSvgMarkup(null) } else if (isSvg) { setSvgMarkup(await blob.text()) setBlobUrl(null) setTextContent(null) } else { objectUrl = URL.createObjectURL(blob) setBlobUrl(objectUrl) setTextContent(null) setSvgMarkup(null) } }) .catch(() => toast.error("Aperçu indisponible")) .finally(() => { if (!cancelled) setLoading(false) }) return () => { cancelled = true if (objectUrl) URL.revokeObjectURL(objectUrl) } }, [token, file, password, kind, isSvg]) if (loading) { return (
) } if (isSvg && svgMarkup) { return (
) } if (kind === "image" && blobUrl) { return (
{/* eslint-disable-next-line @next/next/no-img-element */} {file.name}
) } if (kind === "video" && blobUrl) { return (
) } if (kind === "audio" && blobUrl) { return (
) } if (kind === "pdf" && blobUrl) { return (
) } if (kind === "text" && textContent != null) { return (
        {textContent}
      
) } return (

Aperçu non disponible pour ce type de fichier.

) } export function PublicShareViewPanel({ token, path, data, password, }: { token: string path: string data: PublicShareView password?: string }) { const router = useRouter() const file = data.item_type === "file" ? data.file : null const files = data.item_type === "folder" ? filterHiddenDriveSidecars(data.files ?? []) : [] const rootShareName = usePublicShareRootName(token, path, data.name) const sharedByLabel = publicShareOwnerLabel(data) const permissions = data.permissions ?? 1 const canEdit = sharePermCanEdit(permissions) useEffect(() => { persistPublicShareRootType(token, data.item_type) }, [token, data.item_type]) useEffect(() => { if (!file) return const isEditorFile = shouldOpenInRichTextEditor(file) || shouldOpenInOnlyOffice(file) if (!isEditorFile) return const returnTo = typeof window !== "undefined" ? window.location.pathname + window.location.search : undefined const editor = shouldOpenInRichTextEditor(file) ? "richtext" : "office" router.replace( buildPublicShareEditHref( token, file.path, returnTo, canEdit ? "edit" : "view", file.name, editor, data.item_type ) ) }, [canEdit, data.item_type, file, router, token]) const downloadCurrent = () => { if (!file) return const url = publicShareDownloadApiPath(token, file.path, password) const anchor = document.createElement("a") anchor.href = url anchor.download = file.name anchor.rel = "noopener" document.body.appendChild(anchor) anchor.click() anchor.remove() } if (file && (shouldOpenInRichTextEditor(file) || shouldOpenInOnlyOffice(file))) { return (
) } return (

Partagé par {sharedByLabel}

{data.item_type === "folder" ? ( ) : null}
{file ? ( ) : null}
{data.item_type === "folder" ? ( ) : file ? ( ) : null}
) } export function PublicShareChrome({ children }: { children: ReactNode }) { return (
UltiDrive Lien de partage
{children}
) }