import { useState, useCallback, useEffect } from "react"; import { listContracts, getContract, createContract, updateContract, deleteContract, changeContractPhase, getContractEvents, addRemoteRepository, addLocalRepository, createManagedRepository, deleteContractRepository, setRepositoryPrimary, addTaskToContract, removeTaskFromContract, VersionConflictError, type ContractSummary, type ContractWithRelations, type ContractEvent, type ContractRepository, type ContractPhase, type CreateContractRequest, type UpdateContractRequest, type AddRemoteRepositoryRequest, type AddLocalRepositoryRequest, type CreateManagedRepositoryRequest, } from "../lib/api"; export interface ConflictState { hasConflict: boolean; expectedVersion: number; actualVersion: number; } export function useContracts() { const [contracts, setContracts] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [conflict, setConflict] = useState(null); const fetchContracts = useCallback(async () => { setLoading(true); setError(null); try { const response = await listContracts(); setContracts(response.contracts); } catch (e) { setError(e instanceof Error ? e.message : "Failed to fetch contracts"); } finally { setLoading(false); } }, []); const fetchContract = useCallback( async (id: string): Promise => { setError(null); try { return await getContract(id); } catch (e) { setError(e instanceof Error ? e.message : "Failed to fetch contract"); return null; } }, [] ); const saveContract = useCallback( async (data: CreateContractRequest): Promise => { setError(null); try { const contract = await createContract(data); await fetchContracts(); // Refresh list return contract; } catch (e) { setError(e instanceof Error ? e.message : "Failed to save contract"); return null; } }, [fetchContracts] ); const editContract = useCallback( async ( id: string, data: UpdateContractRequest ): Promise => { setError(null); setConflict(null); try { const contract = await updateContract(id, data); await fetchContracts(); // Refresh list return contract; } catch (e) { if (e instanceof VersionConflictError) { setConflict({ hasConflict: true, expectedVersion: e.expectedVersion, actualVersion: e.actualVersion, }); return null; } setError(e instanceof Error ? e.message : "Failed to update contract"); return null; } }, [fetchContracts] ); const clearConflict = useCallback(() => { setConflict(null); }, []); const removeContract = useCallback( async (id: string): Promise => { setError(null); try { await deleteContract(id); await fetchContracts(); // Refresh list return true; } catch (e) { setError(e instanceof Error ? e.message : "Failed to delete contract"); return false; } }, [fetchContracts] ); const changePhase = useCallback( async ( id: string, phase: ContractPhase ): Promise => { setError(null); try { const contract = await changeContractPhase(id, phase); await fetchContracts(); // Refresh list return contract; } catch (e) { setError(e instanceof Error ? e.message : "Failed to change phase"); return null; } }, [fetchContracts] ); const fetchEvents = useCallback( async (id: string): Promise => { setError(null); try { return await getContractEvents(id); } catch (e) { setError(e instanceof Error ? e.message : "Failed to fetch events"); return []; } }, [] ); // Repository management const addRemoteRepo = useCallback( async ( contractId: string, data: AddRemoteRepositoryRequest ): Promise => { setError(null); try { return await addRemoteRepository(contractId, data); } catch (e) { setError( e instanceof Error ? e.message : "Failed to add remote repository" ); return null; } }, [] ); const addLocalRepo = useCallback( async ( contractId: string, data: AddLocalRepositoryRequest ): Promise => { setError(null); try { return await addLocalRepository(contractId, data); } catch (e) { setError( e instanceof Error ? e.message : "Failed to add local repository" ); return null; } }, [] ); const createManagedRepo = useCallback( async ( contractId: string, data: CreateManagedRepositoryRequest ): Promise => { setError(null); try { return await createManagedRepository(contractId, data); } catch (e) { setError( e instanceof Error ? e.message : "Failed to create managed repository" ); return null; } }, [] ); const removeRepo = useCallback( async (contractId: string, repoId: string): Promise => { setError(null); try { await deleteContractRepository(contractId, repoId); return true; } catch (e) { setError( e instanceof Error ? e.message : "Failed to delete repository" ); return false; } }, [] ); const setRepoPrimary = useCallback( async (contractId: string, repoId: string): Promise => { setError(null); try { await setRepositoryPrimary(contractId, repoId); return true; } catch (e) { setError( e instanceof Error ? e.message : "Failed to set repository as primary" ); return false; } }, [] ); // Task association const addTask = useCallback( async (contractId: string, taskId: string): Promise => { setError(null); try { await addTaskToContract(contractId, taskId); return true; } catch (e) { setError( e instanceof Error ? e.message : "Failed to add task to contract" ); return false; } }, [] ); const removeTask = useCallback( async (contractId: string, taskId: string): Promise => { setError(null); try { await removeTaskFromContract(contractId, taskId); return true; } catch (e) { setError( e instanceof Error ? e.message : "Failed to remove task from contract" ); return false; } }, [] ); // Initial fetch useEffect(() => { fetchContracts(); }, [fetchContracts]); return { contracts, loading, error, conflict, clearConflict, fetchContracts, fetchContract, saveContract, editContract, removeContract, changePhase, fetchEvents, // Repository management addRemoteRepo, addLocalRepo, createManagedRepo, removeRepo, setRepoPrimary, // Task association addTask, removeTask, }; }