# refactor\(web\): ChatView's module-level helpers live in their own files · PR \#22665 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/22665)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: merged

Source repository: pingdotgg/t3code

Source branch: refactor/chatview-helpers

Target branch: main

Head commit: f48841f9ef73601c5af03586ca7c334684b92fb5

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/22665)

[Commits](https://git.cafe/pingdotgg/t3code/pull/22665/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/22665/diffs?format=markdown)

## Description

---

ChatView.tsx is ~9,100 lines, and about 500 of them are module-level helpers that have nothing to do with rendering. This is the first layer of a stack that splits ChatView up.

What moved:
- `ThreadVisitWatermark` → `chat/ThreadVisitWatermark.tsx`
- `useDraftHeroLayoutTransition` → `chat/useDraftHeroLayoutTransition.ts`
- `useLocalDispatchState` → `chat/useLocalDispatchState.ts`
- The multiple-model send state and `startFanoutThread` / `rewindToMessage` → `chat/chatViewSend.ts`
- Pure helpers (`formatOutgoingPrompt`, `isCompactCommandMessage`, `makeThreadErrorSetter`, `makeModelDisabledReason`, `releaseChatTimelineAnchor`, `chatActionErrorMessage`) → `ChatView.logic.ts`

The code is unchanged. Render boundaries don't change in this layer, so it has no render numbers of its own.

| | main | this layer |
|---|---|---|
| ChatView.tsx lines | 9,093 | 8,585 |

Tests: `vp test run src/reactCompilerCoverage.test.ts` for ChatView and every new file (0 bailouts), `vp test run src/components/ChatView.logic.test.ts`, `tsc-rs --noEmit` for apps/web, and oxlint on the changed files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

