import { useState } from "react"; import { createProject, deleteProject, listProjects, updateProject, type ProjectCreateInput, type ProjectUpdateInput, } from "../api/projects"; import { deleteWorkspace, syncWorkspace } from "../api/workspaces"; import { useAsyncData } from "./use-async-data"; import type { ProjectWithRepos, WorkspaceSummary } from "../types"; type DialogMode = "none" | "create" | "edit"; export const useProjects = () => { const { data: projects, status, reload, } = useAsyncData(listProjects, []); const [dialogMode, setDialogMode] = useState("none"); const [editingProject, setEditingProject] = useState( null, ); const [formName, setFormName] = useState(""); const [formDescription, setFormDescription] = useState(""); const [formError, setFormError] = useState(null); const [deleteConfirmId, setDeleteConfirmId] = useState(null); const [expandedProject, setExpandedProject] = useState(null); const [creatingWorkspace, setCreatingWorkspace] = useState<{ projectId: string; repoId: string; } | null>(null); const [workspaceLoading, setWorkspaceLoading] = useState(null); const safeProjects = projects ?? []; const openCreate = () => { setFormName(""); setFormDescription(""); setFormError(null); setEditingProject(null); setDialogMode("create"); }; const openEdit = (project: ProjectWithRepos) => { setFormName(project.name); setFormDescription(project.description ?? ""); setFormError(null); setEditingProject(project); setDialogMode("edit"); }; const closeDialog = () => { setDialogMode("none"); setEditingProject(null); setFormError(null); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setFormError(null); if (!formName.trim()) { setFormError("Project name is required"); return; } try { if (dialogMode === "create") { const input: ProjectCreateInput = { name: formName.trim(), description: formDescription.trim() || null, }; await createProject(input); } else if (dialogMode === "edit" && editingProject) { const input: ProjectUpdateInput = { name: formName.trim(), description: formDescription.trim() || null, }; await updateProject(editingProject.id, input); } closeDialog(); reload(); } catch { setFormError("Failed to save project"); } }; const handleDelete = async (projectId: string) => { try { await deleteProject(projectId); setDeleteConfirmId(null); reload(); } catch { setDeleteConfirmId(null); } }; const handleSyncWorkspace = async ( projectId: string, repoId: string, workspace: WorkspaceSummary, ) => { setWorkspaceLoading(workspace.id); try { await syncWorkspace(projectId, repoId, workspace.id); reload(); } catch (err) { alert(err instanceof Error ? err.message : "Failed to sync workspace"); } finally { setWorkspaceLoading(null); } }; const handleDeleteWorkspace = async (workspace: WorkspaceSummary) => { if (!confirm(`Delete workspace "${workspace.name}"?`)) return; setWorkspaceLoading(workspace.id); try { await deleteWorkspace(workspace.id); reload(); } catch (err) { alert(err instanceof Error ? err.message : "Failed to delete workspace"); } finally { setWorkspaceLoading(null); } }; return { projects: safeProjects, status, reload, dialogMode, formName, setFormName, formDescription, setFormDescription, formError, deleteConfirmId, setDeleteConfirmId, expandedProject, setExpandedProject, creatingWorkspace, setCreatingWorkspace, workspaceLoading, openCreate, openEdit, closeDialog, handleSubmit, handleDelete, handleSyncWorkspace, handleDeleteWorkspace, }; };