import { sanitizeFeatureBranchName } from "@t3tools/shared/git"; import { useRouter } from "expo-router"; import { useState } from "react"; import { Pressable, ScrollView, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useThemeColor } from "../../../lib/useThemeColor"; import { AppText as Text, AppTextInput as TextInput } from "../../../components/AppText"; import { useVcsStatus } from "../../../state/use-vcs-status"; import { useThreadSelection } from "../../../state/use-thread-selection"; import { useSelectedThreadGitActions } from "../../../state/use-selected-thread-git-actions"; import { useSelectedThreadGitState } from "../../../state/use-selected-thread-git-state"; import { useSelectedThreadWorktree } from "../../../state/use-selected-thread-worktree"; import { SheetActionButton } from "./gitSheetComponents"; export function GitBranchesSheet() { const router = useRouter(); const insets = useSafeAreaInsets(); const { selectedThread } = useThreadSelection(); const { selectedThreadCwd, selectedThreadWorktreePath } = useSelectedThreadWorktree(); const gitState = useSelectedThreadGitState(); const gitActions = useSelectedThreadGitActions(); const borderColor = useThemeColor("--color-border"); const inputBorderColor = useThemeColor("--color-input-border"); const inputBg = useThemeColor("--color-input"); const foregroundColor = useThemeColor("--color-foreground"); const subtleStrongColor = useThemeColor("--color-subtle-strong"); const gitStatus = useVcsStatus({ environmentId: selectedThread?.environmentId ?? null, cwd: selectedThreadCwd, }); const currentBranchLabel = gitStatus.data?.refName ?? selectedThread?.branch ?? "Detached HEAD"; const currentWorktreePath = selectedThreadWorktreePath; const availableBranches = gitState.selectedThreadBranches; const branchesLoading = gitState.selectedThreadBranchesLoading; const busy = gitState.gitOperationLabel !== null; const [newBranchName, setNewBranchName] = useState(""); const [worktreeBaseBranch, setWorktreeBaseBranch] = useState( currentBranchLabel === "Detached HEAD" ? "main" : currentBranchLabel, ); const [worktreeBranchName, setWorktreeBranchName] = useState(""); const disabledExistingBranchNames: Array = []; for (const branch of availableBranches) { if (branch.worktreePath !== null && branch.worktreePath !== currentWorktreePath) { disabledExistingBranchNames.push(branch.name); } } const disabledExistingBranches = new Set(disabledExistingBranchNames); return ( New branch { const branch = sanitizeFeatureBranchName(newBranchName.trim()); if (branch.length === 0) return; void gitActions.onCreateSelectedThreadBranch(branch).then(() => { setNewBranchName(""); router.dismiss(); }); }} /> New worktree { const baseBranch = worktreeBaseBranch.trim(); const newBranch = worktreeBranchName.trim(); if (baseBranch.length === 0 || newBranch.length === 0) return; void gitActions.onCreateSelectedThreadWorktree({ baseBranch, newBranch }).then(() => { setWorktreeBranchName(""); router.dismiss(); }); }} /> Existing branches {branchesLoading ? ( Loading branches... ) : null} {!branchesLoading && availableBranches.length === 0 ? ( No local branches found. ) : null} {availableBranches.map((branch) => { const disabled = disabledExistingBranches.has(branch.name); const subtitle = branch.worktreePath ? branch.worktreePath === currentWorktreePath ? "Checked out in this thread" : "Checked out in another worktree" : branch.isDefault ? "Default branch" : "Local branch"; return ( { void gitActions.onCheckoutSelectedThreadBranch(branch.name).then(() => { router.dismiss(); }); }} > {branch.name} {subtitle} ); })} ); }