import { ActivityIndicator, Pressable, ScrollView, Text, View } from 'react-native' import { RotateCw } from 'lucide-react-native' import { colors } from '../theme/mobile-theme' import type { PrSidebarState } from '../session/mobile-pr-sidebar-state' import type { ConnectionState } from '../transport/types' import type { RpcClient } from '../transport/rpc-client' import { useMobilePrActions, type MobilePrActions } from '../session/use-mobile-pr-actions' import { useMobilePrCommentActions, type MobilePrCommentActions } from '../session/use-mobile-pr-comment-actions' import { useMobilePrTitleAction, type MobilePrTitleAction } from '../session/use-mobile-pr-title-action' import { useMobilePrAiTriage, type MobilePrAiTriage } from '../session/use-mobile-pr-ai-triage' import { buildFixChecksPrompt, buildResolveConflictsPrompt } from '../session/pr-ai-triage-prompt' import { prSidebarRenderBranch } from './mobile-pr-sidebar-presentation' import { mobilePrSidebarStyles as styles } from './pr-sidebar/mobile-pr-sidebar-styles' import type { MobileGitStatusResult } from '../source-control/mobile-git-status' import { PRSidebarHeader } from './pr-sidebar/PRSidebarHeader' import { PRConflictingFilesSection } from './pr-sidebar/PRConflictingFilesSection' import { PRActionsSection } from './pr-sidebar/PRActionsSection' import { PRReviewersSection } from './pr-sidebar/PRReviewersSection' import { PRChecksSection } from './pr-sidebar/PRChecksSection' import { PRCommentsSection } from './pr-sidebar/PRCommentsSection' import { PrSidebarCreateEmptyState } from './pr-sidebar/PrSidebarCreateEmptyState' type Props = { state: PrSidebarState onRetry: () => void // Re-fetches authoritative PR data after a successful mutation (U3/U6) or create. refetch: () => void // Threaded to sections for github.* fetches + mutations. client: RpcClient | null connState: ConnectionState worktreeId: string gitBranch: string | null gitStatus: MobileGitStatusResult | null headSha: string | null bottomInset?: number } // Mutation hooks run unconditionally here and gate internally until a PR is ready. export function MobilePRSidebar({ state, onRetry, refetch, client, connState, worktreeId, gitBranch, gitStatus, headSha, bottomInset = 0 }: Props) { const branch = prSidebarRenderBranch(state) // prNumber is 0 until ready; the hook gates on `ready` so it never fires early. const prNumber = state.kind === 'ready' ? state.data.pr.number : 0 const prRepo = state.kind === 'ready' ? state.data.pr.prRepo ? { owner: state.data.pr.prRepo.owner, repo: state.data.pr.prRepo.repo } : null : null const actions = useMobilePrActions({ client, connState, worktreeId, prNumber, headSha, prRepo, refetch }) const commentActions = useMobilePrCommentActions({ client, connState, worktreeId, prNumber, prRepo, refetch }) const titleAction = useMobilePrTitleAction({ client, connState, worktreeId, prNumber, prRepo, refetch }) const triage = useMobilePrAiTriage({ client, connState, worktreeId }) return ( ) } function PrSidebarContent({ branch, state, onRetry, refetch, client, connState, worktreeId, gitBranch, gitStatus, actions, commentActions, titleAction, triage }: { branch: ReturnType state: PrSidebarState onRetry: () => void refetch: () => void client: RpcClient | null connState: ConnectionState worktreeId: string gitBranch: string | null gitStatus: MobileGitStatusResult | null actions: MobilePrActions commentActions: MobilePrCommentActions titleAction: MobilePrTitleAction triage: MobilePrAiTriage }) { if (branch === 'loading') { return ( Loading pull request… ) } if (branch === 'error') { const message = state.kind === 'error' ? state.message : 'Something went wrong.' return ( {message} Retry ) } if (branch === 'blocked' || actions.blocked) { // Permanent failure (R9): explanatory, no retry-encouragement styling. A // mutation-time block (actions.blocked) routes here even from a ready state. const message = actions.blocked ?? (state.kind === 'blocked' ? state.message : 'Not permitted — your GitHub account is not connected.') return ( {message} ) } if (branch === 'none') { // GitHub repo, but the current branch has no open PR — offer to create one // (desktop parity) rather than showing a dead-end message. return ( ) } if (branch === 'ready' && state.kind === 'ready') { return ( ) } return null } function PrSidebarSections({ data, client, worktreeId, actions, commentActions, titleAction, triage, refetch }: { data: Extract['data'] client: RpcClient | null worktreeId: string actions: MobilePrActions commentActions: MobilePrCommentActions titleAction: MobilePrTitleAction triage: MobilePrAiTriage refetch: () => void }) { const pr = data.pr // Bind the triage launchers to this PR's data; the prompt builders are pure so // building lazily inside launch() keeps a stale capture from leaking in. const checksTriage = { fixChecks: () => void triage.launch('fix-checks', () => buildFixChecksPrompt({ prNumber: pr.number, prTitle: pr.title, prUrl: pr.url, checks: data.checks }) ), isBusy: triage.isBusy('fix-checks'), error: triage.error } const conflictsTriage = { resolveConflicts: () => void triage.launch('resolve-conflicts', () => buildResolveConflictsPrompt({ prNumber: pr.number, baseRef: pr.conflictSummary?.baseRef ?? pr.baseRefName ?? null, files: pr.conflictSummary?.files ?? [] }) ), isBusy: triage.isBusy('resolve-conflicts'), error: triage.error } return ( <> {/* Conflicting-files section mirrors desktop order: directly below the header, before actions/checks. Renders only when the PR has merge conflicts. */} ) }