import { useCallback, useEffect, useMemo, useState } from 'react'; import { api } from '@renderer/api'; import { Button } from '@renderer/components/ui/button'; import { AlertTriangle, CheckCircle2, GitBranch, Loader2 } from 'lucide-react'; import type { TeamWorktreeGitStatus } from '@shared/types'; interface WorktreeGitReadinessState { status: TeamWorktreeGitStatus | null; loading: boolean; actionLoading: 'init' | 'commit' | null; error: string | null; refresh: () => Promise; initializeRepository: () => Promise; createInitialCommit: () => Promise; } export function useWorktreeGitReadiness( projectPath: string | null, enabled: boolean ): WorktreeGitReadinessState { const [status, setStatus] = useState(null); const [loading, setLoading] = useState(false); const [actionLoading, setActionLoading] = useState<'init' | 'commit' | null>(null); const [error, setError] = useState(null); const refresh = useCallback(async () => { if (!enabled || !projectPath?.trim()) { setStatus(null); setError(null); setLoading(false); return; } setLoading(true); setError(null); try { setStatus(await api.teams.getWorktreeGitStatus(projectPath)); } catch (err) { setStatus(null); setError(err instanceof Error ? err.message : 'Failed to inspect Git repository'); } finally { setLoading(false); } }, [enabled, projectPath]); useEffect(() => { let cancelled = false; if (!enabled || !projectPath?.trim()) { setStatus(null); setError(null); setLoading(false); return; } setLoading(true); setError(null); void api.teams .getWorktreeGitStatus(projectPath) .then((nextStatus) => { if (!cancelled) setStatus(nextStatus); }) .catch((err) => { if (!cancelled) { setStatus(null); setError(err instanceof Error ? err.message : 'Failed to inspect Git repository'); } }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [enabled, projectPath]); const initializeRepository = useCallback(async () => { if (!projectPath?.trim()) return; setActionLoading('init'); setError(null); try { setStatus(await api.teams.initializeGitRepository(projectPath)); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to initialize Git repository'); } finally { setActionLoading(null); } }, [projectPath]); const createInitialCommit = useCallback(async () => { if (!projectPath?.trim()) return; setActionLoading('commit'); setError(null); try { setStatus(await api.teams.createInitialGitCommit(projectPath)); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create initial Git commit'); } finally { setActionLoading(null); } }, [projectPath]); return useMemo( () => ({ status, loading, actionLoading, error, refresh, initializeRepository, createInitialCommit, }), [actionLoading, createInitialCommit, error, initializeRepository, loading, refresh, status] ); } export function getWorktreeGitBlockingMessage( state: Pick, hasSelectedWorktreeIsolation: boolean ): string | null { if (!hasSelectedWorktreeIsolation) { return null; } if (state.loading) { return 'Checking Git repository status before enabling worktree isolation.'; } if (state.error) { return state.error; } if (!state.status) { return 'Worktree isolation requires a Git repository with an initial commit.'; } return state.status.canUseWorktrees ? null : (state.status.message ?? null); } export function getWorktreeGitControlDisabledReason( state: Pick ): string | null { if (state.loading) { return 'Checking Git repository status...'; } if (state.error) { return state.error; } if (!state.status) { return null; } return state.status.canUseWorktrees ? null : (state.status.message ?? null); } export const WorktreeGitReadinessBanner = ({ state, showReady = false, }: { state: WorktreeGitReadinessState; showReady?: boolean; }): React.JSX.Element | null => { const { status, loading, actionLoading, error, initializeRepository, createInitialCommit } = state; if (loading) { return (

Checking Git repository status for teammate worktrees...

); } if (error) { return (

{error}

); } if (!status) { return null; } if (status.canUseWorktrees) { if (!showReady) return null; return (

Git worktrees are ready {status.branch ? ` on branch ${status.branch}` : ''}.

); } return (

Worktree isolation needs Git setup

{status.message ?? 'Worktree isolation requires a Git repository with an initial commit.'}

{status.reason === 'missing_head' ? (

The initial commit action stages and commits all current files with message{' '} chore: initial commit.

) : null}
{status.reason === 'not_git_repo' ? ( ) : null} {status.reason === 'missing_head' ? ( ) : null}
); };