From af73065f92cea5e4e4607bcb2b2e1276c741b0ff Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 00:57:56 +0000 Subject: [PATCH] Refactor project manager dialog hooks --- src/components/ProjectManager.tsx | 6 +- src/hooks/use-project-manager-dialogs.ts | 182 +++++++++++++++++++++++ src/hooks/use-project-manager.ts | 170 +-------------------- 3 files changed, 188 insertions(+), 170 deletions(-) create mode 100644 src/hooks/use-project-manager-dialogs.ts diff --git a/src/components/ProjectManager.tsx b/src/components/ProjectManager.tsx index d039571..30b1d13 100644 --- a/src/components/ProjectManager.tsx +++ b/src/components/ProjectManager.tsx @@ -1,4 +1,5 @@ import { useProjectManager } from '@/hooks/use-project-manager' +import { useProjectManagerDialogs } from '@/hooks/use-project-manager-dialogs' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from '@/components/ui/card' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' @@ -23,6 +24,9 @@ export function ProjectManager({ currentProject, onProjectLoad }: ProjectManager const { projects, isLoading, + loadProjectsList, + } = useProjectManager() + const { currentProjectId, projectName, projectDescription, @@ -49,7 +53,7 @@ export function ProjectManager({ currentProject, onProjectLoad }: ProjectManager handleExportProject, handleImportProject, handleNewProject, - } = useProjectManager({ currentProject, onProjectLoad }) + } = useProjectManagerDialogs({ currentProject, onProjectLoad, loadProjectsList }) const formatDate = (timestamp: number) => { return new Date(timestamp).toLocaleString() diff --git a/src/hooks/use-project-manager-dialogs.ts b/src/hooks/use-project-manager-dialogs.ts new file mode 100644 index 0000000..a405994 --- /dev/null +++ b/src/hooks/use-project-manager-dialogs.ts @@ -0,0 +1,182 @@ +import { useCallback, useState } from 'react' +import { toast } from 'sonner' +import { ProjectService, SavedProject } from '@/lib/project-service' +import { Project } from '@/types/project' + +interface UseProjectManagerDialogsOptions { + currentProject: Project + onProjectLoad: (project: Project) => void + loadProjectsList: () => Promise +} + +export function useProjectManagerDialogs({ + currentProject, + onProjectLoad, + loadProjectsList, +}: UseProjectManagerDialogsOptions) { + const [saveDialogOpen, setSaveDialogOpen] = useState(false) + const [loadDialogOpen, setLoadDialogOpen] = useState(false) + const [newProjectDialogOpen, setNewProjectDialogOpen] = useState(false) + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) + const [importDialogOpen, setImportDialogOpen] = useState(false) + const [projectToDelete, setProjectToDelete] = useState(null) + const [projectName, setProjectName] = useState('') + const [projectDescription, setProjectDescription] = useState('') + const [currentProjectId, setCurrentProjectId] = useState(null) + const [importJson, setImportJson] = useState('') + + const handleSaveProject = useCallback(async () => { + if (!projectName.trim()) { + toast.error('Please enter a project name') + return + } + + try { + const id = currentProjectId || ProjectService.generateProjectId() + + await ProjectService.saveProject( + id, + projectName, + currentProject, + projectDescription + ) + + setCurrentProjectId(id) + toast.success('Project saved successfully!') + setSaveDialogOpen(false) + await loadProjectsList() + } catch (error) { + console.error('Failed to save project:', error) + toast.error('Failed to save project') + } + }, [currentProject, currentProjectId, loadProjectsList, projectDescription, projectName]) + + const handleLoadProject = useCallback(async (project: SavedProject) => { + try { + onProjectLoad(project.data) + setCurrentProjectId(project.id) + setProjectName(project.name) + setProjectDescription(project.description || '') + setLoadDialogOpen(false) + toast.success(`Loaded project: ${project.name}`) + } catch (error) { + console.error('Failed to load project:', error) + toast.error('Failed to load project') + } + }, [onProjectLoad]) + + const handleDeleteProject = useCallback(async () => { + if (!projectToDelete) return + + try { + await ProjectService.deleteProject(projectToDelete) + toast.success('Project deleted successfully') + setDeleteDialogOpen(false) + setProjectToDelete(null) + + if (currentProjectId === projectToDelete) { + setCurrentProjectId(null) + setProjectName('') + setProjectDescription('') + } + + await loadProjectsList() + } catch (error) { + console.error('Failed to delete project:', error) + toast.error('Failed to delete project') + } + }, [currentProjectId, loadProjectsList, projectToDelete]) + + const handleDuplicateProject = useCallback(async (id: string, name: string) => { + try { + const duplicated = await ProjectService.duplicateProject(id, `${name} (Copy)`) + if (duplicated) { + toast.success('Project duplicated successfully') + await loadProjectsList() + } + } catch (error) { + console.error('Failed to duplicate project:', error) + toast.error('Failed to duplicate project') + } + }, [loadProjectsList]) + + const handleExportProject = useCallback(async (id: string, name: string) => { + try { + const json = await ProjectService.exportProjectAsJSON(id) + if (json) { + const blob = new Blob([json], { type: 'application/json' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = `${name.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.json` + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + URL.revokeObjectURL(url) + toast.success('Project exported successfully') + } + } catch (error) { + console.error('Failed to export project:', error) + toast.error('Failed to export project') + } + }, []) + + const handleImportProject = useCallback(async () => { + if (!importJson.trim()) { + toast.error('Please paste project JSON') + return + } + + try { + const imported = await ProjectService.importProjectFromJSON(importJson) + if (imported) { + toast.success('Project imported successfully') + setImportDialogOpen(false) + setImportJson('') + await loadProjectsList() + } else { + toast.error('Invalid project JSON') + } + } catch (error) { + console.error('Failed to import project:', error) + toast.error('Failed to import project') + } + }, [importJson, loadProjectsList]) + + const handleNewProject = useCallback(() => { + setCurrentProjectId(null) + setProjectName('') + setProjectDescription('') + setNewProjectDialogOpen(false) + toast.success('New project started') + }, []) + + return { + currentProjectId, + projectName, + projectDescription, + importJson, + saveDialogOpen, + loadDialogOpen, + newProjectDialogOpen, + deleteDialogOpen, + importDialogOpen, + projectToDelete, + setSaveDialogOpen, + setLoadDialogOpen, + setNewProjectDialogOpen, + setDeleteDialogOpen, + setImportDialogOpen, + setProjectToDelete, + setProjectName, + setProjectDescription, + setImportJson, + handleSaveProject, + handleLoadProject, + handleDeleteProject, + handleDuplicateProject, + handleExportProject, + handleImportProject, + handleNewProject, + } +} diff --git a/src/hooks/use-project-manager.ts b/src/hooks/use-project-manager.ts index 6de0829..8131891 100644 --- a/src/hooks/use-project-manager.ts +++ b/src/hooks/use-project-manager.ts @@ -1,25 +1,9 @@ import { useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' import { ProjectService, SavedProject } from '@/lib/project-service' -import { Project } from '@/types/project' -interface UseProjectManagerOptions { - currentProject: Project - onProjectLoad: (project: Project) => void -} - -export function useProjectManager({ currentProject, onProjectLoad }: UseProjectManagerOptions) { +export function useProjectManager() { const [projects, setProjects] = useState([]) - const [saveDialogOpen, setSaveDialogOpen] = useState(false) - const [loadDialogOpen, setLoadDialogOpen] = useState(false) - const [newProjectDialogOpen, setNewProjectDialogOpen] = useState(false) - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) - const [importDialogOpen, setImportDialogOpen] = useState(false) - const [projectToDelete, setProjectToDelete] = useState(null) - const [projectName, setProjectName] = useState('') - const [projectDescription, setProjectDescription] = useState('') - const [currentProjectId, setCurrentProjectId] = useState(null) - const [importJson, setImportJson] = useState('') const [isLoading, setIsLoading] = useState(false) const loadProjectsList = useCallback(async () => { @@ -39,161 +23,9 @@ export function useProjectManager({ currentProject, onProjectLoad }: UseProjectM void loadProjectsList() }, [loadProjectsList]) - const handleSaveProject = useCallback(async () => { - if (!projectName.trim()) { - toast.error('Please enter a project name') - return - } - - try { - const id = currentProjectId || ProjectService.generateProjectId() - - await ProjectService.saveProject( - id, - projectName, - currentProject, - projectDescription - ) - - setCurrentProjectId(id) - toast.success('Project saved successfully!') - setSaveDialogOpen(false) - await loadProjectsList() - } catch (error) { - console.error('Failed to save project:', error) - toast.error('Failed to save project') - } - }, [currentProject, currentProjectId, loadProjectsList, projectDescription, projectName]) - - const handleLoadProject = useCallback(async (project: SavedProject) => { - try { - onProjectLoad(project.data) - setCurrentProjectId(project.id) - setProjectName(project.name) - setProjectDescription(project.description || '') - setLoadDialogOpen(false) - toast.success(`Loaded project: ${project.name}`) - } catch (error) { - console.error('Failed to load project:', error) - toast.error('Failed to load project') - } - }, [onProjectLoad]) - - const handleDeleteProject = useCallback(async () => { - if (!projectToDelete) return - - try { - await ProjectService.deleteProject(projectToDelete) - toast.success('Project deleted successfully') - setDeleteDialogOpen(false) - setProjectToDelete(null) - - if (currentProjectId === projectToDelete) { - setCurrentProjectId(null) - setProjectName('') - setProjectDescription('') - } - - await loadProjectsList() - } catch (error) { - console.error('Failed to delete project:', error) - toast.error('Failed to delete project') - } - }, [currentProjectId, loadProjectsList, projectToDelete]) - - const handleDuplicateProject = useCallback(async (id: string, name: string) => { - try { - const duplicated = await ProjectService.duplicateProject(id, `${name} (Copy)`) - if (duplicated) { - toast.success('Project duplicated successfully') - await loadProjectsList() - } - } catch (error) { - console.error('Failed to duplicate project:', error) - toast.error('Failed to duplicate project') - } - }, [loadProjectsList]) - - const handleExportProject = useCallback(async (id: string, name: string) => { - try { - const json = await ProjectService.exportProjectAsJSON(id) - if (json) { - const blob = new Blob([json], { type: 'application/json' }) - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = `${name.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.json` - document.body.appendChild(a) - a.click() - document.body.removeChild(a) - URL.revokeObjectURL(url) - toast.success('Project exported successfully') - } - } catch (error) { - console.error('Failed to export project:', error) - toast.error('Failed to export project') - } - }, []) - - const handleImportProject = useCallback(async () => { - if (!importJson.trim()) { - toast.error('Please paste project JSON') - return - } - - try { - const imported = await ProjectService.importProjectFromJSON(importJson) - if (imported) { - toast.success('Project imported successfully') - setImportDialogOpen(false) - setImportJson('') - await loadProjectsList() - } else { - toast.error('Invalid project JSON') - } - } catch (error) { - console.error('Failed to import project:', error) - toast.error('Failed to import project') - } - }, [importJson, loadProjectsList]) - - const handleNewProject = useCallback(() => { - setCurrentProjectId(null) - setProjectName('') - setProjectDescription('') - setNewProjectDialogOpen(false) - toast.success('New project started') - }, []) - return { projects, isLoading, - currentProjectId, - projectName, - projectDescription, - importJson, - saveDialogOpen, - loadDialogOpen, - newProjectDialogOpen, - deleteDialogOpen, - importDialogOpen, - projectToDelete, - setSaveDialogOpen, - setLoadDialogOpen, - setNewProjectDialogOpen, - setDeleteDialogOpen, - setImportDialogOpen, - setProjectToDelete, - setProjectName, - setProjectDescription, - setImportJson, loadProjectsList, - handleSaveProject, - handleLoadProject, - handleDeleteProject, - handleDuplicateProject, - handleExportProject, - handleImportProject, - handleNewProject, } }