From e6103a4473bc37d95d20471a934786cb3fa0f67a Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 10 May 2026 12:04:24 +0200 Subject: [PATCH] feat(documents): MoveToFolderDialog single-doc move picker cmdk Combobox dialog showing all folder paths flat (' / '-separated), plus a "Root (no folder)" pseudo-option. Move button disabled when the picked folder matches the document's current folder. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../documents/move-to-folder-dialog.tsx | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/components/documents/move-to-folder-dialog.tsx diff --git a/src/components/documents/move-to-folder-dialog.tsx b/src/components/documents/move-to-folder-dialog.tsx new file mode 100644 index 00000000..7e2cae28 --- /dev/null +++ b/src/components/documents/move-to-folder-dialog.tsx @@ -0,0 +1,115 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { Check, FolderInput } from 'lucide-react'; +import { toast } from 'sonner'; + +import { Button } from '@/components/ui/button'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from '@/components/ui/command'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog'; +import { toastError } from '@/lib/api/toast-error'; +import { + buildFolderPaths, + useDocumentFolders, + useMoveDocument, +} from '@/hooks/use-document-folders'; + +interface MoveToFolderDialogProps { + documentId: string; + documentTitle: string; + currentFolderId: string | null; + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export function MoveToFolderDialog({ + documentId, + documentTitle, + currentFolderId, + open, + onOpenChange, +}: MoveToFolderDialogProps) { + const { data: tree = [] } = useDocumentFolders(); + const move = useMoveDocument(); + const [pickedId, setPickedId] = useState(currentFolderId); + + const paths = useMemo(() => buildFolderPaths(tree), [tree]); + + return ( + + + + Move “{documentTitle}” + + + + + No folders match. + + setPickedId(null)} + className="flex items-center gap-2" + > + + Root (no folder) + + + {paths.length > 0 ? ( + + {paths.map((p) => ( + setPickedId(p.id)} + className="flex items-center gap-2" + > + + {p.path} + + ))} + + ) : null} + + + + + + + + + ); +}