@burdenoff/microfe-files 2026.625.2 → 2026.625.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/files/components/EmptyState.js +31 -34
- package/dist/files/components/EmptyState.js.map +1 -1
- package/dist/files/components/FileBrowser.js +49 -43
- package/dist/files/components/FileBrowser.js.map +1 -1
- package/dist/files/components/UploadQueue.js +27 -20
- package/dist/files/components/UploadQueue.js.map +1 -1
- package/dist/files/pages/BrowserPage.js +219 -225
- package/dist/files/pages/BrowserPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserPage.js","names":[],"sources":["../../../src/files/pages/BrowserPage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from \"react\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n Button,\n Input,\n CTAOverflowMenu,\n EmphasisPanel,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useKeyboardNavigation } from \"../hooks/useKeyboardNavigation\";\nimport {\n Upload,\n FolderPlus,\n FolderUp,\n Grid3x3,\n List,\n Search,\n X,\n Loader2,\n Trash2,\n Home,\n FileDown,\n FolderX,\n} from \"lucide-react\";\nimport { useFilesContext } from \"../providers/FilesProvider\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { useBrowsePage } from \"../hooks/useBrowsePage\";\nimport { useRecentFiles } from \"../hooks/useRecentFiles\";\nimport { useStarredItems } from \"../hooks/useStarredItems\";\nimport { useBinItems } from \"../hooks/useBinItems\";\nimport { useCreateFolder } from \"../hooks/useCreateFolder\";\nimport { useUploadFile } from \"../hooks/useUploadFile\";\nimport { useDeleteFile } from \"../hooks/useDeleteFile\";\nimport { useDeleteFolder } from \"../hooks/useDeleteFolder\";\nimport { useRestoreFile } from \"../hooks/useRestoreFile\";\nimport { useRestoreFolder } from \"../hooks/useRestoreFolder\";\nimport { usePermanentlyDeleteFile } from \"../hooks/usePermanentlyDeleteFile\";\nimport { usePermanentlyDeleteFolder } from \"../hooks/usePermanentlyDeleteFolder\";\nimport { useToggleStar } from \"../hooks/useToggleStar\";\nimport { useRenameFile } from \"../hooks/useRenameFile\";\nimport { useRenameFolder } from \"../hooks/useRenameFolder\";\nimport { type CreateShareInput, useCreateShare } from \"../hooks/useCreateShare\";\nimport {\n type CreateFolderShareInput,\n useCreateFolderShare,\n} from \"../hooks/useCreateFolderShare\";\nimport { useCopyFile } from \"../hooks/useCopyFile\";\nimport { useMoveFile } from \"../hooks/useMoveFile\";\nimport { useMoveFolder } from \"../hooks/useMoveFolder\";\nimport { useBulkDelete } from \"../hooks/useBatchOperations\";\nimport { type SearchFilters, useSearch } from \"../hooks/useSearch\";\nimport { useToast } from \"../hooks/useToast\";\nimport { FileBrowser } from \"../components/FileBrowser\";\nimport { TabBar, type TabView } from \"../components/TabBar\";\nimport { ShareDialog, type ShareDialogInput } from \"../components/ShareDialog\";\nimport { FilePreviewModal } from \"../components/FilePreviewModal\";\nimport { FileInfoPanel } from \"../components/FileInfoPanel\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ToastContainer } from \"../components/Toast\";\nimport { SearchBar } from \"../components/SearchBar\";\nimport { MoveDialog } from \"../components/MoveDialog\";\nimport { CopyDialog } from \"../components/CopyDialog\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { UploadQueue } from \"../components/UploadQueue\";\nimport { StorageBanner } from \"../components/StorageBanner\";\nimport { useStorageQuota } from \"../hooks/useStorageQuota\";\nimport type { FileItem, FolderItem, UploadItem } from \"../types\";\nimport type { FilesEventName } from \"../utils/events\";\nimport { isQuotaExhaustedError } from \"../utils/quotaUtils\";\nimport {\n nativeImpact,\n nativeNotify,\n nativeOpenUrl,\n} from \"../../utils/nativeBridge\";\nimport { emitFilesEvent } from \"../utils/events\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport { generateThumbnail } from \"../utils\";\n\ninterface ShareDialogResult {\n publicUrl: string;\n token: string;\n}\n\ninterface ConfirmDialogState {\n title: string;\n description: string;\n confirmLabel: string;\n variant?: \"danger\" | \"default\";\n onConfirm: () => Promise<void> | void;\n loading?: boolean;\n}\n\n/**\n * BrowserPage - Main file browser with toolbar and view modes\n */\nexport function BrowserPage() {\n const { t } = useI18n();\n const { folderId } = useParams<{ folderId: string }>();\n const navigate = useNavigate();\n const filesContext = useFilesContext();\n const { workspaceId } = filesContext;\n const storageQuota = useStorageQuota(workspaceId ?? \"\");\n const {\n viewMode,\n setViewMode,\n breadcrumbs,\n selectedFiles,\n selectedFolders,\n clearSelection,\n } = useFilesStore();\n\n // Tab state\n const [activeTab, setActiveTab] = useState<TabView>(\"all\");\n\n // All browser sections are shown unconditionally. Bin and Starred are first\n // -class tabs (not feature-flag-gated): the backend serves their queries\n // directly (subject to RBAC), so there is nothing to gate on the client.\n const enabledTabs = useMemo<TabView[]>(() => {\n return [\"all\", \"recent\", \"starred\", \"bin\"];\n }, []);\n\n // Defensive: if the active tab is ever not in the rendered set, fall back to\n // \"all\" instead of leaving the user on a blank screen.\n useEffect(() => {\n if (!enabledTabs.includes(activeTab)) {\n setActiveTab(\"all\");\n }\n }, [enabledTabs, activeTab]);\n\n const pageSize = 100;\n\n // Search state\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [searchFilters, setSearchFilters] = useState<SearchFilters>();\n const isSearching = searchQuery.trim().length >= 2;\n\n // Info panel state\n const [infoPanel, setInfoPanel] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n\n // Preview state\n const [previewFile, setPreviewFile] = useState<FileItem | null>(null);\n\n // Toast notifications\n const toast = useToast();\n\n // Fetch data based on active tab. Each view owns one composed page query so\n // files, folders, and folder context travel in a single GraphQL operation.\n const browsePageQuery = useBrowsePage({\n folderId: folderId || undefined,\n pageSize,\n skip: activeTab !== \"all\" || isSearching,\n });\n const recentFilesQuery = useRecentFiles({\n skip: activeTab !== \"recent\" || isSearching,\n });\n const starredItemsQuery = useStarredItems({\n skip: activeTab !== \"starred\" || isSearching,\n });\n const binItemsQuery = useBinItems({\n skip: activeTab !== \"bin\" || isSearching,\n });\n\n const searchResults = useSearch(searchQuery, isSearching, searchFilters);\n\n // Update breadcrumbs when folder path data changes\n useEffect(() => {\n if (\n folderId &&\n browsePageQuery.data?.folderPath &&\n browsePageQuery.data?.currentFolder\n ) {\n // Combine parent folders with current folder\n const parentFolders = browsePageQuery.data.folderPath.folders || [];\n const currentFolder = browsePageQuery.data.currentFolder;\n const breadcrumbPath = [\n ...parentFolders.map((f: { id: string; name: string }) => ({\n id: f.id,\n name: f.name,\n })),\n { id: currentFolder.id, name: currentFolder.name },\n ];\n useFilesStore.getState().setBreadcrumbs(breadcrumbPath);\n } else {\n useFilesStore.getState().setBreadcrumbs([]);\n }\n }, [folderId, browsePageQuery.data]);\n\n // Determine which data to display based on search state\n let files: FileItem[] = [];\n let folders: FolderItem[] = [];\n let loading = false;\n let error: Error | null = null;\n let preserveSortOrder = false; // For Recent/Bin tabs - skip re-sorting\n\n // If searching, use search results\n if (isSearching && searchResults.data) {\n files = searchResults.data.files || [];\n folders = searchResults.data.folders || [];\n loading = searchResults.isLoading;\n error = searchResults.error as Error | null;\n } else {\n // Show data based on active tab\n switch (activeTab) {\n case \"all\":\n files = (browsePageQuery.data?.filesList?.files || []) as FileItem[];\n folders = (browsePageQuery.data?.foldersList?.folders ||\n []) as FolderItem[];\n loading = browsePageQuery.loading;\n error = (browsePageQuery.error as Error) || null;\n preserveSortOrder = false;\n break;\n case \"recent\":\n files = recentFilesQuery.files || [];\n folders = recentFilesQuery.folders || [];\n loading = recentFilesQuery.isLoading;\n error = (recentFilesQuery.error as Error) || null;\n preserveSortOrder = true; // Recent tab already sorted by backend\n break;\n case \"starred\":\n files = starredItemsQuery.files;\n folders = starredItemsQuery.folders;\n loading = starredItemsQuery.isLoading;\n error = (starredItemsQuery.error as Error) || null;\n preserveSortOrder = true;\n break;\n case \"bin\":\n files = binItemsQuery.files;\n folders = binItemsQuery.folders;\n loading = binItemsQuery.isLoading;\n error = (binItemsQuery.error as Error) || null;\n preserveSortOrder = true; // Bin tab already sorted by backend\n break;\n }\n }\n\n const totalItemsInCurrentView =\n activeTab === \"all\"\n ? (browsePageQuery.data?.filesList?.total ?? files.length) +\n (browsePageQuery.data?.foldersList?.total ?? folders.length)\n : null;\n\n const totalSelected = selectedFiles.size + selectedFolders.size;\n const [showNewFolderDialog, setShowNewFolderDialog] = useState(false);\n const [showFolderQuotaExhausted, setShowFolderQuotaExhausted] =\n useState(false);\n const [showRenameDialog, setShowRenameDialog] = useState(false);\n const [showShareDialog, setShowShareDialog] = useState(false);\n const [showMoveDialog, setShowMoveDialog] = useState(false);\n const [showCopyDialog, setShowCopyDialog] = useState(false);\n const [shareTarget, setShareTarget] = useState<FileItem | FolderItem | null>(\n null,\n );\n const [moveTarget, setMoveTarget] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [copyTarget, setCopyTarget] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [renameTarget, setRenameTarget] = useState<{\n id: string;\n name: string;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [newName, setNewName] = useState(\"\");\n const [newFolderName, setNewFolderName] = useState(\"\");\n const [uploading, setUploading] = useState(false);\n const [uploadQueue, setUploadQueue] = useState<UploadItem[]>([]);\n const [isUploadPanelOpen, setIsUploadPanelOpen] = useState(false);\n const [confirmDialog, setConfirmDialog] = useState<ConfirmDialogState | null>(\n null,\n );\n\n const emitEvent = (\n name: FilesEventName,\n payload: Record<string, unknown>,\n ) => {\n emitFilesEvent(filesContext, name, payload);\n };\n\n const runConfirmedAction = async () => {\n if (!confirmDialog || confirmDialog.loading) return;\n\n const action = confirmDialog.onConfirm;\n setConfirmDialog({ ...confirmDialog, loading: true });\n try {\n await action();\n setConfirmDialog(null);\n } catch (error) {\n emitEvent(\"files.api.failed\", {\n action: \"confirmDialog\",\n message:\n error instanceof Error ? error.message : \"Confirmed action failed\",\n });\n setConfirmDialog((current) =>\n current ? { ...current, loading: false } : current,\n );\n }\n };\n\n // Mutations\n const createFolderMutation = useCreateFolder();\n const uploadFileMutation = useUploadFile();\n const deleteFileMutation = useDeleteFile();\n const deleteFolderMutation = useDeleteFolder();\n const restoreFileMutation = useRestoreFile();\n const restoreFolderMutation = useRestoreFolder();\n const permanentlyDeleteFileMutation = usePermanentlyDeleteFile();\n const permanentlyDeleteFolderMutation = usePermanentlyDeleteFolder();\n const toggleStarMutation = useToggleStar();\n const renameFileMutation = useRenameFile();\n const renameFolderMutation = useRenameFolder();\n const createShareMutation = useCreateShare();\n const createFolderShareMutation = useCreateFolderShare();\n const copyFileMutation = useCopyFile();\n const moveFileMutation = useMoveFile();\n const moveFolderMutation = useMoveFolder();\n const bulkDeleteMutation = useBulkDelete();\n\n // Action handlers\n const handleUploadClick = () => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.multiple = true;\n input.onchange = async (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files && files.length > 0) {\n const newItems: UploadItem[] = await Promise.all(\n Array.from(files).map(async (file, index) => {\n const thumbnailUrl = await generateThumbnail(file);\n return {\n id: `${Date.now()}-${index}-${file.name}`,\n file,\n status: \"pending\" as const,\n progress: 0,\n folderId: folderId || undefined,\n thumbnailUrl: thumbnailUrl ?? undefined,\n };\n }),\n );\n setUploadQueue((prev) => [...prev, ...newItems]);\n setIsUploadPanelOpen(true);\n setUploading(true);\n\n for (const item of newItems) {\n await processUpload(item);\n }\n setUploading(false);\n }\n };\n input.click();\n };\n\n const processUpload = async (item: UploadItem) => {\n const updateItem = (updates: Partial<UploadItem>) => {\n setUploadQueue((prev) =>\n prev.map((i) => (i.id === item.id ? { ...i, ...updates } : i)),\n );\n };\n\n updateItem({ status: \"uploading\" });\n\n try {\n const uploadedFile = await uploadFileMutation.mutateAsync({\n file: item.file,\n folderId: item.folderId,\n onProgress: (progress) => {\n updateItem({ progress });\n },\n });\n updateItem({ status: \"completed\", progress: 100 });\n emitEvent(\"files.file.uploaded\", {\n fileId: uploadedFile.id,\n fileName: uploadedFile.name,\n folderId: item.folderId,\n });\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : tWithFallback(t, \"files.upload.errors.failed\", \"Upload failed\");\n if (errorMessage === \"Upload paused\") {\n updateItem({ status: \"paused\" });\n } else if (errorMessage === \"QUOTA_EXHAUSTED\") {\n updateItem({\n status: \"failed\",\n error: tWithFallback(\n t,\n \"files.upload.errors.quotaExceeded\",\n \"Storage quota exceeded\",\n ),\n });\n toast.error(\n tWithFallback(\n t,\n \"files.upload.errors.quotaExceeded\",\n \"Storage quota exceeded. Please upgrade your plan or delete files.\",\n ),\n );\n } else {\n updateItem({ status: \"failed\", error: errorMessage });\n emitEvent(\"files.api.failed\", {\n action: \"uploadFile\",\n fileName: item.file.name,\n message: errorMessage,\n });\n }\n }\n };\n\n const handlePauseUpload = (id: string) => {\n uploadFileMutation.pause();\n setUploadQueue((prev) =>\n prev.map((i) => (i.id === id ? { ...i, status: \"paused\" as const } : i)),\n );\n };\n\n const handleResumeUpload = (id: string) => {\n const item = uploadQueue.find((i) => i.id === id);\n if (item) {\n processUpload(item);\n }\n };\n\n const handleRetryUpload = (id: string) => {\n const item = uploadQueue.find((i) => i.id === id);\n if (item) {\n setUploadQueue((prev) =>\n prev.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"pending\" as const,\n progress: 0,\n error: undefined,\n }\n : i,\n ),\n );\n processUpload(item);\n }\n };\n\n const handleCancelUpload = (id: string) => {\n setUploadQueue((prev) => {\n const remaining = prev.filter((i) => i.id !== id);\n if (remaining.length === 0) {\n setIsUploadPanelOpen(false);\n setUploading(false);\n }\n return remaining;\n });\n };\n\n // Folder upload handler - uploads entire folder with structure\n const handleFolderUploadClick = () => {\n if (!workspaceId) {\n toast.error(\n tWithFallback(\n t,\n \"files.workspace.errors.notSelected\",\n \"Workspace not selected\",\n ),\n );\n return;\n }\n\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.webkitdirectory = true;\n input.onchange = async (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files && files.length > 0) {\n const filesByFolder = new Map<string, File[]>();\n for (const file of Array.from(files)) {\n const relativePath = file.webkitRelativePath || file.name;\n const pathParts = relativePath.split(\"/\");\n const folderPath = pathParts.slice(0, -1).join(\"/\");\n\n if (!filesByFolder.has(folderPath)) {\n filesByFolder.set(folderPath, []);\n }\n filesByFolder.get(folderPath)!.push(file);\n }\n\n const folderIdMap = new Map<string, string>();\n const sortedPaths = Array.from(filesByFolder.keys()).sort();\n\n for (const folderPath of sortedPaths) {\n if (!folderPath) continue;\n\n const pathParts = folderPath.split(\"/\");\n let currentPath = \"\";\n let parentId = folderId || undefined;\n\n for (const part of pathParts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n if (!folderIdMap.has(currentPath)) {\n try {\n const { data: createdFolder } =\n await createFolderMutation.mutateAsync({\n name: part,\n parentFolderId: parentId,\n });\n if (createdFolder?.id) {\n folderIdMap.set(currentPath, createdFolder.id);\n parentId = createdFolder.id;\n }\n } catch {\n // Continue best-effort\n }\n } else {\n parentId = folderIdMap.get(currentPath);\n }\n }\n }\n\n const newItems: UploadItem[] = [];\n let index = 0;\n for (const [folderPath, folderFiles] of filesByFolder) {\n const targetFolderId = folderPath\n ? folderIdMap.get(folderPath)\n : folderId || undefined;\n\n for (const file of folderFiles) {\n const thumbnailUrl = await generateThumbnail(file);\n newItems.push({\n id: `${Date.now()}-${index++}-${file.name}`,\n file,\n status: \"pending\",\n progress: 0,\n folderId: targetFolderId,\n thumbnailUrl: thumbnailUrl ?? undefined,\n });\n }\n }\n\n setUploadQueue((prev) => [...prev, ...newItems]);\n setIsUploadPanelOpen(true);\n setUploading(true);\n\n for (const item of newItems) {\n await processUpload(item);\n }\n setUploading(false);\n\n toast.success(\n tWithFallback(\n t,\n \"files.upload.folder.success\",\n \"Uploaded {{count}} file{{plural}} from folder\",\n { count: newItems.length, plural: newItems.length > 1 ? \"s\" : \"\" },\n ),\n );\n }\n };\n input.click();\n };\n\n const handleNewFolderClick = () => {\n setShowNewFolderDialog(true);\n };\n\n const handleCreateFolder = async () => {\n if (newFolderName.trim() && workspaceId) {\n const { data: createdFolder, error } =\n await createFolderMutation.mutateAsync({\n name: newFolderName,\n parentFolderId: folderId,\n });\n\n if (error) {\n if (isQuotaExhaustedError(error)) {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n setShowFolderQuotaExhausted(true);\n } else {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.createFailed\",\n \"Folder creation failed\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"createFolder\",\n message:\n error instanceof Error ? error.message : \"Folder creation failed\",\n });\n }\n return;\n }\n\n if (createdFolder) {\n setNewFolderName(\"\");\n setShowNewFolderDialog(false);\n emitEvent(\"files.folder.created\", {\n folderName: newFolderName,\n parentFolderId: folderId,\n });\n }\n }\n };\n\n // File action handlers\n const handleFilePreview = (file: FileItem) => {\n setPreviewFile(file);\n };\n\n const handleFileShare = (file: FileItem) => {\n setShareTarget(file);\n setShowShareDialog(true);\n };\n\n const handleFolderShare = (folder: FolderItem) => {\n setShareTarget(folder);\n setShowShareDialog(true);\n };\n\n const handleCreateShare = async (\n input: ShareDialogInput,\n ): Promise<ShareDialogResult> => {\n if (!input.fileId && !input.folderId) {\n throw new Error(\n tWithFallback(\n t,\n \"files.share.errors.targetRequired\",\n \"Share requires a file id or folder id\",\n ),\n );\n }\n\n const shareType = input.invitedEmail ? \"EMAIL_INVITE\" : \"PUBLIC_LINK\";\n let token = \"\";\n\n if (input.fileId) {\n // File share\n const shareInput: CreateShareInput = {\n fileId: input.fileId,\n expiresAt: input.expiresAt,\n maxDownloads: input.maxDownloads,\n password: input.password,\n invitedEmail: input.invitedEmail,\n shareType,\n accessLevel: \"DOWNLOAD\" as const,\n };\n const result = await createShareMutation.mutateAsync(shareInput);\n token = result?.token ?? \"\";\n emitEvent(\"files.share.created\", {\n entityType: \"file\",\n fileId: input.fileId,\n shareType,\n });\n } else if (input.folderId) {\n // Folder share\n const shareInput: CreateFolderShareInput = {\n folderId: input.folderId,\n expiresAt: input.expiresAt,\n maxDownloads: input.maxDownloads,\n password: input.password,\n invitedEmail: input.invitedEmail,\n shareType,\n accessLevel: \"DOWNLOAD\" as const,\n };\n const result = await createFolderShareMutation.mutateAsync(shareInput);\n token = result?.createFolderShare?.token ?? \"\";\n emitEvent(\"files.share.created\", {\n entityType: \"folder\",\n folderId: input.folderId,\n shareType,\n });\n }\n\n return {\n publicUrl: token ? `${window.location.origin}/files/share/${token}` : \"\",\n token,\n };\n };\n\n const handleFileDelete = async (file: FileItem) => {\n nativeImpact(\"medium\");\n setConfirmDialog({\n title: tWithFallback(t, \"files.confirm.deleteFile.title\", \"Delete file\"),\n description: tWithFallback(\n t,\n \"files.confirm.deleteFile.description\",\n 'Move \"{{name}}\" to the bin?',\n { name: file.name },\n ),\n confirmLabel: tWithFallback(t, \"files.common.actions.delete\", \"Delete\"),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteFileMutation.mutateAsync({ id: file.id });\n nativeNotify(\"success\");\n toast.success(\n tWithFallback(\n t,\n \"files.file.delete.success\",\n '\"{{name}}\" moved to bin',\n { name: file.name },\n ),\n );\n emitEvent(\"files.file.deleted\", {\n fileId: file.id,\n fileName: file.name,\n permanent: false,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.deleteFailed\",\n 'Failed to delete \"{{name}}\"',\n { name: file.name },\n ),\n );\n nativeNotify(\"error\");\n emitEvent(\"files.api.failed\", {\n action: \"deleteFile\",\n fileId: file.id,\n message:\n error instanceof Error ? error.message : \"Failed to delete file\",\n });\n }\n },\n });\n };\n\n const handleFileRestore = async (file: FileItem) => {\n try {\n await restoreFileMutation.mutateAsync({ id: file.id });\n toast.success(\n tWithFallback(t, \"files.file.restore.success\", '\"{{name}}\" restored', {\n name: file.name,\n }),\n );\n emitEvent(\"files.file.restored\", {\n fileId: file.id,\n fileName: file.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.restoreFailed\",\n \"Failed to restore file\",\n ),\n );\n }\n };\n\n const handleFilePermanentDelete = async (file: FileItem) => {\n nativeImpact(\"heavy\");\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFile.title\",\n \"Permanently delete file\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFile.description\",\n 'Permanently delete \"{{name}}\"? This cannot be undone.',\n { name: file.name },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await permanentlyDeleteFileMutation.mutateAsync({ id: file.id });\n toast.success(\n tWithFallback(\n t,\n \"files.file.permanentDelete.success\",\n '\"{{name}}\" deleted permanently',\n { name: file.name },\n ),\n );\n emitEvent(\"files.file.deleted\", {\n fileId: file.id,\n fileName: file.name,\n permanent: true,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.permanentDeleteFailed\",\n \"Failed to permanently delete file\",\n ),\n );\n }\n },\n });\n };\n\n const handleFileFavorite = async (file: FileItem) => {\n try {\n await toggleStarMutation.mutateAsync({ id: file.id, type: \"file\" });\n emitEvent(\"files.file.starred\", {\n fileId: file.id,\n fileName: file.name,\n starred: !file.starred,\n });\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.file.errors.starFailed\",\n \"Failed to update starred state\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"toggleFileStar\",\n fileId: file.id,\n });\n }\n };\n\n const handleFileRename = (file: FileItem) => {\n setRenameTarget({ id: file.id, name: file.name, type: \"file\" });\n setNewName(file.name);\n setShowRenameDialog(true);\n };\n\n const handleFileDownload = async (file: FileItem) => {\n try {\n const downloadUrl = file.downloadUrl || file.url;\n\n if (!downloadUrl) {\n throw new Error(\n tWithFallback(\n t,\n \"files.file.errors.downloadUrlUnavailable\",\n \"Download URL is unavailable\",\n ),\n );\n }\n\n const a = document.createElement(\"a\");\n a.style.display = \"none\";\n a.href = downloadUrl;\n a.download = file.name;\n a.rel = \"noopener noreferrer\";\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n\n toast.success(\n tWithFallback(t, \"files.file.download.success\", \"Downloaded {{name}}\", {\n name: file.name,\n }),\n );\n emitEvent(\"files.file.downloaded\", {\n fileId: file.id,\n fileName: file.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.downloadFailed\",\n \"Failed to download file\",\n ),\n );\n }\n };\n\n const handleFileCopy = (file: FileItem) => {\n setCopyTarget({ item: file, type: \"file\" });\n setShowCopyDialog(true);\n };\n\n const handleFileMove = (file: FileItem) => {\n setMoveTarget({ item: file, type: \"file\" });\n setShowMoveDialog(true);\n };\n\n const handleFileInfoClick = (file: FileItem) => {\n setInfoPanel({ item: file, type: \"file\" });\n };\n\n // Folder action handlers\n const handleFolderOpen = (folder: FolderItem) => {\n // Navigate to folder by updating URL\n navigate(`/files/browse/${folder.id}`);\n };\n\n const handleFolderDelete = async (folder: FolderItem) => {\n nativeImpact(\"medium\");\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.deleteFolder.title\",\n \"Delete folder\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.deleteFolder.description\",\n 'Move folder \"{{name}}\" and all its contents to the bin?',\n { name: folder.name },\n ),\n confirmLabel: tWithFallback(t, \"files.common.actions.delete\", \"Delete\"),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteFolderMutation.mutateAsync({\n id: folder.id,\n recursive: true,\n });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.delete.success\",\n '\"{{name}}\" moved to bin',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.deleted\", {\n folderId: folder.id,\n folderName: folder.name,\n permanent: false,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.deleteFailed\",\n \"Failed to delete folder\",\n ),\n );\n }\n },\n });\n };\n\n const handleFolderRestore = async (folder: FolderItem) => {\n try {\n await restoreFolderMutation.mutateAsync({ id: folder.id });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.restore.success\",\n '\"{{name}}\" restored',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.restored\", {\n folderId: folder.id,\n folderName: folder.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.restoreFailed\",\n \"Failed to restore folder\",\n ),\n );\n }\n };\n\n const handleFolderPermanentDelete = async (folder: FolderItem) => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFolder.title\",\n \"Permanently delete folder\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFolder.description\",\n 'Permanently delete folder \"{{name}}\" and its contents? This cannot be undone.',\n { name: folder.name },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await permanentlyDeleteFolderMutation.mutateAsync({ id: folder.id });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.permanentDelete.success\",\n '\"{{name}}\" deleted permanently',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.deleted\", {\n folderId: folder.id,\n folderName: folder.name,\n permanent: true,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.permanentDeleteFailed\",\n \"Failed to permanently delete folder\",\n ),\n );\n }\n },\n });\n };\n\n const handleFolderRename = (folder: FolderItem) => {\n setRenameTarget({ id: folder.id, name: folder.name, type: \"folder\" });\n setNewName(folder.name);\n setShowRenameDialog(true);\n };\n\n const handleFolderMove = (folder: FolderItem) => {\n setMoveTarget({ item: folder, type: \"folder\" });\n setShowMoveDialog(true);\n };\n\n const handleFolderFavorite = async (folder: FolderItem) => {\n try {\n await toggleStarMutation.mutateAsync({ id: folder.id, type: \"folder\" });\n emitEvent(\"files.folder.starred\", {\n folderId: folder.id,\n folderName: folder.name,\n starred: !folder.starred,\n });\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.folder.errors.starFailed\",\n \"Failed to update starred state\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"toggleFolderStar\",\n folderId: folder.id,\n });\n }\n };\n\n const handleFolderInfoClick = (folder: FolderItem) => {\n setInfoPanel({ item: folder, type: \"folder\" });\n };\n\n // Move and Copy handlers\n const handleMoveSubmit = async (destinationFolderId: string | null) => {\n if (!moveTarget) return;\n\n try {\n if (moveTarget.type === \"file\") {\n await moveFileMutation.mutateAsync({\n fileId: moveTarget.item.id,\n targetFolderId: destinationFolderId || null,\n });\n toast.success(\n tWithFallback(t, \"files.file.move.success\", '\"{{name}}\" moved', {\n name: moveTarget.item.name,\n }),\n );\n emitEvent(\"files.file.moved\", {\n fileId: moveTarget.item.id,\n fileName: moveTarget.item.name,\n destinationFolderId,\n });\n } else {\n await moveFolderMutation.mutateAsync({\n folderId: moveTarget.item.id,\n targetParentFolderId: destinationFolderId,\n });\n toast.success(\n tWithFallback(t, \"files.folder.move.success\", '\"{{name}}\" moved', {\n name: moveTarget.item.name,\n }),\n );\n emitEvent(\"files.folder.moved\", {\n folderId: moveTarget.item.id,\n folderName: moveTarget.item.name,\n destinationFolderId,\n });\n }\n setShowMoveDialog(false);\n setMoveTarget(null);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.item.errors.moveFailed\",\n 'Failed to move \"{{name}}\"',\n {\n name: moveTarget.item.name,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: moveTarget.type === \"file\" ? \"moveFile\" : \"moveFolder\",\n itemId: moveTarget.item.id,\n itemType: moveTarget.type,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleCopySubmit = async (\n destinationFolderId: string | null,\n newName?: string,\n ) => {\n if (!copyTarget) return;\n\n try {\n if (copyTarget.type !== \"file\") {\n throw new Error(\n tWithFallback(\n t,\n \"files.folder.errors.copyUnsupported\",\n \"Folder copy is not supported\",\n ),\n );\n }\n\n await copyFileMutation.mutateAsync({\n id: copyTarget.item.id,\n newName: newName || `Copy of ${copyTarget.item.name}`,\n targetFolderId: destinationFolderId || undefined,\n });\n toast.success(\n tWithFallback(t, \"files.file.copy.success\", '\"{{name}}\" copied', {\n name: copyTarget.item.name,\n }),\n );\n emitEvent(\"files.file.copied\", {\n fileId: copyTarget.item.id,\n fileName: copyTarget.item.name,\n destinationFolderId,\n });\n\n setShowCopyDialog(false);\n setCopyTarget(null);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.copyFailed\",\n 'Failed to copy \"{{name}}\"',\n {\n name: copyTarget.item.name,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"copyFile\",\n fileId: copyTarget.item.id,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleRenameSubmit = async () => {\n if (!renameTarget || !newName.trim()) return;\n\n try {\n const previousName = renameTarget.name;\n const nextName = newName.trim();\n\n if (renameTarget.type === \"file\") {\n await renameFileMutation.mutateAsync({\n fileId: renameTarget.id,\n newName: nextName,\n });\n toast.success(\n tWithFallback(t, \"files.file.rename.success\", 'Renamed \"{{name}}\"', {\n name: nextName,\n }),\n );\n emitEvent(\"files.file.renamed\", {\n fileId: renameTarget.id,\n previousName,\n name: nextName,\n });\n } else {\n await renameFolderMutation.mutateAsync({\n folderId: renameTarget.id,\n newName: nextName,\n });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.rename.success\",\n 'Renamed \"{{name}}\"',\n {\n name: nextName,\n },\n ),\n );\n emitEvent(\"files.folder.renamed\", {\n folderId: renameTarget.id,\n previousName,\n name: nextName,\n });\n }\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.item.errors.renameFailed\",\n \"Failed to rename {{type}}\",\n {\n type: renameTarget.type,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: renameTarget.type === \"file\" ? \"renameFile\" : \"renameFolder\",\n itemId: renameTarget.id,\n itemType: renameTarget.type,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleSearch = (query: string, filters?: SearchFilters) => {\n setSearchQuery(query);\n setSearchFilters(filters);\n };\n\n useKeyboardNavigation({\n files,\n folders,\n onFilePreview: handleFilePreview,\n onFileDelete: handleFileDelete,\n onFolderOpen: handleFolderOpen,\n onFolderDelete: handleFolderDelete,\n activeTab,\n });\n\n // Guard: if the host shell hasn't pushed workspace context yet, render a\n // clear loading state rather than firing queries with an undefined workspace\n // (which used to manifest as a silent blank screen).\n // NOTE: We explicitly check for undefined (not yet provided) vs empty string\n // (explicitly no workspace selected) to show appropriate messaging.\n if (workspaceId === undefined) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[60vh] gap-3 text-center px-6\">\n <Loader2 className=\"size-8 animate-spin text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary max-w-md\">\n {tWithFallback(\n t,\n \"files.browser.workspace.waiting\",\n \"Waiting for workspace context. If this persists, the app shell may not have provided a workspaceId to the Files module. Try reloading the page or switching workspaces.\",\n )}\n </p>\n </div>\n );\n }\n\n // Empty string means host shell provided context but no workspace is selected\n if (workspaceId === \"\") {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[60vh] gap-3 text-center px-6\">\n <FolderX className=\"size-8 text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary max-w-md\">\n {tWithFallback(\n t,\n \"files.browser.workspace.notSelected\",\n \"No workspace selected. Please select a workspace to view files.\",\n )}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-screen bg-bg-surface\">\n {/* Google Drive-style Header with Breadcrumb Navigation */}\n <div\n className=\"bg-bg-surface border-b border-border-seam px-4 py-3 sm:px-6 sm:py-4\"\n data-tour=\"files-breadcrumb-nav\"\n >\n <div className=\"flex items-center gap-2 sm:gap-4\">\n <div className=\"flex items-center gap-1 sm:gap-2 text-sm overflow-x-auto\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/files/browse\")}\n className=\"flex items-center gap-1 text-text-primary hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap\"\n title={tWithFallback(\n t,\n \"files.browser.actions.goToRoot\",\n \"Go to root\",\n )}\n >\n <Home className=\"size-4\" />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, \"files.browser.rootLabel\", \"My Drive\")}\n </span>\n </button>\n {breadcrumbs.map((crumb, index) => (\n <div key={crumb.id} className=\"flex items-center gap-1 sm:gap-2\">\n <span className=\"text-text-tertiary\">/</span>\n <button\n type=\"button\"\n onClick={() => navigate(`/files/browse/${crumb.id}`)}\n className={`hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap ${\n index === breadcrumbs.length - 1\n ? \"text-text-primary font-medium\"\n : \"text-text-secondary\"\n }`}\n title={`Go to ${crumb.name}`}\n >\n {crumb.name}\n </button>\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Navigation Tabs */}\n <div data-tour=\"files-tab-bar\">\n <TabBar\n activeTab={activeTab}\n onTabChange={setActiveTab}\n tabs={enabledTabs}\n />\n </div>\n\n {/* Google Drive-style Toolbar */}\n <div className=\"bg-bg-surface border-b border-border-seam px-4 py-2 sm:px-6 sm:py-3\">\n <div className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-inline-gap\">\n {/* Left side - Search */}\n <div\n className=\"w-full sm:flex-1 min-w-0 order-2 sm:order-1\"\n data-tour=\"files-search-bar\"\n >\n <div className=\"relative w-full max-w-2xl\">\n <SearchBar\n onSearch={handleSearch}\n placeholder={tWithFallback(\n t,\n \"files.search.input.placeholder\",\n \"Search files and folders...\",\n )}\n initialQuery={searchQuery}\n showFilters={true}\n />\n </div>\n </div>\n\n {/* Right side - Actions: one primary CTA (Upload Files), the rest\n collapsed into an overflow menu to keep the toolbar uncluttered. */}\n <div className=\"flex items-center gap-2 order-1 sm:order-2 w-full sm:w-auto justify-between sm:justify-end\">\n {!isSearching && (\n <div data-tour=\"files-upload-files-button\">\n <CTAOverflowMenu\n primary={{\n label: uploading\n ? tWithFallback(\n t,\n \"files.browser.upload.uploading\",\n \"Uploading...\",\n )\n : tWithFallback(\n t,\n \"files.browser.actions.uploadFiles\",\n \"Upload Files\",\n ),\n onSelect: handleUploadClick,\n disabled: uploading,\n icon: uploading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Upload className=\"size-4\" />\n ),\n }}\n actions={[\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.newFolder\",\n \"New Folder\",\n ),\n icon: <FolderPlus className=\"size-4\" />,\n onSelect: handleNewFolderClick,\n },\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.uploadFolder\",\n \"Upload Folder\",\n ),\n icon: <FolderUp className=\"size-4\" />,\n onSelect: handleFolderUploadClick,\n disabled: uploading,\n },\n ...(files.length > 0 || folders.length > 0\n ? [\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.selectAll\",\n \"Select All\",\n ),\n onSelect: () => {\n const allFileIds = files.map((f) => f.id);\n const allFolderIds = folders.map((f) => f.id);\n useFilesStore.getState().selectAllFiles(allFileIds);\n allFolderIds.forEach((id) =>\n useFilesStore.getState().selectFolder(id),\n );\n },\n },\n ]\n : []),\n ]}\n />\n </div>\n )}\n\n {/* View mode toggle */}\n <div\n className=\"flex items-center border border-border-seam rounded-lg overflow-hidden\"\n data-tour=\"files-view-mode-toggle\"\n >\n <button\n type=\"button\"\n onClick={() => setViewMode(\"grid\")}\n className={`p-2 transition-colors duration-200 ${\n viewMode === \"grid\"\n ? \"bg-bg-accent text-text-link\"\n : \"text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n aria-label={tWithFallback(\n t,\n \"files.browser.view.grid\",\n \"Grid view\",\n )}\n >\n <Grid3x3 className=\"size-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"list\")}\n className={`p-2 transition-colors duration-200 ${\n viewMode === \"list\"\n ? \"bg-bg-accent text-text-link\"\n : \"text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n aria-label={tWithFallback(\n t,\n \"files.browser.view.list\",\n \"List view\",\n )}\n >\n <List className=\"size-5\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Search results indicator */}\n {isSearching && (\n <div className=\"mt-3 flex items-center justify-between p-3 bg-status-success-bg-subtle rounded-lg border border-status-success-border transition-all duration-200\">\n <span className=\"text-sm font-medium text-status-success-text\">\n {tWithFallback(\n t,\n \"files.browser.search.showingResults\",\n 'Showing search results for \"{{query}}\"',\n { query: searchQuery },\n )}\n {searchResults.data &&\n ` (${(searchResults.data.files?.length || 0) + (searchResults.data.folders?.length || 0)} items)`}\n </span>\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"flex items-center gap-2 text-status-success-text hover:text-status-success-text/80 text-sm font-medium transition-colors duration-200\"\n >\n <X className=\"size-4\" />\n {tWithFallback(t, \"files.browser.search.clear\", \"Clear search\")}\n </button>\n </div>\n )}\n\n {/* Selection info with bulk actions — emphasised as the single primary\n action zone while a selection is active. */}\n {totalSelected > 0 && (\n <EmphasisPanel className=\"mt-3 flex items-center justify-between p-3\">\n <div className=\"flex items-center gap-4\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(\n t,\n \"files.browser.selection.selectedCount\",\n \"{{count}} item{{suffix}} selected\",\n {\n count: totalSelected,\n suffix: totalSelected > 1 ? \"s\" : \"\",\n },\n )}\n </span>\n\n {/* Bulk action buttons */}\n <div className=\"flex items-center gap-2\">\n {activeTab === \"bin\" ? (\n <>\n <button\n type=\"button\"\n onClick={async () => {\n try {\n await Promise.all([\n ...Array.from(selectedFiles).map((fileId) =>\n restoreFileMutation.mutateAsync({ id: fileId }),\n ),\n ...Array.from(selectedFolders).map((folderId) =>\n restoreFolderMutation.mutateAsync({\n id: folderId,\n }),\n ),\n ]);\n\n clearSelection();\n toast.success(\n `${totalSelected} item${totalSelected > 1 ? \"s\" : \"\"} restored`,\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : \"Failed to restore some items\",\n );\n }\n }}\n className=\"flex items-center gap-1.5 rounded-lg border border-status-success-border bg-bg-surface px-3 py-1.5 text-sm font-medium text-status-success-text transition-colors duration-200 hover:bg-status-success-bg-subtle\"\n >\n {tWithFallback(\n t,\n \"files.browser.selection.actions.restore\",\n \"Restore\",\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={async () => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.bulkPermanentDelete.title\",\n \"Permanently delete selected items\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.bulkPermanentDelete.description\",\n \"Permanently delete {{count}} selected item{{plural}}? This cannot be undone.\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await Promise.all([\n ...Array.from(selectedFiles).map((fileId) =>\n permanentlyDeleteFileMutation.mutateAsync({\n id: fileId,\n }),\n ),\n ...Array.from(selectedFolders).map((folderId) =>\n permanentlyDeleteFolderMutation.mutateAsync({\n id: folderId,\n }),\n ),\n ]);\n\n clearSelection();\n toast.success(\n tWithFallback(\n t,\n \"files.bulk.permanentDelete.success\",\n \"{{count}} item{{plural}} deleted permanently\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.bulk.errors.permanentDeleteFailed\",\n \"Failed to permanently delete some items\",\n ),\n );\n }\n },\n });\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-status-error-text bg-bg-surface border border-status-error-border rounded-lg hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n <Trash2 className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.browser.selection.actions.deletePermanently\",\n \"Delete permanently\",\n )}\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n onClick={async () => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.bulkDelete.title\",\n \"Delete selected items\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.bulkDelete.description\",\n \"Move {{count}} selected item{{plural}} to the bin?\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.delete\",\n \"Delete\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n const fileIds = Array.from(selectedFiles);\n const folderIds = Array.from(selectedFolders);\n\n if (fileIds.length > 0) {\n await bulkDeleteMutation.mutateAsync(fileIds);\n }\n\n await Promise.all(\n folderIds.map((folderId) =>\n deleteFolderMutation.mutateAsync({\n id: folderId,\n recursive: true,\n }),\n ),\n );\n\n clearSelection();\n toast.success(\n tWithFallback(\n t,\n \"files.bulk.delete.success\",\n \"{{count}} item{{plural}} moved to bin\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.bulk.errors.deleteFailed\",\n \"Failed to delete some items\",\n ),\n );\n }\n },\n });\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-status-error-text bg-bg-surface border border-status-error-border rounded-lg hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n <Trash2 className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.browser.selection.actions.delete\",\n \"Delete\",\n )}\n </button>\n )}\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"flex items-center gap-2 text-text-link hover:text-action-primary-bg-hover text-sm font-medium transition-colors duration-200\"\n >\n <X className=\"size-4\" />\n {tWithFallback(t, \"files.common.actions.clear\", \"Clear\")}\n </button>\n </EmphasisPanel>\n )}\n </div>\n\n {/* Storage quota banner */}\n {(storageQuota.isExhausted || storageQuota.isNearLimit) && (\n <div className=\"px-4 sm:px-6 pt-3\">\n <StorageBanner quota={storageQuota} />\n </div>\n )}\n\n {/* File Browser */}\n <div\n className=\"px-2 sm:px-4 md:px-6 py-3 sm:py-4\"\n data-tour=\"files-browser-grid\"\n >\n <FileBrowser\n files={files}\n folders={folders}\n loading={loading}\n error={error}\n preserveSortOrder={preserveSortOrder}\n onFilePreview={handleFilePreview}\n onFileShare={activeTab === \"bin\" ? undefined : handleFileShare}\n onFileDelete={\n activeTab === \"bin\" ? handleFilePermanentDelete : handleFileDelete\n }\n onFileRestore={activeTab === \"bin\" ? handleFileRestore : undefined}\n onFileFavorite={activeTab === \"bin\" ? undefined : handleFileFavorite}\n onFileRename={activeTab === \"bin\" ? undefined : handleFileRename}\n onFileDownload={handleFileDownload}\n onFileCopy={activeTab === \"bin\" ? undefined : handleFileCopy}\n onFileMove={activeTab === \"bin\" ? undefined : handleFileMove}\n onFileInfo={handleFileInfoClick}\n onFolderOpen={handleFolderOpen}\n onFolderShare={activeTab === \"bin\" ? undefined : handleFolderShare}\n onFolderDelete={\n activeTab === \"bin\"\n ? handleFolderPermanentDelete\n : handleFolderDelete\n }\n onFolderRestore={\n activeTab === \"bin\" ? handleFolderRestore : undefined\n }\n onFolderRename={activeTab === \"bin\" ? undefined : handleFolderRename}\n onFolderFavorite={\n activeTab === \"bin\" ? undefined : handleFolderFavorite\n }\n onFolderMove={activeTab === \"bin\" ? undefined : handleFolderMove}\n onFolderInfo={handleFolderInfoClick}\n />\n\n {/* Results Summary */}\n {!loading && (files.length > 0 || folders.length > 0) && (\n <div className=\"mt-4 px-2 text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.browser.results.showingItems\",\n \"Showing {{count}} items\",\n { count: files.length + folders.length },\n )}\n {!isSearching &&\n activeTab === \"all\" &&\n totalItemsInCurrentView !== null &&\n ` ${tWithFallback(\n t,\n \"files.browser.results.ofItems\",\n \"of {{count}} items\",\n { count: totalItemsInCurrentView },\n )}`}\n </div>\n )}\n </div>\n\n {/* New Folder Dialog */}\n {showNewFolderDialog && (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !createFolderMutation.isPending) {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n }\n }}\n >\n <ResponsiveDialogContent className=\"w-full max-w-xs\">\n <ResponsiveDialogHeader className=\"text-left\">\n <ResponsiveDialogTitle\n id=\"files-new-folder-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.browser.newFolderDialog.title\",\n \"New folder\",\n )}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <Input\n type=\"text\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleCreateFolder();\n }}\n aria-label={tWithFallback(\n t,\n \"files.browser.newFolderDialog.title\",\n \"New folder\",\n )}\n placeholder={tWithFallback(\n t,\n \"files.browser.newFolderDialog.placeholder\",\n \"Folder name\",\n )}\n />\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n }}\n >\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleCreateFolder}\n disabled={\n !newFolderName.trim() || createFolderMutation.isPending\n }\n >\n {createFolderMutation.isPending && (\n <Loader2 className=\"size-4 animate-spin\" />\n )}\n {createFolderMutation.isPending\n ? tWithFallback(\n t,\n \"files.browser.newFolderDialog.actions.creating\",\n \"Creating...\",\n )\n : tWithFallback(t, \"files.common.actions.create\", \"Create\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n )}\n\n {/* Rename Dialog */}\n {showRenameDialog && renameTarget && (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (\n !next &&\n !renameFileMutation.isPending &&\n !renameFolderMutation.isPending\n ) {\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n }\n }}\n >\n <ResponsiveDialogContent className=\"w-full max-w-xs\">\n <ResponsiveDialogHeader className=\"text-left\">\n <ResponsiveDialogTitle\n id=\"files-rename-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.browser.renameDialog.title\",\n \"Rename {{type}}\",\n { type: renameTarget.type },\n )}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <Input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleRenameSubmit();\n }}\n aria-label={tWithFallback(\n t,\n \"files.browser.renameDialog.title\",\n \"Rename\",\n )}\n placeholder={tWithFallback(\n t,\n \"files.browser.renameDialog.placeholder\",\n \"New name\",\n )}\n />\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n }}\n >\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleRenameSubmit}\n disabled={\n !newName.trim() ||\n newName.trim() === renameTarget.name ||\n renameFileMutation.isPending ||\n renameFolderMutation.isPending\n }\n >\n {(renameFileMutation.isPending ||\n renameFolderMutation.isPending) && (\n <Loader2 className=\"size-4 animate-spin\" />\n )}\n {renameFileMutation.isPending || renameFolderMutation.isPending\n ? tWithFallback(\n t,\n \"files.browser.renameDialog.actions.renaming\",\n \"Renaming...\",\n )\n : tWithFallback(t, \"files.common.actions.rename\", \"Rename\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n )}\n\n {/* Share Dialog */}\n {showShareDialog && shareTarget && (\n <ShareDialog\n item={shareTarget}\n itemType={\"mimeType\" in shareTarget ? \"file\" : \"folder\"}\n onClose={() => {\n setShowShareDialog(false);\n setShareTarget(null);\n }}\n onCreateShare={handleCreateShare}\n isLoading={createShareMutation.isPending}\n />\n )}\n\n {confirmDialog && (\n <ConfirmDialog\n title={confirmDialog.title}\n description={confirmDialog.description}\n confirmLabel={confirmDialog.confirmLabel}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.cancel\",\n \"Cancel\",\n )}\n variant={confirmDialog.variant}\n loading={confirmDialog.loading}\n onConfirm={runConfirmedAction}\n onCancel={() => {\n if (!confirmDialog.loading) {\n setConfirmDialog(null);\n }\n }}\n />\n )}\n\n {/* Folder Quota Exhausted Dialog */}\n {showFolderQuotaExhausted && (\n <ConfirmDialog\n title={tWithFallback(\n t,\n \"files.folder.quota.title\",\n \"Folder Limit Reached\",\n )}\n description={tWithFallback(\n t,\n \"files.folder.quota.description\",\n \"You've reached the folder limit for your plan. Upgrade your plan or purchase an add-on to create more folders.\",\n )}\n confirmLabel={tWithFallback(\n t,\n \"files.folder.quota.upgrade\",\n \"View Billing\",\n )}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.dismiss\",\n \"Dismiss\",\n )}\n onConfirm={() => {\n setShowFolderQuotaExhausted(false);\n navigate(\"/billing\");\n }}\n onCancel={() => setShowFolderQuotaExhausted(false)}\n />\n )}\n\n {/* Move Dialog */}\n {showMoveDialog && moveTarget && (\n <MoveDialog\n item={moveTarget.item}\n type={moveTarget.type}\n onClose={() => {\n setShowMoveDialog(false);\n setMoveTarget(null);\n }}\n onMove={handleMoveSubmit}\n isLoading={moveFileMutation.isPending || moveFolderMutation.isPending}\n />\n )}\n\n {/* Copy Dialog */}\n {showCopyDialog && copyTarget && (\n <CopyDialog\n item={copyTarget.item}\n type={copyTarget.type}\n onClose={() => {\n setShowCopyDialog(false);\n setCopyTarget(null);\n }}\n onCopy={handleCopySubmit}\n isLoading={copyFileMutation.isPending}\n />\n )}\n\n {/* File Preview Modal */}\n {previewFile && (\n <FilePreviewModal\n file={previewFile}\n onClose={() => setPreviewFile(null)}\n onDownload={() => {\n const url = previewFile.downloadUrl || previewFile.url;\n void nativeOpenUrl(url);\n }}\n onShare={\n activeTab === \"bin\"\n ? undefined\n : () => {\n setShareTarget(previewFile);\n setShowShareDialog(true);\n }\n }\n onStar={\n activeTab === \"bin\"\n ? undefined\n : () => handleFileFavorite(previewFile)\n }\n onDelete={() =>\n activeTab === \"bin\"\n ? handleFilePermanentDelete(previewFile)\n : handleFileDelete(previewFile)\n }\n />\n )}\n\n {/* File Info Panel */}\n {infoPanel && (\n <FileInfoPanel\n item={infoPanel.item}\n type={infoPanel.type}\n onClose={() => setInfoPanel(null)}\n />\n )}\n\n {/* Upload Progress Indicator */}\n {/* Upload Queue */}\n <UploadQueue\n items={uploadQueue}\n isOpen={isUploadPanelOpen}\n onClose={() => setIsUploadPanelOpen(false)}\n onPause={handlePauseUpload}\n onResume={handleResumeUpload}\n onRetry={handleRetryUpload}\n onCancel={handleCancelUpload}\n />\n\n {/* Toast Notifications */}\n <ToastContainer toasts={toast.toasts} onClose={toast.removeToast} />\n\n {/* Empty State */}\n {!loading && files.length === 0 && folders.length === 0 && (\n <div className=\"px-6 py-12\">\n {isSearching ? (\n <div className=\"text-center animate-in fade-in duration-200\">\n <div className=\"inline-flex items-center justify-center size-16 bg-bg-sunken rounded-full mb-4\">\n <Search className=\"size-8 text-text-tertiary\" />\n </div>\n <h3 className=\"text-lg font-medium text-text-primary mb-2\">\n {tWithFallback(\n t,\n \"files.browser.empty.search.title\",\n \"No results found\",\n )}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tWithFallback(\n t,\n \"files.browser.empty.search.description\",\n \"Try adjusting your search query or filters\",\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => {\n setSearchQuery(\"\");\n setSearchFilters(undefined);\n }}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-text-inverse bg-action-primary-bg rounded-lg hover:bg-action-primary-bg-hover transition-colors duration-200\"\n >\n {tWithFallback(t, \"files.browser.search.clear\", \"Clear search\")}\n </button>\n </div>\n ) : (\n <EmptyState\n type={activeTab}\n onUpload={activeTab === \"all\" ? handleUploadClick : undefined}\n onNewFolder={\n activeTab === \"all\" ? handleNewFolderClick : undefined\n }\n />\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BrowserPage.js","names":[],"sources":["../../../src/files/pages/BrowserPage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from \"react\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n Button,\n Input,\n CTAOverflowMenu,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useKeyboardNavigation } from \"../hooks/useKeyboardNavigation\";\nimport {\n Upload,\n FolderPlus,\n FolderUp,\n Grid3x3,\n List,\n X,\n Loader2,\n Trash2,\n Home,\n FileDown,\n FolderX,\n} from \"lucide-react\";\nimport { useFilesContext } from \"../providers/FilesProvider\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { useBrowsePage } from \"../hooks/useBrowsePage\";\nimport { useRecentFiles } from \"../hooks/useRecentFiles\";\nimport { useStarredItems } from \"../hooks/useStarredItems\";\nimport { useBinItems } from \"../hooks/useBinItems\";\nimport { useCreateFolder } from \"../hooks/useCreateFolder\";\nimport { useUploadFile } from \"../hooks/useUploadFile\";\nimport { useDeleteFile } from \"../hooks/useDeleteFile\";\nimport { useDeleteFolder } from \"../hooks/useDeleteFolder\";\nimport { useRestoreFile } from \"../hooks/useRestoreFile\";\nimport { useRestoreFolder } from \"../hooks/useRestoreFolder\";\nimport { usePermanentlyDeleteFile } from \"../hooks/usePermanentlyDeleteFile\";\nimport { usePermanentlyDeleteFolder } from \"../hooks/usePermanentlyDeleteFolder\";\nimport { useToggleStar } from \"../hooks/useToggleStar\";\nimport { useRenameFile } from \"../hooks/useRenameFile\";\nimport { useRenameFolder } from \"../hooks/useRenameFolder\";\nimport { type CreateShareInput, useCreateShare } from \"../hooks/useCreateShare\";\nimport {\n type CreateFolderShareInput,\n useCreateFolderShare,\n} from \"../hooks/useCreateFolderShare\";\nimport { useCopyFile } from \"../hooks/useCopyFile\";\nimport { useMoveFile } from \"../hooks/useMoveFile\";\nimport { useMoveFolder } from \"../hooks/useMoveFolder\";\nimport { useBulkDelete } from \"../hooks/useBatchOperations\";\nimport { type SearchFilters, useSearch } from \"../hooks/useSearch\";\nimport { useToast } from \"../hooks/useToast\";\nimport { FileBrowser } from \"../components/FileBrowser\";\nimport { TabBar, type TabView } from \"../components/TabBar\";\nimport { ShareDialog, type ShareDialogInput } from \"../components/ShareDialog\";\nimport { FilePreviewModal } from \"../components/FilePreviewModal\";\nimport { FileInfoPanel } from \"../components/FileInfoPanel\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { ToastContainer } from \"../components/Toast\";\nimport { SearchBar } from \"../components/SearchBar\";\nimport { MoveDialog } from \"../components/MoveDialog\";\nimport { CopyDialog } from \"../components/CopyDialog\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { UploadQueue } from \"../components/UploadQueue\";\nimport { StorageBanner } from \"../components/StorageBanner\";\nimport { useStorageQuota } from \"../hooks/useStorageQuota\";\nimport type { FileItem, FolderItem, UploadItem } from \"../types\";\nimport type { FilesEventName } from \"../utils/events\";\nimport { isQuotaExhaustedError } from \"../utils/quotaUtils\";\nimport {\n nativeImpact,\n nativeNotify,\n nativeOpenUrl,\n} from \"../../utils/nativeBridge\";\nimport { emitFilesEvent } from \"../utils/events\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport { generateThumbnail } from \"../utils\";\n\ninterface ShareDialogResult {\n publicUrl: string;\n token: string;\n}\n\ninterface ConfirmDialogState {\n title: string;\n description: string;\n confirmLabel: string;\n variant?: \"danger\" | \"default\";\n onConfirm: () => Promise<void> | void;\n loading?: boolean;\n}\n\n/**\n * BrowserPage - Main file browser with toolbar and view modes\n */\nexport function BrowserPage() {\n const { t } = useI18n();\n const { folderId } = useParams<{ folderId: string }>();\n const navigate = useNavigate();\n const filesContext = useFilesContext();\n const { workspaceId } = filesContext;\n const storageQuota = useStorageQuota(workspaceId ?? \"\");\n const {\n viewMode,\n setViewMode,\n breadcrumbs,\n selectedFiles,\n selectedFolders,\n clearSelection,\n } = useFilesStore();\n\n // Tab state\n const [activeTab, setActiveTab] = useState<TabView>(\"all\");\n\n // All browser sections are shown unconditionally. Bin and Starred are first\n // -class tabs (not feature-flag-gated): the backend serves their queries\n // directly (subject to RBAC), so there is nothing to gate on the client.\n const enabledTabs = useMemo<TabView[]>(() => {\n return [\"all\", \"recent\", \"starred\", \"bin\"];\n }, []);\n\n // Defensive: if the active tab is ever not in the rendered set, fall back to\n // \"all\" instead of leaving the user on a blank screen.\n useEffect(() => {\n if (!enabledTabs.includes(activeTab)) {\n setActiveTab(\"all\");\n }\n }, [enabledTabs, activeTab]);\n\n const pageSize = 100;\n\n // Search state\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [searchFilters, setSearchFilters] = useState<SearchFilters>();\n const isSearching = searchQuery.trim().length >= 2;\n\n // Info panel state\n const [infoPanel, setInfoPanel] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n\n // Preview state\n const [previewFile, setPreviewFile] = useState<FileItem | null>(null);\n\n // Toast notifications\n const toast = useToast();\n\n // Fetch data based on active tab. Each view owns one composed page query so\n // files, folders, and folder context travel in a single GraphQL operation.\n const browsePageQuery = useBrowsePage({\n folderId: folderId || undefined,\n pageSize,\n skip: activeTab !== \"all\" || isSearching,\n });\n const recentFilesQuery = useRecentFiles({\n skip: activeTab !== \"recent\" || isSearching,\n });\n const starredItemsQuery = useStarredItems({\n skip: activeTab !== \"starred\" || isSearching,\n });\n const binItemsQuery = useBinItems({\n skip: activeTab !== \"bin\" || isSearching,\n });\n\n const searchResults = useSearch(searchQuery, isSearching, searchFilters);\n\n // Update breadcrumbs when folder path data changes\n useEffect(() => {\n if (\n folderId &&\n browsePageQuery.data?.folderPath &&\n browsePageQuery.data?.currentFolder\n ) {\n // Combine parent folders with current folder\n const parentFolders = browsePageQuery.data.folderPath.folders || [];\n const currentFolder = browsePageQuery.data.currentFolder;\n const breadcrumbPath = [\n ...parentFolders.map((f: { id: string; name: string }) => ({\n id: f.id,\n name: f.name,\n })),\n { id: currentFolder.id, name: currentFolder.name },\n ];\n useFilesStore.getState().setBreadcrumbs(breadcrumbPath);\n } else {\n useFilesStore.getState().setBreadcrumbs([]);\n }\n }, [folderId, browsePageQuery.data]);\n\n // Determine which data to display based on search state\n let files: FileItem[] = [];\n let folders: FolderItem[] = [];\n let loading = false;\n let error: Error | null = null;\n let preserveSortOrder = false; // For Recent/Bin tabs - skip re-sorting\n\n // If searching, use search results\n if (isSearching && searchResults.data) {\n files = searchResults.data.files || [];\n folders = searchResults.data.folders || [];\n loading = searchResults.isLoading;\n error = searchResults.error as Error | null;\n } else {\n // Show data based on active tab\n switch (activeTab) {\n case \"all\":\n files = (browsePageQuery.data?.filesList?.files || []) as FileItem[];\n folders = (browsePageQuery.data?.foldersList?.folders ||\n []) as FolderItem[];\n loading = browsePageQuery.loading;\n error = (browsePageQuery.error as Error) || null;\n preserveSortOrder = false;\n break;\n case \"recent\":\n files = recentFilesQuery.files || [];\n folders = recentFilesQuery.folders || [];\n loading = recentFilesQuery.isLoading;\n error = (recentFilesQuery.error as Error) || null;\n preserveSortOrder = true; // Recent tab already sorted by backend\n break;\n case \"starred\":\n files = starredItemsQuery.files;\n folders = starredItemsQuery.folders;\n loading = starredItemsQuery.isLoading;\n error = (starredItemsQuery.error as Error) || null;\n preserveSortOrder = true;\n break;\n case \"bin\":\n files = binItemsQuery.files;\n folders = binItemsQuery.folders;\n loading = binItemsQuery.isLoading;\n error = (binItemsQuery.error as Error) || null;\n preserveSortOrder = true; // Bin tab already sorted by backend\n break;\n }\n }\n\n const totalItemsInCurrentView =\n activeTab === \"all\"\n ? (browsePageQuery.data?.filesList?.total ?? files.length) +\n (browsePageQuery.data?.foldersList?.total ?? folders.length)\n : null;\n\n const totalSelected = selectedFiles.size + selectedFolders.size;\n const [showNewFolderDialog, setShowNewFolderDialog] = useState(false);\n const [showFolderQuotaExhausted, setShowFolderQuotaExhausted] =\n useState(false);\n const [showRenameDialog, setShowRenameDialog] = useState(false);\n const [showShareDialog, setShowShareDialog] = useState(false);\n const [showMoveDialog, setShowMoveDialog] = useState(false);\n const [showCopyDialog, setShowCopyDialog] = useState(false);\n const [shareTarget, setShareTarget] = useState<FileItem | FolderItem | null>(\n null,\n );\n const [moveTarget, setMoveTarget] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [copyTarget, setCopyTarget] = useState<{\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [renameTarget, setRenameTarget] = useState<{\n id: string;\n name: string;\n type: \"file\" | \"folder\";\n } | null>(null);\n const [newName, setNewName] = useState(\"\");\n const [newFolderName, setNewFolderName] = useState(\"\");\n const [uploading, setUploading] = useState(false);\n const [uploadQueue, setUploadQueue] = useState<UploadItem[]>([]);\n const [isUploadPanelOpen, setIsUploadPanelOpen] = useState(false);\n const [confirmDialog, setConfirmDialog] = useState<ConfirmDialogState | null>(\n null,\n );\n\n const emitEvent = (\n name: FilesEventName,\n payload: Record<string, unknown>,\n ) => {\n emitFilesEvent(filesContext, name, payload);\n };\n\n const runConfirmedAction = async () => {\n if (!confirmDialog || confirmDialog.loading) return;\n\n const action = confirmDialog.onConfirm;\n setConfirmDialog({ ...confirmDialog, loading: true });\n try {\n await action();\n setConfirmDialog(null);\n } catch (error) {\n emitEvent(\"files.api.failed\", {\n action: \"confirmDialog\",\n message:\n error instanceof Error ? error.message : \"Confirmed action failed\",\n });\n setConfirmDialog((current) =>\n current ? { ...current, loading: false } : current,\n );\n }\n };\n\n // Mutations\n const createFolderMutation = useCreateFolder();\n const uploadFileMutation = useUploadFile();\n const deleteFileMutation = useDeleteFile();\n const deleteFolderMutation = useDeleteFolder();\n const restoreFileMutation = useRestoreFile();\n const restoreFolderMutation = useRestoreFolder();\n const permanentlyDeleteFileMutation = usePermanentlyDeleteFile();\n const permanentlyDeleteFolderMutation = usePermanentlyDeleteFolder();\n const toggleStarMutation = useToggleStar();\n const renameFileMutation = useRenameFile();\n const renameFolderMutation = useRenameFolder();\n const createShareMutation = useCreateShare();\n const createFolderShareMutation = useCreateFolderShare();\n const copyFileMutation = useCopyFile();\n const moveFileMutation = useMoveFile();\n const moveFolderMutation = useMoveFolder();\n const bulkDeleteMutation = useBulkDelete();\n\n // Action handlers\n const handleUploadClick = () => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.multiple = true;\n input.onchange = async (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files && files.length > 0) {\n const newItems: UploadItem[] = await Promise.all(\n Array.from(files).map(async (file, index) => {\n const thumbnailUrl = await generateThumbnail(file);\n return {\n id: `${Date.now()}-${index}-${file.name}`,\n file,\n status: \"pending\" as const,\n progress: 0,\n folderId: folderId || undefined,\n thumbnailUrl: thumbnailUrl ?? undefined,\n };\n }),\n );\n setUploadQueue((prev) => [...prev, ...newItems]);\n setIsUploadPanelOpen(true);\n setUploading(true);\n\n for (const item of newItems) {\n await processUpload(item);\n }\n setUploading(false);\n }\n };\n input.click();\n };\n\n const processUpload = async (item: UploadItem) => {\n const updateItem = (updates: Partial<UploadItem>) => {\n setUploadQueue((prev) =>\n prev.map((i) => (i.id === item.id ? { ...i, ...updates } : i)),\n );\n };\n\n updateItem({ status: \"uploading\" });\n\n try {\n const uploadedFile = await uploadFileMutation.mutateAsync({\n file: item.file,\n folderId: item.folderId,\n onProgress: (progress) => {\n updateItem({ progress });\n },\n });\n updateItem({ status: \"completed\", progress: 100 });\n emitEvent(\"files.file.uploaded\", {\n fileId: uploadedFile.id,\n fileName: uploadedFile.name,\n folderId: item.folderId,\n });\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : tWithFallback(t, \"files.upload.errors.failed\", \"Upload failed\");\n if (errorMessage === \"Upload paused\") {\n updateItem({ status: \"paused\" });\n } else if (errorMessage === \"QUOTA_EXHAUSTED\") {\n updateItem({\n status: \"failed\",\n error: tWithFallback(\n t,\n \"files.upload.errors.quotaExceeded\",\n \"Storage quota exceeded\",\n ),\n });\n toast.error(\n tWithFallback(\n t,\n \"files.upload.errors.quotaExceeded\",\n \"Storage quota exceeded. Please upgrade your plan or delete files.\",\n ),\n );\n } else {\n updateItem({ status: \"failed\", error: errorMessage });\n emitEvent(\"files.api.failed\", {\n action: \"uploadFile\",\n fileName: item.file.name,\n message: errorMessage,\n });\n }\n }\n };\n\n const handlePauseUpload = (id: string) => {\n uploadFileMutation.pause();\n setUploadQueue((prev) =>\n prev.map((i) => (i.id === id ? { ...i, status: \"paused\" as const } : i)),\n );\n };\n\n const handleResumeUpload = (id: string) => {\n const item = uploadQueue.find((i) => i.id === id);\n if (item) {\n processUpload(item);\n }\n };\n\n const handleRetryUpload = (id: string) => {\n const item = uploadQueue.find((i) => i.id === id);\n if (item) {\n setUploadQueue((prev) =>\n prev.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"pending\" as const,\n progress: 0,\n error: undefined,\n }\n : i,\n ),\n );\n processUpload(item);\n }\n };\n\n const handleCancelUpload = (id: string) => {\n setUploadQueue((prev) => {\n const remaining = prev.filter((i) => i.id !== id);\n if (remaining.length === 0) {\n setIsUploadPanelOpen(false);\n setUploading(false);\n }\n return remaining;\n });\n };\n\n // Folder upload handler - uploads entire folder with structure\n const handleFolderUploadClick = () => {\n if (!workspaceId) {\n toast.error(\n tWithFallback(\n t,\n \"files.workspace.errors.notSelected\",\n \"Workspace not selected\",\n ),\n );\n return;\n }\n\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.webkitdirectory = true;\n input.onchange = async (e) => {\n const files = (e.target as HTMLInputElement).files;\n if (files && files.length > 0) {\n const filesByFolder = new Map<string, File[]>();\n for (const file of Array.from(files)) {\n const relativePath = file.webkitRelativePath || file.name;\n const pathParts = relativePath.split(\"/\");\n const folderPath = pathParts.slice(0, -1).join(\"/\");\n\n if (!filesByFolder.has(folderPath)) {\n filesByFolder.set(folderPath, []);\n }\n filesByFolder.get(folderPath)!.push(file);\n }\n\n const folderIdMap = new Map<string, string>();\n const sortedPaths = Array.from(filesByFolder.keys()).sort();\n\n for (const folderPath of sortedPaths) {\n if (!folderPath) continue;\n\n const pathParts = folderPath.split(\"/\");\n let currentPath = \"\";\n let parentId = folderId || undefined;\n\n for (const part of pathParts) {\n currentPath = currentPath ? `${currentPath}/${part}` : part;\n\n if (!folderIdMap.has(currentPath)) {\n try {\n const { data: createdFolder } =\n await createFolderMutation.mutateAsync({\n name: part,\n parentFolderId: parentId,\n });\n if (createdFolder?.id) {\n folderIdMap.set(currentPath, createdFolder.id);\n parentId = createdFolder.id;\n }\n } catch {\n // Continue best-effort\n }\n } else {\n parentId = folderIdMap.get(currentPath);\n }\n }\n }\n\n const newItems: UploadItem[] = [];\n let index = 0;\n for (const [folderPath, folderFiles] of filesByFolder) {\n const targetFolderId = folderPath\n ? folderIdMap.get(folderPath)\n : folderId || undefined;\n\n for (const file of folderFiles) {\n const thumbnailUrl = await generateThumbnail(file);\n newItems.push({\n id: `${Date.now()}-${index++}-${file.name}`,\n file,\n status: \"pending\",\n progress: 0,\n folderId: targetFolderId,\n thumbnailUrl: thumbnailUrl ?? undefined,\n });\n }\n }\n\n setUploadQueue((prev) => [...prev, ...newItems]);\n setIsUploadPanelOpen(true);\n setUploading(true);\n\n for (const item of newItems) {\n await processUpload(item);\n }\n setUploading(false);\n\n toast.success(\n tWithFallback(\n t,\n \"files.upload.folder.success\",\n \"Uploaded {{count}} file{{plural}} from folder\",\n { count: newItems.length, plural: newItems.length > 1 ? \"s\" : \"\" },\n ),\n );\n }\n };\n input.click();\n };\n\n const handleNewFolderClick = () => {\n setShowNewFolderDialog(true);\n };\n\n const handleCreateFolder = async () => {\n if (newFolderName.trim() && workspaceId) {\n const { data: createdFolder, error } =\n await createFolderMutation.mutateAsync({\n name: newFolderName,\n parentFolderId: folderId,\n });\n\n if (error) {\n if (isQuotaExhaustedError(error)) {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n setShowFolderQuotaExhausted(true);\n } else {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.createFailed\",\n \"Folder creation failed\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"createFolder\",\n message:\n error instanceof Error ? error.message : \"Folder creation failed\",\n });\n }\n return;\n }\n\n if (createdFolder) {\n setNewFolderName(\"\");\n setShowNewFolderDialog(false);\n emitEvent(\"files.folder.created\", {\n folderName: newFolderName,\n parentFolderId: folderId,\n });\n }\n }\n };\n\n // File action handlers\n const handleFilePreview = (file: FileItem) => {\n setPreviewFile(file);\n };\n\n const handleFileShare = (file: FileItem) => {\n setShareTarget(file);\n setShowShareDialog(true);\n };\n\n const handleFolderShare = (folder: FolderItem) => {\n setShareTarget(folder);\n setShowShareDialog(true);\n };\n\n const handleCreateShare = async (\n input: ShareDialogInput,\n ): Promise<ShareDialogResult> => {\n if (!input.fileId && !input.folderId) {\n throw new Error(\n tWithFallback(\n t,\n \"files.share.errors.targetRequired\",\n \"Share requires a file id or folder id\",\n ),\n );\n }\n\n const shareType = input.invitedEmail ? \"EMAIL_INVITE\" : \"PUBLIC_LINK\";\n let token = \"\";\n\n if (input.fileId) {\n // File share\n const shareInput: CreateShareInput = {\n fileId: input.fileId,\n expiresAt: input.expiresAt,\n maxDownloads: input.maxDownloads,\n password: input.password,\n invitedEmail: input.invitedEmail,\n shareType,\n accessLevel: \"DOWNLOAD\" as const,\n };\n const result = await createShareMutation.mutateAsync(shareInput);\n token = result?.token ?? \"\";\n emitEvent(\"files.share.created\", {\n entityType: \"file\",\n fileId: input.fileId,\n shareType,\n });\n } else if (input.folderId) {\n // Folder share\n const shareInput: CreateFolderShareInput = {\n folderId: input.folderId,\n expiresAt: input.expiresAt,\n maxDownloads: input.maxDownloads,\n password: input.password,\n invitedEmail: input.invitedEmail,\n shareType,\n accessLevel: \"DOWNLOAD\" as const,\n };\n const result = await createFolderShareMutation.mutateAsync(shareInput);\n token = result?.createFolderShare?.token ?? \"\";\n emitEvent(\"files.share.created\", {\n entityType: \"folder\",\n folderId: input.folderId,\n shareType,\n });\n }\n\n return {\n publicUrl: token ? `${window.location.origin}/files/share/${token}` : \"\",\n token,\n };\n };\n\n const handleFileDelete = async (file: FileItem) => {\n nativeImpact(\"medium\");\n setConfirmDialog({\n title: tWithFallback(t, \"files.confirm.deleteFile.title\", \"Delete file\"),\n description: tWithFallback(\n t,\n \"files.confirm.deleteFile.description\",\n 'Move \"{{name}}\" to the bin?',\n { name: file.name },\n ),\n confirmLabel: tWithFallback(t, \"files.common.actions.delete\", \"Delete\"),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteFileMutation.mutateAsync({ id: file.id });\n nativeNotify(\"success\");\n toast.success(\n tWithFallback(\n t,\n \"files.file.delete.success\",\n '\"{{name}}\" moved to bin',\n { name: file.name },\n ),\n );\n emitEvent(\"files.file.deleted\", {\n fileId: file.id,\n fileName: file.name,\n permanent: false,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.deleteFailed\",\n 'Failed to delete \"{{name}}\"',\n { name: file.name },\n ),\n );\n nativeNotify(\"error\");\n emitEvent(\"files.api.failed\", {\n action: \"deleteFile\",\n fileId: file.id,\n message:\n error instanceof Error ? error.message : \"Failed to delete file\",\n });\n }\n },\n });\n };\n\n const handleFileRestore = async (file: FileItem) => {\n try {\n await restoreFileMutation.mutateAsync({ id: file.id });\n toast.success(\n tWithFallback(t, \"files.file.restore.success\", '\"{{name}}\" restored', {\n name: file.name,\n }),\n );\n emitEvent(\"files.file.restored\", {\n fileId: file.id,\n fileName: file.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.restoreFailed\",\n \"Failed to restore file\",\n ),\n );\n }\n };\n\n const handleFilePermanentDelete = async (file: FileItem) => {\n nativeImpact(\"heavy\");\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFile.title\",\n \"Permanently delete file\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFile.description\",\n 'Permanently delete \"{{name}}\"? This cannot be undone.',\n { name: file.name },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await permanentlyDeleteFileMutation.mutateAsync({ id: file.id });\n toast.success(\n tWithFallback(\n t,\n \"files.file.permanentDelete.success\",\n '\"{{name}}\" deleted permanently',\n { name: file.name },\n ),\n );\n emitEvent(\"files.file.deleted\", {\n fileId: file.id,\n fileName: file.name,\n permanent: true,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.permanentDeleteFailed\",\n \"Failed to permanently delete file\",\n ),\n );\n }\n },\n });\n };\n\n const handleFileFavorite = async (file: FileItem) => {\n try {\n await toggleStarMutation.mutateAsync({ id: file.id, type: \"file\" });\n emitEvent(\"files.file.starred\", {\n fileId: file.id,\n fileName: file.name,\n starred: !file.starred,\n });\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.file.errors.starFailed\",\n \"Failed to update starred state\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"toggleFileStar\",\n fileId: file.id,\n });\n }\n };\n\n const handleFileRename = (file: FileItem) => {\n setRenameTarget({ id: file.id, name: file.name, type: \"file\" });\n setNewName(file.name);\n setShowRenameDialog(true);\n };\n\n const handleFileDownload = async (file: FileItem) => {\n try {\n const downloadUrl = file.downloadUrl || file.url;\n\n if (!downloadUrl) {\n throw new Error(\n tWithFallback(\n t,\n \"files.file.errors.downloadUrlUnavailable\",\n \"Download URL is unavailable\",\n ),\n );\n }\n\n const a = document.createElement(\"a\");\n a.style.display = \"none\";\n a.href = downloadUrl;\n a.download = file.name;\n a.rel = \"noopener noreferrer\";\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n\n toast.success(\n tWithFallback(t, \"files.file.download.success\", \"Downloaded {{name}}\", {\n name: file.name,\n }),\n );\n emitEvent(\"files.file.downloaded\", {\n fileId: file.id,\n fileName: file.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.downloadFailed\",\n \"Failed to download file\",\n ),\n );\n }\n };\n\n const handleFileCopy = (file: FileItem) => {\n setCopyTarget({ item: file, type: \"file\" });\n setShowCopyDialog(true);\n };\n\n const handleFileMove = (file: FileItem) => {\n setMoveTarget({ item: file, type: \"file\" });\n setShowMoveDialog(true);\n };\n\n const handleFileInfoClick = (file: FileItem) => {\n setInfoPanel({ item: file, type: \"file\" });\n };\n\n // Folder action handlers\n const handleFolderOpen = (folder: FolderItem) => {\n // Navigate to folder by updating URL\n navigate(`/files/browse/${folder.id}`);\n };\n\n const handleFolderDelete = async (folder: FolderItem) => {\n nativeImpact(\"medium\");\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.deleteFolder.title\",\n \"Delete folder\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.deleteFolder.description\",\n 'Move folder \"{{name}}\" and all its contents to the bin?',\n { name: folder.name },\n ),\n confirmLabel: tWithFallback(t, \"files.common.actions.delete\", \"Delete\"),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteFolderMutation.mutateAsync({\n id: folder.id,\n recursive: true,\n });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.delete.success\",\n '\"{{name}}\" moved to bin',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.deleted\", {\n folderId: folder.id,\n folderName: folder.name,\n permanent: false,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.deleteFailed\",\n \"Failed to delete folder\",\n ),\n );\n }\n },\n });\n };\n\n const handleFolderRestore = async (folder: FolderItem) => {\n try {\n await restoreFolderMutation.mutateAsync({ id: folder.id });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.restore.success\",\n '\"{{name}}\" restored',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.restored\", {\n folderId: folder.id,\n folderName: folder.name,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.restoreFailed\",\n \"Failed to restore folder\",\n ),\n );\n }\n };\n\n const handleFolderPermanentDelete = async (folder: FolderItem) => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFolder.title\",\n \"Permanently delete folder\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.permanentDeleteFolder.description\",\n 'Permanently delete folder \"{{name}}\" and its contents? This cannot be undone.',\n { name: folder.name },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await permanentlyDeleteFolderMutation.mutateAsync({ id: folder.id });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.permanentDelete.success\",\n '\"{{name}}\" deleted permanently',\n { name: folder.name },\n ),\n );\n emitEvent(\"files.folder.deleted\", {\n folderId: folder.id,\n folderName: folder.name,\n permanent: true,\n });\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.folder.errors.permanentDeleteFailed\",\n \"Failed to permanently delete folder\",\n ),\n );\n }\n },\n });\n };\n\n const handleFolderRename = (folder: FolderItem) => {\n setRenameTarget({ id: folder.id, name: folder.name, type: \"folder\" });\n setNewName(folder.name);\n setShowRenameDialog(true);\n };\n\n const handleFolderMove = (folder: FolderItem) => {\n setMoveTarget({ item: folder, type: \"folder\" });\n setShowMoveDialog(true);\n };\n\n const handleFolderFavorite = async (folder: FolderItem) => {\n try {\n await toggleStarMutation.mutateAsync({ id: folder.id, type: \"folder\" });\n emitEvent(\"files.folder.starred\", {\n folderId: folder.id,\n folderName: folder.name,\n starred: !folder.starred,\n });\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.folder.errors.starFailed\",\n \"Failed to update starred state\",\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"toggleFolderStar\",\n folderId: folder.id,\n });\n }\n };\n\n const handleFolderInfoClick = (folder: FolderItem) => {\n setInfoPanel({ item: folder, type: \"folder\" });\n };\n\n // Move and Copy handlers\n const handleMoveSubmit = async (destinationFolderId: string | null) => {\n if (!moveTarget) return;\n\n try {\n if (moveTarget.type === \"file\") {\n await moveFileMutation.mutateAsync({\n fileId: moveTarget.item.id,\n targetFolderId: destinationFolderId || null,\n });\n toast.success(\n tWithFallback(t, \"files.file.move.success\", '\"{{name}}\" moved', {\n name: moveTarget.item.name,\n }),\n );\n emitEvent(\"files.file.moved\", {\n fileId: moveTarget.item.id,\n fileName: moveTarget.item.name,\n destinationFolderId,\n });\n } else {\n await moveFolderMutation.mutateAsync({\n folderId: moveTarget.item.id,\n targetParentFolderId: destinationFolderId,\n });\n toast.success(\n tWithFallback(t, \"files.folder.move.success\", '\"{{name}}\" moved', {\n name: moveTarget.item.name,\n }),\n );\n emitEvent(\"files.folder.moved\", {\n folderId: moveTarget.item.id,\n folderName: moveTarget.item.name,\n destinationFolderId,\n });\n }\n setShowMoveDialog(false);\n setMoveTarget(null);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.item.errors.moveFailed\",\n 'Failed to move \"{{name}}\"',\n {\n name: moveTarget.item.name,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: moveTarget.type === \"file\" ? \"moveFile\" : \"moveFolder\",\n itemId: moveTarget.item.id,\n itemType: moveTarget.type,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleCopySubmit = async (\n destinationFolderId: string | null,\n newName?: string,\n ) => {\n if (!copyTarget) return;\n\n try {\n if (copyTarget.type !== \"file\") {\n throw new Error(\n tWithFallback(\n t,\n \"files.folder.errors.copyUnsupported\",\n \"Folder copy is not supported\",\n ),\n );\n }\n\n await copyFileMutation.mutateAsync({\n id: copyTarget.item.id,\n newName: newName || `Copy of ${copyTarget.item.name}`,\n targetFolderId: destinationFolderId || undefined,\n });\n toast.success(\n tWithFallback(t, \"files.file.copy.success\", '\"{{name}}\" copied', {\n name: copyTarget.item.name,\n }),\n );\n emitEvent(\"files.file.copied\", {\n fileId: copyTarget.item.id,\n fileName: copyTarget.item.name,\n destinationFolderId,\n });\n\n setShowCopyDialog(false);\n setCopyTarget(null);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.file.errors.copyFailed\",\n 'Failed to copy \"{{name}}\"',\n {\n name: copyTarget.item.name,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: \"copyFile\",\n fileId: copyTarget.item.id,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleRenameSubmit = async () => {\n if (!renameTarget || !newName.trim()) return;\n\n try {\n const previousName = renameTarget.name;\n const nextName = newName.trim();\n\n if (renameTarget.type === \"file\") {\n await renameFileMutation.mutateAsync({\n fileId: renameTarget.id,\n newName: nextName,\n });\n toast.success(\n tWithFallback(t, \"files.file.rename.success\", 'Renamed \"{{name}}\"', {\n name: nextName,\n }),\n );\n emitEvent(\"files.file.renamed\", {\n fileId: renameTarget.id,\n previousName,\n name: nextName,\n });\n } else {\n await renameFolderMutation.mutateAsync({\n folderId: renameTarget.id,\n newName: nextName,\n });\n toast.success(\n tWithFallback(\n t,\n \"files.folder.rename.success\",\n 'Renamed \"{{name}}\"',\n {\n name: nextName,\n },\n ),\n );\n emitEvent(\"files.folder.renamed\", {\n folderId: renameTarget.id,\n previousName,\n name: nextName,\n });\n }\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.item.errors.renameFailed\",\n \"Failed to rename {{type}}\",\n {\n type: renameTarget.type,\n },\n ),\n );\n emitEvent(\"files.api.failed\", {\n action: renameTarget.type === \"file\" ? \"renameFile\" : \"renameFolder\",\n itemId: renameTarget.id,\n itemType: renameTarget.type,\n message: error instanceof Error ? error.message : undefined,\n });\n }\n };\n\n const handleSearch = (query: string, filters?: SearchFilters) => {\n setSearchQuery(query);\n setSearchFilters(filters);\n };\n\n useKeyboardNavigation({\n files,\n folders,\n onFilePreview: handleFilePreview,\n onFileDelete: handleFileDelete,\n onFolderOpen: handleFolderOpen,\n onFolderDelete: handleFolderDelete,\n activeTab,\n });\n\n // Guard: if the host shell hasn't pushed workspace context yet, render a\n // clear loading state rather than firing queries with an undefined workspace\n // (which used to manifest as a silent blank screen).\n // NOTE: We explicitly check for undefined (not yet provided) vs empty string\n // (explicitly no workspace selected) to show appropriate messaging.\n if (workspaceId === undefined) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[60vh] gap-3 text-center px-6\">\n <Loader2 className=\"size-8 animate-spin text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary max-w-md\">\n {tWithFallback(\n t,\n \"files.browser.workspace.waiting\",\n \"Waiting for workspace context. If this persists, the app shell may not have provided a workspaceId to the Files module. Try reloading the page or switching workspaces.\",\n )}\n </p>\n </div>\n );\n }\n\n // Empty string means host shell provided context but no workspace is selected\n if (workspaceId === \"\") {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-[60vh] gap-3 text-center px-6\">\n <FolderX className=\"size-8 text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary max-w-md\">\n {tWithFallback(\n t,\n \"files.browser.workspace.notSelected\",\n \"No workspace selected. Please select a workspace to view files.\",\n )}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-screen bg-bg-surface\">\n {/* Google Drive-style Header with Breadcrumb Navigation. The hero zone\n carries the single per-MFE aurora backdrop (subtle, behind content,\n reduced-motion-safe) for real-glass depth. */}\n <div\n className=\"relative overflow-hidden bg-bg-surface border-b border-border-seam px-4 py-3 sm:px-6 sm:py-4\"\n data-tour=\"files-breadcrumb-nav\"\n >\n <AuroraBackground intensity=\"subtle\" />\n <h1 className=\"mb-2 text-lg font-semibold tracking-tight sm:text-xl\">\n <GradientText>\n {tWithFallback(t, \"files.browser.rootLabel\", \"My Drive\")}\n </GradientText>\n </h1>\n <div className=\"flex items-center gap-2 sm:gap-4\">\n <div className=\"flex items-center gap-1 sm:gap-2 text-sm overflow-x-auto\">\n <button\n type=\"button\"\n onClick={() => navigate(\"/files/browse\")}\n className=\"flex items-center gap-1 text-text-primary hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap\"\n title={tWithFallback(\n t,\n \"files.browser.actions.goToRoot\",\n \"Go to root\",\n )}\n >\n <Home className=\"size-4\" />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, \"files.browser.rootLabel\", \"My Drive\")}\n </span>\n </button>\n {breadcrumbs.map((crumb, index) => (\n <div key={crumb.id} className=\"flex items-center gap-1 sm:gap-2\">\n <span className=\"text-text-tertiary\">/</span>\n <button\n type=\"button\"\n onClick={() => navigate(`/files/browse/${crumb.id}`)}\n className={`hover:bg-action-ghost-bg-hover px-2 py-1 rounded transition-colors duration-200 whitespace-nowrap ${\n index === breadcrumbs.length - 1\n ? \"text-text-primary font-medium\"\n : \"text-text-secondary\"\n }`}\n title={`Go to ${crumb.name}`}\n >\n {crumb.name}\n </button>\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Navigation Tabs */}\n <div data-tour=\"files-tab-bar\">\n <TabBar\n activeTab={activeTab}\n onTabChange={setActiveTab}\n tabs={enabledTabs}\n />\n </div>\n\n {/* Google Drive-style Toolbar */}\n <div className=\"bg-bg-surface border-b border-border-seam px-4 py-2 sm:px-6 sm:py-3\">\n <div className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-inline-gap\">\n {/* Left side - Search */}\n <div\n className=\"w-full sm:flex-1 min-w-0 order-2 sm:order-1\"\n data-tour=\"files-search-bar\"\n >\n <div className=\"relative w-full max-w-2xl\">\n <SearchBar\n onSearch={handleSearch}\n placeholder={tWithFallback(\n t,\n \"files.search.input.placeholder\",\n \"Search files and folders...\",\n )}\n initialQuery={searchQuery}\n showFilters={true}\n />\n </div>\n </div>\n\n {/* Right side - Actions: one primary CTA (Upload Files), the rest\n collapsed into an overflow menu to keep the toolbar uncluttered. */}\n <div className=\"flex items-center gap-2 order-1 sm:order-2 w-full sm:w-auto justify-between sm:justify-end\">\n {!isSearching && (\n <div data-tour=\"files-upload-files-button\">\n <CTAOverflowMenu\n primary={{\n label: uploading\n ? tWithFallback(\n t,\n \"files.browser.upload.uploading\",\n \"Uploading...\",\n )\n : tWithFallback(\n t,\n \"files.browser.actions.uploadFiles\",\n \"Upload Files\",\n ),\n onSelect: handleUploadClick,\n disabled: uploading,\n icon: uploading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Upload className=\"size-4\" />\n ),\n }}\n actions={[\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.newFolder\",\n \"New Folder\",\n ),\n icon: <FolderPlus className=\"size-4\" />,\n onSelect: handleNewFolderClick,\n },\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.uploadFolder\",\n \"Upload Folder\",\n ),\n icon: <FolderUp className=\"size-4\" />,\n onSelect: handleFolderUploadClick,\n disabled: uploading,\n },\n ...(files.length > 0 || folders.length > 0\n ? [\n {\n label: tWithFallback(\n t,\n \"files.browser.actions.selectAll\",\n \"Select All\",\n ),\n onSelect: () => {\n const allFileIds = files.map((f) => f.id);\n const allFolderIds = folders.map((f) => f.id);\n useFilesStore\n .getState()\n .selectAllFiles(allFileIds);\n allFolderIds.forEach((id) =>\n useFilesStore.getState().selectFolder(id),\n );\n },\n },\n ]\n : []),\n ]}\n />\n </div>\n )}\n\n {/* View mode toggle */}\n <div\n className=\"flex items-center border border-border-seam rounded-lg overflow-hidden\"\n data-tour=\"files-view-mode-toggle\"\n >\n <button\n type=\"button\"\n onClick={() => setViewMode(\"grid\")}\n className={`p-2 transition-colors duration-200 ${\n viewMode === \"grid\"\n ? \"bg-bg-accent text-text-link\"\n : \"text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n aria-label={tWithFallback(\n t,\n \"files.browser.view.grid\",\n \"Grid view\",\n )}\n >\n <Grid3x3 className=\"size-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode(\"list\")}\n className={`p-2 transition-colors duration-200 ${\n viewMode === \"list\"\n ? \"bg-bg-accent text-text-link\"\n : \"text-text-secondary hover:bg-action-ghost-bg-hover\"\n }`}\n aria-label={tWithFallback(\n t,\n \"files.browser.view.list\",\n \"List view\",\n )}\n >\n <List className=\"size-5\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Search results indicator */}\n {isSearching && (\n <div className=\"mt-3 flex items-center justify-between p-3 bg-status-success-bg-subtle rounded-lg border border-status-success-border transition-all duration-200\">\n <span className=\"text-sm font-medium text-status-success-text\">\n {tWithFallback(\n t,\n \"files.browser.search.showingResults\",\n 'Showing search results for \"{{query}}\"',\n { query: searchQuery },\n )}\n {searchResults.data &&\n ` (${(searchResults.data.files?.length || 0) + (searchResults.data.folders?.length || 0)} items)`}\n </span>\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"flex items-center gap-2 text-status-success-text hover:text-status-success-text/80 text-sm font-medium transition-colors duration-200\"\n >\n <X className=\"size-4\" />\n {tWithFallback(t, \"files.browser.search.clear\", \"Clear search\")}\n </button>\n </div>\n )}\n\n {/* Selection info with bulk actions — emphasised as the single primary\n action zone while a selection is active. */}\n {totalSelected > 0 && (\n <EmphasisPanel className=\"mt-3 flex items-center justify-between p-3\">\n <div className=\"flex items-center gap-4\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(\n t,\n \"files.browser.selection.selectedCount\",\n \"{{count}} item{{suffix}} selected\",\n {\n count: totalSelected,\n suffix: totalSelected > 1 ? \"s\" : \"\",\n },\n )}\n </span>\n\n {/* Bulk action buttons */}\n <div className=\"flex items-center gap-2\">\n {activeTab === \"bin\" ? (\n <>\n <button\n type=\"button\"\n onClick={async () => {\n try {\n await Promise.all([\n ...Array.from(selectedFiles).map((fileId) =>\n restoreFileMutation.mutateAsync({ id: fileId }),\n ),\n ...Array.from(selectedFolders).map((folderId) =>\n restoreFolderMutation.mutateAsync({\n id: folderId,\n }),\n ),\n ]);\n\n clearSelection();\n toast.success(\n `${totalSelected} item${totalSelected > 1 ? \"s\" : \"\"} restored`,\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : \"Failed to restore some items\",\n );\n }\n }}\n className=\"flex items-center gap-1.5 rounded-lg border border-status-success-border bg-bg-surface px-3 py-1.5 text-sm font-medium text-status-success-text transition-colors duration-200 hover:bg-status-success-bg-subtle\"\n >\n {tWithFallback(\n t,\n \"files.browser.selection.actions.restore\",\n \"Restore\",\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={async () => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.bulkPermanentDelete.title\",\n \"Permanently delete selected items\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.bulkPermanentDelete.description\",\n \"Permanently delete {{count}} selected item{{plural}}? This cannot be undone.\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.deletePermanently\",\n \"Delete permanently\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await Promise.all([\n ...Array.from(selectedFiles).map((fileId) =>\n permanentlyDeleteFileMutation.mutateAsync({\n id: fileId,\n }),\n ),\n ...Array.from(selectedFolders).map((folderId) =>\n permanentlyDeleteFolderMutation.mutateAsync({\n id: folderId,\n }),\n ),\n ]);\n\n clearSelection();\n toast.success(\n tWithFallback(\n t,\n \"files.bulk.permanentDelete.success\",\n \"{{count}} item{{plural}} deleted permanently\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.bulk.errors.permanentDeleteFailed\",\n \"Failed to permanently delete some items\",\n ),\n );\n }\n },\n });\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-status-error-text bg-bg-surface border border-status-error-border rounded-lg hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n <Trash2 className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.browser.selection.actions.deletePermanently\",\n \"Delete permanently\",\n )}\n </button>\n </>\n ) : (\n <button\n type=\"button\"\n onClick={async () => {\n setConfirmDialog({\n title: tWithFallback(\n t,\n \"files.confirm.bulkDelete.title\",\n \"Delete selected items\",\n ),\n description: tWithFallback(\n t,\n \"files.confirm.bulkDelete.description\",\n \"Move {{count}} selected item{{plural}} to the bin?\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.common.actions.delete\",\n \"Delete\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n const fileIds = Array.from(selectedFiles);\n const folderIds = Array.from(selectedFolders);\n\n if (fileIds.length > 0) {\n await bulkDeleteMutation.mutateAsync(fileIds);\n }\n\n await Promise.all(\n folderIds.map((folderId) =>\n deleteFolderMutation.mutateAsync({\n id: folderId,\n recursive: true,\n }),\n ),\n );\n\n clearSelection();\n toast.success(\n tWithFallback(\n t,\n \"files.bulk.delete.success\",\n \"{{count}} item{{plural}} moved to bin\",\n {\n count: totalSelected,\n plural: totalSelected > 1 ? \"s\" : \"\",\n },\n ),\n );\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.bulk.errors.deleteFailed\",\n \"Failed to delete some items\",\n ),\n );\n }\n },\n });\n }}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-status-error-text bg-bg-surface border border-status-error-border rounded-lg hover:bg-status-error-bg-subtle transition-colors duration-200\"\n >\n <Trash2 className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.browser.selection.actions.delete\",\n \"Delete\",\n )}\n </button>\n )}\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"flex items-center gap-2 text-text-link hover:text-action-primary-bg-hover text-sm font-medium transition-colors duration-200\"\n >\n <X className=\"size-4\" />\n {tWithFallback(t, \"files.common.actions.clear\", \"Clear\")}\n </button>\n </EmphasisPanel>\n )}\n </div>\n\n {/* Storage quota banner */}\n {(storageQuota.isExhausted || storageQuota.isNearLimit) && (\n <div className=\"px-4 sm:px-6 pt-3\">\n <StorageBanner quota={storageQuota} />\n </div>\n )}\n\n {/* File Browser */}\n <div\n className=\"px-2 sm:px-4 md:px-6 py-3 sm:py-4\"\n data-tour=\"files-browser-grid\"\n >\n <FileBrowser\n files={files}\n folders={folders}\n loading={loading}\n error={error}\n preserveSortOrder={preserveSortOrder}\n onFilePreview={handleFilePreview}\n onFileShare={activeTab === \"bin\" ? undefined : handleFileShare}\n onFileDelete={\n activeTab === \"bin\" ? handleFilePermanentDelete : handleFileDelete\n }\n onFileRestore={activeTab === \"bin\" ? handleFileRestore : undefined}\n onFileFavorite={activeTab === \"bin\" ? undefined : handleFileFavorite}\n onFileRename={activeTab === \"bin\" ? undefined : handleFileRename}\n onFileDownload={handleFileDownload}\n onFileCopy={activeTab === \"bin\" ? undefined : handleFileCopy}\n onFileMove={activeTab === \"bin\" ? undefined : handleFileMove}\n onFileInfo={handleFileInfoClick}\n onFolderOpen={handleFolderOpen}\n onFolderShare={activeTab === \"bin\" ? undefined : handleFolderShare}\n onFolderDelete={\n activeTab === \"bin\"\n ? handleFolderPermanentDelete\n : handleFolderDelete\n }\n onFolderRestore={\n activeTab === \"bin\" ? handleFolderRestore : undefined\n }\n onFolderRename={activeTab === \"bin\" ? undefined : handleFolderRename}\n onFolderFavorite={\n activeTab === \"bin\" ? undefined : handleFolderFavorite\n }\n onFolderMove={activeTab === \"bin\" ? undefined : handleFolderMove}\n onFolderInfo={handleFolderInfoClick}\n />\n\n {/* Results Summary */}\n {!loading && (files.length > 0 || folders.length > 0) && (\n <div className=\"mt-4 px-2 text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.browser.results.showingItems\",\n \"Showing {{count}} items\",\n { count: files.length + folders.length },\n )}\n {!isSearching &&\n activeTab === \"all\" &&\n totalItemsInCurrentView !== null &&\n ` ${tWithFallback(\n t,\n \"files.browser.results.ofItems\",\n \"of {{count}} items\",\n { count: totalItemsInCurrentView },\n )}`}\n </div>\n )}\n </div>\n\n {/* New Folder Dialog */}\n {showNewFolderDialog && (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (!next && !createFolderMutation.isPending) {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n }\n }}\n >\n <ResponsiveDialogContent className=\"w-full max-w-xs\">\n <ResponsiveDialogHeader className=\"text-left\">\n <ResponsiveDialogTitle\n id=\"files-new-folder-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.browser.newFolderDialog.title\",\n \"New folder\",\n )}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <Input\n type=\"text\"\n value={newFolderName}\n onChange={(e) => setNewFolderName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleCreateFolder();\n }}\n aria-label={tWithFallback(\n t,\n \"files.browser.newFolderDialog.title\",\n \"New folder\",\n )}\n placeholder={tWithFallback(\n t,\n \"files.browser.newFolderDialog.placeholder\",\n \"Folder name\",\n )}\n />\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowNewFolderDialog(false);\n setNewFolderName(\"\");\n }}\n >\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleCreateFolder}\n disabled={\n !newFolderName.trim() || createFolderMutation.isPending\n }\n >\n {createFolderMutation.isPending && (\n <Loader2 className=\"size-4 animate-spin\" />\n )}\n {createFolderMutation.isPending\n ? tWithFallback(\n t,\n \"files.browser.newFolderDialog.actions.creating\",\n \"Creating...\",\n )\n : tWithFallback(t, \"files.common.actions.create\", \"Create\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n )}\n\n {/* Rename Dialog */}\n {showRenameDialog && renameTarget && (\n <ResponsiveDialog\n open\n onOpenChange={(next: boolean) => {\n if (\n !next &&\n !renameFileMutation.isPending &&\n !renameFolderMutation.isPending\n ) {\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n }\n }}\n >\n <ResponsiveDialogContent className=\"w-full max-w-xs\">\n <ResponsiveDialogHeader className=\"text-left\">\n <ResponsiveDialogTitle\n id=\"files-rename-title\"\n className=\"text-base font-semibold text-text-primary\"\n >\n {tWithFallback(\n t,\n \"files.browser.renameDialog.title\",\n \"Rename {{type}}\",\n { type: renameTarget.type },\n )}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <Input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleRenameSubmit();\n }}\n aria-label={tWithFallback(\n t,\n \"files.browser.renameDialog.title\",\n \"Rename\",\n )}\n placeholder={tWithFallback(\n t,\n \"files.browser.renameDialog.placeholder\",\n \"New name\",\n )}\n />\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n setShowRenameDialog(false);\n setRenameTarget(null);\n setNewName(\"\");\n }}\n >\n {tWithFallback(t, \"files.common.actions.cancel\", \"Cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleRenameSubmit}\n disabled={\n !newName.trim() ||\n newName.trim() === renameTarget.name ||\n renameFileMutation.isPending ||\n renameFolderMutation.isPending\n }\n >\n {(renameFileMutation.isPending ||\n renameFolderMutation.isPending) && (\n <Loader2 className=\"size-4 animate-spin\" />\n )}\n {renameFileMutation.isPending || renameFolderMutation.isPending\n ? tWithFallback(\n t,\n \"files.browser.renameDialog.actions.renaming\",\n \"Renaming...\",\n )\n : tWithFallback(t, \"files.common.actions.rename\", \"Rename\")}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n )}\n\n {/* Share Dialog */}\n {showShareDialog && shareTarget && (\n <ShareDialog\n item={shareTarget}\n itemType={\"mimeType\" in shareTarget ? \"file\" : \"folder\"}\n onClose={() => {\n setShowShareDialog(false);\n setShareTarget(null);\n }}\n onCreateShare={handleCreateShare}\n isLoading={createShareMutation.isPending}\n />\n )}\n\n {confirmDialog && (\n <ConfirmDialog\n title={confirmDialog.title}\n description={confirmDialog.description}\n confirmLabel={confirmDialog.confirmLabel}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.cancel\",\n \"Cancel\",\n )}\n variant={confirmDialog.variant}\n loading={confirmDialog.loading}\n onConfirm={runConfirmedAction}\n onCancel={() => {\n if (!confirmDialog.loading) {\n setConfirmDialog(null);\n }\n }}\n />\n )}\n\n {/* Folder Quota Exhausted Dialog */}\n {showFolderQuotaExhausted && (\n <ConfirmDialog\n title={tWithFallback(\n t,\n \"files.folder.quota.title\",\n \"Folder Limit Reached\",\n )}\n description={tWithFallback(\n t,\n \"files.folder.quota.description\",\n \"You've reached the folder limit for your plan. Upgrade your plan or purchase an add-on to create more folders.\",\n )}\n confirmLabel={tWithFallback(\n t,\n \"files.folder.quota.upgrade\",\n \"View Billing\",\n )}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.dismiss\",\n \"Dismiss\",\n )}\n onConfirm={() => {\n setShowFolderQuotaExhausted(false);\n navigate(\"/billing\");\n }}\n onCancel={() => setShowFolderQuotaExhausted(false)}\n />\n )}\n\n {/* Move Dialog */}\n {showMoveDialog && moveTarget && (\n <MoveDialog\n item={moveTarget.item}\n type={moveTarget.type}\n onClose={() => {\n setShowMoveDialog(false);\n setMoveTarget(null);\n }}\n onMove={handleMoveSubmit}\n isLoading={moveFileMutation.isPending || moveFolderMutation.isPending}\n />\n )}\n\n {/* Copy Dialog */}\n {showCopyDialog && copyTarget && (\n <CopyDialog\n item={copyTarget.item}\n type={copyTarget.type}\n onClose={() => {\n setShowCopyDialog(false);\n setCopyTarget(null);\n }}\n onCopy={handleCopySubmit}\n isLoading={copyFileMutation.isPending}\n />\n )}\n\n {/* File Preview Modal */}\n {previewFile && (\n <FilePreviewModal\n file={previewFile}\n onClose={() => setPreviewFile(null)}\n onDownload={() => {\n const url = previewFile.downloadUrl || previewFile.url;\n void nativeOpenUrl(url);\n }}\n onShare={\n activeTab === \"bin\"\n ? undefined\n : () => {\n setShareTarget(previewFile);\n setShowShareDialog(true);\n }\n }\n onStar={\n activeTab === \"bin\"\n ? undefined\n : () => handleFileFavorite(previewFile)\n }\n onDelete={() =>\n activeTab === \"bin\"\n ? handleFilePermanentDelete(previewFile)\n : handleFileDelete(previewFile)\n }\n />\n )}\n\n {/* File Info Panel */}\n {infoPanel && (\n <FileInfoPanel\n item={infoPanel.item}\n type={infoPanel.type}\n onClose={() => setInfoPanel(null)}\n />\n )}\n\n {/* Upload Progress Indicator */}\n {/* Upload Queue */}\n <UploadQueue\n items={uploadQueue}\n isOpen={isUploadPanelOpen}\n onClose={() => setIsUploadPanelOpen(false)}\n onPause={handlePauseUpload}\n onResume={handleResumeUpload}\n onRetry={handleRetryUpload}\n onCancel={handleCancelUpload}\n />\n\n {/* Toast Notifications */}\n <ToastContainer toasts={toast.toasts} onClose={toast.removeToast} />\n\n {/* Empty State */}\n {!loading && files.length === 0 && folders.length === 0 && (\n <div className=\"px-6 py-12\">\n {isSearching ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tWithFallback(\n t,\n \"files.browser.empty.search.title\",\n \"No results found\",\n )}\n description={tWithFallback(\n t,\n \"files.browser.empty.search.description\",\n \"Try adjusting your search query or filters\",\n )}\n action={\n <Button\n type=\"button\"\n onClick={() => {\n setSearchQuery(\"\");\n setSearchFilters(undefined);\n }}\n >\n {tWithFallback(\n t,\n \"files.browser.search.clear\",\n \"Clear search\",\n )}\n </Button>\n }\n />\n ) : (\n <EmptyState\n type={activeTab}\n onUpload={activeTab === \"all\" ? handleUploadClick : undefined}\n onNewFolder={\n activeTab === \"all\" ? handleNewFolderClick : undefined\n }\n />\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-files",
|
|
3
|
-
"version": "2026.625.
|
|
3
|
+
"version": "2026.625.3",
|
|
4
4
|
"description": "Burdenoff Files Microfrontend - Standalone file management module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"imports": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@apollo/client": "^4.0.13",
|
|
48
|
-
"@burdenoff/fe-libs": "2026.625.
|
|
48
|
+
"@burdenoff/fe-libs": "2026.625.3",
|
|
49
49
|
"@tanstack/react-query": "^5.90.17",
|
|
50
50
|
"graphql": "^16.12.0",
|
|
51
51
|
"lucide-react": "^0.468.0",
|