"use client" import type { ReactNode } from "react" import { toast } from "sonner" import { CheckSquare, Copy, Download, ExternalLink, FolderInput, Link2, Pencil, Star, Trash2, Undo2, } from "lucide-react" import { Icon } from "@iconify/react" import { ContextMenuItem, } from "@/components/ui/context-menu" import { DropdownMenuItem, } from "@/components/ui/dropdown-menu" import type { useDriveMutations } from "@/lib/api/hooks/use-drive-queries" import type { DriveFileInfo } from "@/lib/api/types" import { guardDriveMenuPointer, stopDriveMenuEvent, } from "@/lib/drive/drive-menu-guard" import { cn } from "@/lib/utils" import { driveTrashItemKey } from "@/lib/drive/drive-trash" import { mountCloudSuiteBrand } from "@/lib/drive/cloud-native-open" export const DRIVE_MENU_ITEM_CLASS = "gap-3 py-2 text-[#3c4043] focus:text-[#3c4043] dark:text-[#e8eaed] dark:focus:text-[#e8eaed] [&_svg]:text-[#3c4043] dark:[&_svg]:text-[#e8eaed]" export const DRIVE_MENU_ITEM_DESTRUCTIVE_CLASS = "gap-3 py-2 text-destructive focus:text-destructive [&_svg]:text-destructive" const SHEET_ACTION_CLASS = "flex w-full items-center gap-3 px-4 py-3 text-left text-sm text-[#3c4043] transition-colors hover:bg-accent active:bg-accent/80 dark:text-[#e8eaed] [&_svg]:text-[#3c4043] dark:[&_svg]:text-[#e8eaed]" export function canShareDriveItem(item: DriveFileInfo) { return item.type === "file" || item.type === "directory" } function DriveMenuItemIcon({ children }: { children: ReactNode }) { return ( {children} ) } type Mutations = ReturnType type DriveFileMenuActionsProps = { variant: "dropdown" | "context" | "sheet" targets: DriveFileInfo[] isTrash?: boolean allowShare?: boolean /** When false, hide rename / move / copy / delete. */ writable?: boolean /** When true, hide the "Ouvrir" action (e.g. current folder in breadcrumb). */ hideOpen?: boolean /** When false, hide favorite actions (public share). */ hideFavorite?: boolean onOpen: () => void onClose?: () => void setSharePath: (path: string | null, itemType?: "file" | "directory" | null) => void mutations: Mutations onRenameRequest: () => void onMoveRequest?: () => void onCopyRequest?: () => void onDownloadRequest?: () => void onQuickLinkRequest?: () => void onEnterSelectionMode?: () => void } export function DriveFileMenuActions({ variant, targets, isTrash, allowShare = true, writable = true, hideOpen = false, hideFavorite = false, onOpen, onClose, setSharePath, mutations, onRenameRequest, onMoveRequest, onCopyRequest, onDownloadRequest, onQuickLinkRequest, onEnterSelectionMode, }: DriveFileMenuActionsProps) { const single = targets.length === 1 ? targets[0]! : null const multi = targets.length > 1 const mountSuiteBrand = single ? mountCloudSuiteBrand(single) : null const runAsync = async (fn: () => Promise, ok: string, err: string) => { onClose?.() try { await fn() toast.success(ok) } catch { toast.error(err) } } const runMenuAction = ( fn: () => void, asyncFn?: () => Promise, ok?: string, err?: string ) => { guardDriveMenuPointer() onClose?.() if (asyncFn && ok && err) { void runAsync(asyncFn, ok, err) return } fn() } const selectAction = (fn: () => void) => () => { guardDriveMenuPointer() onClose?.() window.setTimeout(fn, 0) } const favoriteLabel = targets.every((f) => f.is_favorite) ? "Retirer des favoris" : "Ajouter aux favoris" const favoriteAsync = async () => { for (const f of targets) { await mutations.favorite.mutateAsync({ path: f.path, favorite: !f.is_favorite, }) } } const deleteAsync = async () => { for (const f of targets) { await mutations.deleteFile.mutateAsync(f.path) } } const restoreAsync = async () => { for (const f of targets) { await mutations.restore.mutateAsync(driveTrashItemKey(f)) } } const deleteTrashAsync = async () => { for (const f of targets) { await mutations.deleteTrash.mutateAsync(driveTrashItemKey(f)) } } const actions: Array<{ key: string label: string icon: ReactNode destructive?: boolean visible: boolean onSelect: () => void }> = [ { key: "open", label: mountSuiteBrand?.label ?? "Ouvrir", icon: mountSuiteBrand ? ( ) : ( ), visible: !hideOpen && !multi && Boolean(single), onSelect: () => runMenuAction(() => window.setTimeout(() => onOpen(), 0)), }, { key: "select", label: "Sélectionner", icon: , visible: variant === "sheet" && Boolean(!isTrash && single && onEnterSelectionMode), onSelect: () => runMenuAction(() => { window.setTimeout(() => onEnterSelectionMode?.(), 0) }), }, { key: "share", label: "Partager", icon: , visible: Boolean(!isTrash && allowShare && !multi && single && canShareDriveItem(single)), onSelect: () => runMenuAction(() => setSharePath(single!.path, single!.type)), }, { key: "copy", label: multi ? `Copier vers (${targets.length})` : "Copier vers", icon: , visible: Boolean(writable && !isTrash && onCopyRequest), onSelect: () => runMenuAction(() => { window.setTimeout(() => onCopyRequest?.(), 0) }), }, { key: "move", label: multi ? `Déplacer vers (${targets.length})` : "Déplacer vers", icon: , visible: Boolean(writable && !isTrash && onMoveRequest), onSelect: () => runMenuAction(() => { window.setTimeout(() => onMoveRequest?.(), 0) }), }, { key: "download", label: "Télécharger", icon: , visible: Boolean(!isTrash && onDownloadRequest), onSelect: () => runMenuAction(() => { window.setTimeout(() => onDownloadRequest?.(), 0) }), }, { key: "quick-link", label: "Obtenir le lien", icon: , visible: Boolean(!isTrash && onQuickLinkRequest && single), onSelect: () => runMenuAction(() => { window.setTimeout(() => onQuickLinkRequest?.(), 0) }), }, { key: "favorite", label: favoriteLabel, icon: , visible: !isTrash && !hideFavorite, onSelect: () => runMenuAction( () => {}, favoriteAsync, favoriteLabel === "Retirer des favoris" ? "Retiré des favoris" : "Ajouté aux favoris", "Impossible de modifier les favoris" ), }, { key: "restore", label: `Restaurer${multi ? ` (${targets.length})` : ""}`, icon: , visible: Boolean(isTrash), onSelect: () => runMenuAction( () => {}, restoreAsync, "Élément(s) restauré(s)", "Impossible de restaurer" ), }, { key: "delete-trash", label: `Supprimer définitivement${multi ? ` (${targets.length})` : ""}`, icon: , destructive: true, visible: Boolean(isTrash && writable), onSelect: () => runMenuAction( () => {}, deleteTrashAsync, "Élément(s) supprimé(s) définitivement", "Impossible de supprimer définitivement" ), }, { key: "rename", label: "Renommer", icon: , visible: Boolean(writable && !isTrash && single && !multi), onSelect: () => runMenuAction(() => { window.setTimeout(() => onRenameRequest(), 0) }), }, { key: "delete", label: `Supprimer${multi ? ` (${targets.length})` : ""}`, icon: , destructive: true, visible: writable && !isTrash, onSelect: () => runMenuAction(() => {}, deleteAsync, "Supprimé", "Impossible de supprimer"), }, ] if (variant === "sheet") { return ( <> {actions .filter((action) => action.visible) .map((action) => ( ))} ) } if (variant === "context") { return ( <> {actions .filter((action) => action.visible) .map((action) => ( stopDriveMenuEvent(e)} onSelect={selectAction(action.onSelect)} > {action.icon} {action.label} ))} ) } return ( <> {actions .filter((action) => action.visible) .map((action) => ( stopDriveMenuEvent(e)} onSelect={() => action.onSelect()} > {action.icon} {action.label} ))} ) }