ultisuite-client/lib/hooks/use-drive-new-menu.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

155 lines
4.6 KiB
TypeScript

"use client"
import { useMemo, useState } from "react"
import { useRouter } from "next/navigation"
import { useQueryClient } from "@tanstack/react-query"
import { toast } from "sonner"
import { useDriveList, useDriveMutations } from "@/lib/api/hooks/use-drive-queries"
import { uploadFile } from "@/lib/api/upload"
import { nextUntitledName } from "@/lib/drive/drive-default-name"
import { buildDriveEditHref } from "@/lib/drive/drive-url"
export type DriveNewKind = "document" | "spreadsheet" | "presentation" | "folder"
export const DRIVE_NEW_KIND_META: Record<
DriveNewKind,
{ ext: string; typeLabel: string; menuLabel: string }
> = {
document: { ext: ".docx", typeLabel: "Document", menuLabel: "Document" },
spreadsheet: { ext: ".xlsx", typeLabel: "Tableur", menuLabel: "Tableur" },
presentation: { ext: ".pptx", typeLabel: "Présentation", menuLabel: "Présentation" },
folder: { ext: "", typeLabel: "Dossier", menuLabel: "Dossier" },
}
export const DRIVE_NEW_MENU_ITEM_CLASS =
"gap-3 rounded-md py-2.5 pr-3 pl-3 text-[15px] focus:bg-accent/80 [&_svg]:size-5"
async function importFolderTree(
files: FileList,
parentPath: string,
createFolder: ReturnType<typeof useDriveMutations>["createFolder"]
) {
const base = parentPath === "/" ? "" : parentPath
const created = new Set<string>()
const ensureDir = async (dirPath: string) => {
if (created.has(dirPath)) return
try {
await createFolder.mutateAsync(dirPath)
} catch {
/* dossier peut déjà exister */
}
created.add(dirPath)
}
for (const file of Array.from(files)) {
const rel = file.webkitRelativePath
if (!rel) continue
const segments = rel.split("/")
const name = segments.pop()
if (!name) continue
let dirAcc = base
for (const segment of segments) {
dirAcc = `${dirAcc}/${segment}`
await ensureDir(dirAcc)
}
await uploadFile(`${dirAcc}/${name}`, file)
}
}
export function useDriveNewMenu(parentPath: string) {
const router = useRouter()
const queryClient = useQueryClient()
const { createFolder, createFile } = useDriveMutations()
const base = parentPath === "/" ? "" : parentPath
const list = useDriveList(parentPath)
const siblingNames = useMemo(
() => (list.data?.files ?? []).map((f) => f.name),
[list.data?.files]
)
const [pendingKind, setPendingKind] = useState<DriveNewKind | null>(null)
const refresh = () => queryClient.invalidateQueries({ queryKey: ["drive"] })
const pendingMeta = pendingKind ? DRIVE_NEW_KIND_META[pendingKind] : null
const defaultName =
pendingMeta && pendingKind
? nextUntitledName(siblingNames, pendingMeta.typeLabel, pendingMeta.ext)
: ""
const confirmNew = async (rawName: string) => {
if (!pendingKind || !pendingMeta) return
const name = rawName.trim().replace(/\//g, "")
if (!name) return
if (pendingKind === "folder") {
try {
await createFolder.mutateAsync(`${base}/${name}`)
toast.success("Dossier créé")
await refresh()
} catch {
toast.error("Impossible de créer le dossier")
throw new Error("folder create failed")
}
return
}
const fileName = name.endsWith(pendingMeta.ext) ? name : name + pendingMeta.ext
try {
const { path } = await createFile.mutateAsync({
parent_path: parentPath,
name: fileName,
kind: pendingKind,
})
toast.success("Fichier créé")
const returnTo =
typeof window !== "undefined"
? window.location.pathname + window.location.search
: undefined
router.push(buildDriveEditHref(path, returnTo))
} catch {
toast.error("Impossible de créer le fichier")
throw new Error("file create failed")
}
}
const uploadFiles = async (files: FileList | null) => {
if (!files?.length) return
for (const file of Array.from(files)) {
try {
await uploadFile(`${base}/${file.name}`, file)
} catch {
toast.error(`Échec : ${file.name}`)
}
}
await refresh()
toast.success("Import terminé")
}
const importFolder = async (files: FileList | null) => {
if (!files?.length) return
try {
await importFolderTree(files, parentPath, createFolder)
await refresh()
toast.success("Dossier importé")
} catch {
toast.error("Impossible d'importer le dossier")
}
}
const pickKind = (kind: DriveNewKind) => setPendingKind(kind)
const closeNameDialog = () => setPendingKind(null)
return {
pendingKind,
pendingMeta,
defaultName,
confirmNew,
uploadFiles,
importFolder,
pickKind,
closeNameDialog,
}
}