import React, { useState, useCallback, useEffect } from "react"; import { useTranslation } from 'react-i18next'; import { useSearchParams } from "react-router-dom"; import { useToolParams } from "../hooks/useToolParams"; import { useFileWithUrl } from "../hooks/useFileWithUrl"; import { fileStorage } from "../services/fileStorage"; import AddToPhotosIcon from "@mui/icons-material/AddToPhotos"; import ContentCutIcon from "@mui/icons-material/ContentCut"; import ZoomInMapIcon from "@mui/icons-material/ZoomInMap"; import { Group, Paper, Box, Button, useMantineTheme, Container } from "@mantine/core"; import { useRainbowThemeContext } from "../components/shared/RainbowThemeProvider"; import rainbowStyles from '../styles/rainbow.module.css'; import ToolPicker from "../components/tools/ToolPicker"; import TopControls from "../components/shared/TopControls"; import FileManager from "../components/fileManagement/FileManager"; import FileEditor from "../components/editor/FileEditor"; import PageEditor from "../components/editor/PageEditor"; import PageEditorControls from "../components/editor/PageEditorControls"; import Viewer from "../components/viewer/Viewer"; import FileUploadSelector from "../components/shared/FileUploadSelector"; import SplitPdfPanel from "../tools/Split"; import CompressPdfPanel from "../tools/Compress"; import MergePdfPanel from "../tools/Merge"; import ToolRenderer from "../components/tools/ToolRenderer"; import QuickAccessBar from "../components/shared/QuickAccessBar"; type ToolRegistryEntry = { icon: React.ReactNode; name: string; component: React.ComponentType; view: string; }; type ToolRegistry = { [key: string]: ToolRegistryEntry; }; // Base tool registry without translations const baseToolRegistry = { split: { icon: , component: SplitPdfPanel, view: "viewer" }, compress: { icon: , component: CompressPdfPanel, view: "viewer" }, merge: { icon: , component: MergePdfPanel, view: "fileManager" }, }; export default function HomePage() { const { t } = useTranslation(); const [searchParams] = useSearchParams(); const theme = useMantineTheme(); const { isRainbowMode } = useRainbowThemeContext(); // Core app state const [selectedToolKey, setSelectedToolKey] = useState(searchParams.get("t") || "split"); const [currentView, setCurrentView] = useState(searchParams.get("v") || "viewer"); // File state separation const [storedFiles, setStoredFiles] = useState([]); // IndexedDB files (FileManager) const [activeFiles, setActiveFiles] = useState([]); // Active working set (persisted) const [preSelectedFiles, setPreSelectedFiles] = useState([]); const [downloadUrl, setDownloadUrl] = useState(null); const [sidebarsVisible, setSidebarsVisible] = useState(true); const [leftPanelView, setLeftPanelView] = useState<'toolPicker' | 'toolContent'>('toolPicker'); const [readerMode, setReaderMode] = useState(false); // Page editor functions const [pageEditorFunctions, setPageEditorFunctions] = useState(null); // URL parameter management const { toolParams, updateParams } = useToolParams(selectedToolKey, currentView); // Persist active files across reloads useEffect(() => { // Save active files to localStorage (just metadata) const activeFileData = activeFiles.map(file => ({ name: file.name, size: file.size, type: file.type, lastModified: file.lastModified })); localStorage.setItem('activeFiles', JSON.stringify(activeFileData)); }, [activeFiles]); // Load stored files from IndexedDB on mount useEffect(() => { const loadStoredFiles = async () => { try { const files = await fileStorage.getAllFiles(); setStoredFiles(files); } catch (error) { console.warn('Failed to load stored files:', error); } }; loadStoredFiles(); }, []); // Restore active files on load useEffect(() => { const restoreActiveFiles = async () => { try { const savedFileData = JSON.parse(localStorage.getItem('activeFiles') || '[]'); if (savedFileData.length > 0) { // TODO: Reconstruct files from IndexedDB when fileStorage is available console.log('Would restore active files:', savedFileData); } } catch (error) { console.warn('Failed to restore active files:', error); } }; restoreActiveFiles(); }, []); const toolRegistry: ToolRegistry = { split: { ...baseToolRegistry.split, name: t("home.split.title", "Split PDF") }, compress: { ...baseToolRegistry.compress, name: t("home.compressPdfs.title", "Compress PDF") }, merge: { ...baseToolRegistry.merge, name: t("home.merge.title", "Merge PDFs") }, }; // Handle tool selection const handleToolSelect = useCallback( (id: string) => { setSelectedToolKey(id); if (toolRegistry[id]?.view) setCurrentView(toolRegistry[id].view); setLeftPanelView('toolContent'); // Switch to tool content view when a tool is selected setReaderMode(false); // Exit reader mode when selecting a tool }, [toolRegistry] ); // Handle quick access actions const handleQuickAccessTools = useCallback(() => { setLeftPanelView('toolPicker'); setReaderMode(false); }, []); const handleReaderToggle = useCallback(() => { setReaderMode(!readerMode); }, [readerMode]); // Update URL when view changes const handleViewChange = useCallback((view: string) => { setCurrentView(view); const params = new URLSearchParams(window.location.search); params.set('view', view); const newUrl = `${window.location.pathname}?${params.toString()}`; window.history.replaceState({}, '', newUrl); }, []); // Active file management const addToActiveFiles = useCallback((file: File) => { setActiveFiles(prev => { // Avoid duplicates based on name and size const exists = prev.some(f => f.name === file.name && f.size === file.size); if (exists) return prev; return [file, ...prev]; }); }, []); const removeFromActiveFiles = useCallback((file: File) => { setActiveFiles(prev => prev.filter(f => !(f.name === file.name && f.size === file.size))); }, []); const setCurrentActiveFile = useCallback((file: File) => { setActiveFiles(prev => { const filtered = prev.filter(f => !(f.name === file.name && f.size === file.size)); return [file, ...filtered]; }); }, []); // Handle file selection from upload (adds to active files) const handleFileSelect = useCallback((file: File) => { addToActiveFiles(file); }, [addToActiveFiles]); // Handle opening file editor with selected files const handleOpenFileEditor = useCallback((selectedFiles) => { setPreSelectedFiles(selectedFiles || []); handleViewChange("fileEditor"); }, [handleViewChange]); const selectedTool = toolRegistry[selectedToolKey]; // Convert current active file to format expected by Viewer/PageEditor const currentFileWithUrl = useFileWithUrl(activeFiles[0] || null); return ( {/* Quick Access Bar */} {/* Left: Tool Picker OR Selected Tool Panel */}
{leftPanelView === 'toolPicker' ? ( // Tool Picker View
) : ( // Selected Tool Content View
{/* Back button */}
{/* Tool title */}

{selectedTool?.name}

{/* Tool content */}
)}
{/* Main View */} {/* Top Controls */} {/* Main content area */} {currentView === "fileManager" ? ( ) : (currentView != "fileManager") && !activeFiles[0] ? ( { addToActiveFiles(file); }} allowMultiple={false} accept={["application/pdf"]} loading={false} /> ) : currentView === "fileEditor" ? ( setPreSelectedFiles([])} onOpenPageEditor={(file) => { setCurrentActiveFile(file); handleViewChange("pageEditor"); }} onMergeFiles={(filesToMerge) => { // Add merged files to active set filesToMerge.forEach(addToActiveFiles); handleViewChange("viewer"); }} /> ) : currentView === "viewer" ? ( { if (fileObj) { setCurrentActiveFile(fileObj.file); } else { setActiveFiles([]); } }} sidebarsVisible={sidebarsVisible} setSidebarsVisible={setSidebarsVisible} /> ) : currentView === "pageEditor" ? ( <> { if (fileObj) { setCurrentActiveFile(fileObj.file); } else { setActiveFiles([]); } }} downloadUrl={downloadUrl} setDownloadUrl={setDownloadUrl} onFunctionsReady={setPageEditorFunctions} sharedFiles={activeFiles} /> {activeFiles[0] && pageEditorFunctions && ( pageEditorFunctions.showExportPreview(true)} onExportAll={() => pageEditorFunctions.showExportPreview(false)} exportLoading={pageEditorFunctions.exportLoading} selectionMode={pageEditorFunctions.selectionMode} selectedPages={pageEditorFunctions.selectedPages} /> )} ) : ( )}
); }