"use client" import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { apiClient } from "@/lib/api/client" import { driveFilesListApiPath, driveFilterCorpusApiPath } from "@/lib/api/drive-download" import { useAuthReady } from "@/lib/api/use-auth-ready" import type { DriveFileInfo, DriveListResponse, DriveQuota, DriveShare, ShareRecipientLookup } from "@/lib/api/types" import type { DriveShareMode } from "@/lib/drive/drive-share-types" function filesKey(path: string, page: number, q: string) { return ["drive", "files", path, page, q] as const } function filterCorpusKey(path: string) { return ["drive", "filter-corpus", path] as const } export function useDriveFilterCorpus(path: string, enabled = true) { const { ready, authenticated } = useAuthReady() const apiPath = driveFilterCorpusApiPath(path) return useQuery({ queryKey: filterCorpusKey(path), enabled: ready && authenticated && enabled, staleTime: 60_000, queryFn: () => apiClient.get(apiPath), }) } export function useDriveList(path: string, page = 1, q = "", enabled = true) { const { ready, authenticated } = useAuthReady() const apiPath = driveFilesListApiPath(path) return useQuery({ queryKey: filesKey(path, page, q), enabled: ready && authenticated && enabled, queryFn: () => apiClient.get(`${apiPath}?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}`), }) } export function useDriveFileById(fileId: string, enabled = true) { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "file", fileId], enabled: ready && authenticated && enabled && Boolean(fileId), staleTime: 30_000, queryFn: () => apiClient.get(`/drive/files/id/${encodeURIComponent(fileId)}`), }) } export function useDriveSharedWithMe(page = 1, q = "", enabled = true) { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "shared", page, q], enabled: ready && authenticated && enabled, queryFn: () => apiClient.get( `/drive/shared?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}` ), }) } export function useDriveTrash(page = 1, q = "") { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "trash", page, q], enabled: ready && authenticated, queryFn: () => apiClient.get(`/drive/trash?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}`), }) } export function useDriveRecent() { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "recent"], enabled: ready && authenticated, retry: 1, queryFn: () => apiClient.get("/drive/recent?page_size=50"), }) } export function useDriveStarred(path = "/") { const { ready, authenticated } = useAuthReady() const suffix = path === "/" ? "" : path return useQuery({ queryKey: ["drive", "starred", path], enabled: ready && authenticated, queryFn: () => apiClient.get(`/drive/starred${suffix}?page_size=50`), }) } function searchKey(q: string, scope: string, path: string, page: number, suggest: boolean) { return ["drive", "search", q, scope, path, page, suggest] as const } export function useDriveSearch( q: string, scope: string, path: string, page = 1, enabled = true ) { const { ready, authenticated } = useAuthReady() const trimmed = q.trim() return useQuery({ queryKey: searchKey(trimmed, scope, path, page, false), enabled: ready && authenticated && enabled && trimmed.length > 0, queryFn: () => { const params = new URLSearchParams({ q: trimmed, scope, page: String(page), page_size: "50", }) if (scope === "folder" && path !== "/") { params.set("path", path) } return apiClient.get(`/drive/search?${params.toString()}`) }, }) } export function useDriveSearchSuggestions( q: string, scope: string, path: string, enabled = true ) { const { ready, authenticated } = useAuthReady() const trimmed = q.trim() return useQuery({ queryKey: searchKey(trimmed, scope, path, 1, true), enabled: ready && authenticated && enabled && trimmed.length >= 2, staleTime: 30_000, queryFn: () => { const params = new URLSearchParams({ q: trimmed, scope, suggest: "1", page_size: "8", }) if (scope === "folder" && path !== "/") { params.set("path", path) } return apiClient.get(`/drive/search?${params.toString()}`) }, }) } export function useDriveQuota() { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "quota"], enabled: ready && authenticated, retry: 1, queryFn: () => apiClient.get("/drive/quota"), }) } export function useDriveShares(filePath: string, enabled: boolean) { const { ready, authenticated } = useAuthReady() return useQuery({ queryKey: ["drive", "shares", filePath], enabled: ready && authenticated && enabled && Boolean(filePath), queryFn: () => apiClient.get<{ shares: DriveShare[] }>(`/drive/shares?path=${encodeURIComponent(filePath)}`), }) } export function useDriveMutations() { const qc = useQueryClient() const invalidate = () => qc.invalidateQueries({ queryKey: ["drive"] }) const createFolder = useMutation({ mutationFn: (path: string) => apiClient.post(`/drive/folders${path}`, {}), onSuccess: invalidate, }) const deleteFile = useMutation({ mutationFn: (path: string) => apiClient.delete(`/drive/files${path}`), onSuccess: invalidate, }) const rename = useMutation({ mutationFn: (body: { path: string; new_name: string }) => apiClient.post("/drive/rename", body), onSuccess: invalidate, }) const move = useMutation({ mutationFn: (body: { source: string; destination: string }) => apiClient.post("/drive/move", body), onSuccess: invalidate, }) const copy = useMutation({ mutationFn: (body: { source: string; destination: string }) => apiClient.post("/drive/copy", body), onSuccess: invalidate, }) const favorite = useMutation({ mutationFn: (body: { path: string; favorite: boolean }) => apiClient.post("/drive/favorite", body), onSuccess: invalidate, }) const restore = useMutation({ mutationFn: (name: string) => apiClient.post("/drive/trash/restore", { name }), onSuccess: invalidate, }) const deleteTrash = useMutation({ mutationFn: (name: string) => apiClient.post("/drive/trash/delete", { name }), onSuccess: invalidate, }) const emptyTrash = useMutation({ mutationFn: () => apiClient.delete("/drive/trash"), onSuccess: invalidate, }) const createShare = useMutation({ mutationFn: (body: { path: string mode?: DriveShareMode role?: string permissions?: number share_type?: number share_with?: string note?: string send_mail?: boolean }) => apiClient.post("/drive/shares", { path: body.path, mode: body.mode ?? "public", ...(body.mode === "contact" ? { share_with: body.share_with, note: body.note, send_mail: body.send_mail ?? true, } : body.mode === "internal" ? { share_type: 3 } : { share_type: body.share_type ?? 3 }), ...(body.permissions != null && body.permissions > 0 ? { permissions: body.permissions } : { role: body.role ?? "viewer" }), }), onSuccess: (_data, variables) => { qc.invalidateQueries({ queryKey: ["drive"] }) if (variables.path) { qc.invalidateQueries({ queryKey: ["drive", "shares", variables.path] }) } }, }) const deleteShare = useMutation({ mutationFn: (shareId: string) => apiClient.delete(`/drive/shares/${shareId}`), onSuccess: invalidate, }) const lookupShareRecipient = useMutation({ mutationFn: (email: string) => apiClient.get( `/drive/shares/recipients/lookup?email=${encodeURIComponent(email)}` ), }) const createFile = useMutation({ mutationFn: (body: { parent_path: string; name: string; kind: string }) => apiClient.post<{ path: string }>("/office/create", body), onSuccess: invalidate, }) return { createFolder, deleteFile, rename, move, copy, favorite, restore, deleteTrash, emptyTrash, createShare, deleteShare, lookupShareRecipient, createFile, invalidate } } /** @deprecated Use openDriveFileInNewTab / downloadDriveFile — API requires Authorization. */ export function fileDownloadUrl(path: string): string { const base = process.env.NEXT_PUBLIC_API_URL ?? "/api/v1" return `${base}/drive/download${path.startsWith("/") ? path : `/${path}`}` } export type { DriveFileInfo }