Skip to content

refactor(components): extract useDraftPersistence hook#58

Merged
saagpatel merged 1 commit into
masterfrom
codex/refactor/wave5-7-draft-persistence
Apr 21, 2026
Merged

refactor(components): extract useDraftPersistence hook#58
saagpatel merged 1 commit into
masterfrom
codex/refactor/wave5-7-draft-persistence

Conversation

@saagpatel
Copy link
Copy Markdown
Owner

What

Pulls the three draft-persistence callbacks out of `DraftTab.tsx` into a dedicated `useDraftPersistence` hook:

  • `handleSaveDraft` — the big one. Builds the payload, dispatches to `saveDraft` (new) or `updateDraft` (existing), handles the runbook-scope rekey from `workspace:*` to `draft:`, logs the quality snapshot, and surfaces the success/warning toast.
  • `handleConfirmOpenDraft` — save-and-open vs replace flow for pending draft dialogs.
  • `handleConfirmOpenSimilarCase` — save-and-open vs replace vs compare flow for pending similar-case dialogs.

Shell reduction: 1893 → 1738 LOC (-155 on this PR).

Why

`handleSaveDraft` was the last remaining ~100-LOC callback in the shell. It was flagged as the biggest high-risk extraction because it reads 20+ pieces of shell state and writes 5 setters, but the two confirm-open callbacks that depend on it sit right next to it in the same concern — bundling all three keeps them co-located in one testable unit.

How

  1. Create `useDraftPersistence.ts` that takes the saveable state, the `useWorkspaceDraftState`-derived appliers (`applyLoadedDraft`, `loadSimilarCaseIntoWorkspace`), the runbook-scope/saved-draft-id setters, and the toast callbacks as a single options object.
  2. Move the three callbacks into the hook, preserving the exact payload shape, logging, and runbook-scope migration rules.
  3. Update `DraftTab.tsx` to destructure the three handlers from the hook call.
  4. Drop the `shouldMigrateVisibleRunbookSession` + `shouldProceedAfterSaveAttempt` imports from the shell — they now live inside the hook.
  5. Add `useDraftPersistence.test.ts` with six `renderHook` tests covering the empty-workspace guard, new-draft path, existing-draft path, draft-open confirm flow (no pending and replace), and similar-case compare flow.

Testing

  • `pnpm tsc --noEmit` — clean.
  • `pnpm test` — 220 pass (was 214; +6 new hook tests).
  • `pnpm ui:gate:static` — exit 0.

Risk / Notes

  • `DraftTabHandle` unchanged (`saveDraft` still points at `handleSaveDraft`, now from the hook).
  • All payload fields preserved: input/response/ticket/sources/case_intake/handoff_summary/model/autosave flag.
  • Runbook-scope rekey + migration path preserved exactly, including the `runbookScopeLinked` fall-through that degrades the success toast to an advisory error when the migration fails.
  • `saveCaseOutcome`-linked ordering is unchanged: `setAutosaveDraftId(null)` fires before `setSavedDraftId` so autosave state is cleared before the new id lands.

Wave 5 status after this PR

  • DraftTab: 2573 → 1738 LOC (-835, ~32% total reduction)
  • Tests: 184 → 220 (+36 direct Draft concern tests)
  • 9 hooks + 1 panel extracted + 1 handle-shape test file
  • Still above the 1000-LOC success target; see the four-PR roadmap for the remaining path.

Move handleSaveDraft + handleConfirmOpenDraft + handleConfirmOpenSimilarCase
out of DraftTab.tsx into a dedicated hook. Hook accepts the shell's
saveable state, the workspaceDraftState-derived appliers (applyLoadedDraft,
loadSimilarCaseIntoWorkspace), setters for the runbook scope and saved/
autosave draft ids, and toast callbacks. Shell drops from 1893 to 1738
LOC and six new renderHook tests cover the save / update / compare
branches.
@saagpatel saagpatel merged commit 545aaa8 into master Apr 21, 2026
23 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants