import { useState, useEffect } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { X, Folder, AlertCircle } from 'lucide-react' import clsx from 'clsx' import { sourceFolders, heaps as heapsApi, type Heap } from '../../services/api' import { HEAPS_QUERY_KEY } from '../../hooks/useHeapsQuery' import { toast } from '../ToastContainer' interface HeapConvertDialogProps { heap: Heap | null onClose: () => void } /** * Modal that converts a heap into a folder. The user picks a target folder * (any source root, today — sub-folder picking is a follow-up), chooses * move vs copy semantics, and optionally has the heap deleted on success. */ export function HeapConvertDialog({ heap, onClose }: HeapConvertDialogProps) { const queryClient = useQueryClient() const [targetId, setTargetId] = useState('') const [mode, setMode] = useState<'move' | 'copy'>('move') const [deleteHeap, setDeleteHeap] = useState(false) const [subfolderName, setSubfolderName] = useState('') const { data: foldersData } = useQuery({ queryKey: ['folders'], queryFn: sourceFolders.list, enabled: !!heap, }) const folders = foldersData?.folders ?? [] // Default to the first folder when the dialog opens or folders load. useEffect(() => { if (!targetId && folders.length > 0) { setTargetId(folders[0].id) } }, [folders, targetId]) // Reset state on close, prefill subfolder name when opened. useEffect(() => { if (heap) { setSubfolderName(heap.name) } else { setTargetId('') setMode('move') setDeleteHeap(false) setSubfolderName('') } }, [heap]) const convertMutation = useMutation({ mutationFn: () => heapsApi.convert(heap!.id, { target_id: targetId, mode, delete_heap: deleteHeap, // Empty subfolder = drop directly into the parent. Trim and only // send if the user kept it populated. subfolder_name: subfolderName.trim() || null, }), onSuccess: (data) => { const total = (data.moved ?? 0) + (data.copied ?? 0) const verb = data.mode === 'move' ? 'Moved' : 'Copied' toast.success( `${verb} ${total} photo${total === 1 ? '' : 's'}`, data.heap_deleted ? `Heap "${heap?.name}" deleted` : undefined ) queryClient.invalidateQueries({ queryKey: HEAPS_QUERY_KEY }) queryClient.invalidateQueries({ queryKey: ['photos'] }) queryClient.invalidateQueries({ queryKey: ['folders'] }) onClose() }, onError: (e: any) => toast.error('Convert failed', e?.response?.data?.detail || e.message), }) if (!heap) return null const targetFolder = folders.find((f: any) => f.id === targetId) return (
{subfolderName.trim() && targetFolder ? `Will create ${targetFolder.path}/${subfolderName.trim()} if missing.` : 'Photos go directly into the parent folder.'}
{mode === 'move' ? 'Files are moved on disk; original photos update their folder.' : 'Files are copied on disk; new photo records are created.'}