plans
2026-05-10
2026 05 10 Hooks Migration

Hooks Migration Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans

Goal: Migrate hooks to follow SoC rules — useQuery/useMutation must be in components, not hooks. Hooks should only manage UI state.

Reference: apps/frontend/hooks/.claude/rules/hooks.md


Current State: 74 Hook Files

Violations Found

CategoryCountRule Violated
Hooks with useQuery/useMutation17Forbidden in hooks
Hooks wrapping context2No wrapper hooks
Potential dead code hooks~10+Unused or one-time use

Hook Rules (from hooks.md)

Forbidden in use-* Hooks

ForbiddenReason
useQuery, useMutationMust be called directly in components
Direct API/network callsHides data dependencies
Business logicBelongs in lib/services/

Allowed in use-* Hooks

AllowedExamples
React stateuseState, useCallback, useMemo, useRef
Form stateuseForm (react-hook-form)
Local UI logicmodal open/close, scroll position, countdown
Custom contextuseContext (but use useContextSelector pattern)

Migration Categories

Category A: Hooks with useQuery/useMutation — Move to Components

These hooks contain Convex calls and must be refactored. The data fetching logic should move to components calling useQuery/useMutation directly.

Files:

  • use-upcoming-shows.ts — Convex useQuery for shows
  • use-ticket-detail.ts — Convex useQuery for ticket
  • use-table-order.ts — Convex useQuery + useMutation
  • use-staff-order.ts — Convex useQuery + useMutation
  • use-spin-wheel.ts — Convex useQuery + useMutation
  • use-shows-list.ts — Convex useQuery + useMutation
  • use-show-reminder.ts — Convex useQuery
  • use-show-event-list.ts — Convex useQuery + useMutation
  • use-reservations-list.ts — Convex useQuery + useMutation
  • use-reservation-filters.ts — Convex useQuery
  • use-reservation-detail.ts — Convex useQuery + useMutation
  • use-photo-wall.ts — Convex useQuery
  • use-photo-submit.ts — Convex useMutation
  • use-photo-like.ts — Convex useMutation
  • use-live-viewer-count.ts — Convex useQuery + useMutation
  • use-guest-wall.ts — Convex useQuery
  • use-addons-list.ts — Convex useQuery

Category B: Form Hooks — Keep but Review

These hooks use react-hook-form for form state. They're acceptable if they don't contain useQuery/useMutation.

Pattern:

// GOOD — form state + local validation only
function useReservationForm() {
  const form = useForm({ ... });
  const createReservation = useMutation(...); // ← Convex in hook is BANNED
  return { form };
}

Files to review:

  • use-show-form.ts
  • use-form-session.ts
  • use-reservation-form.ts
  • use-dinner-theater-form.ts
  • use-booking-reservation-form.ts
  • use-addon-form.ts
  • use-contact-form.ts
  • use-checkout-form.ts
  • use-artist-proposal-form.ts
  • use-profile-form.ts
  • use-batch-generation-form.ts
  • use-challenge-review.ts

Category C: Pure UI Hooks — Keep

These hooks manage UI state only (no Convex calls, no context wrapping). They're acceptable.

Files:

  • use-modal-state.ts — local boolean state
  • use-mobile-menu.ts — local UI state
  • use-carousel.ts — local UI state
  • use-countdown.ts — timer logic
  • use-scroll-lock.ts — DOM scroll
  • use-escape-key.ts — keyboard listener
  • use-active-section.ts — scroll tracking
  • use-is-mobile.ts — breakpoint check
  • use-header-scroll.ts — scroll state
  • use-scroll-header.ts — scroll state
  • use-scroll-navigation.ts — navigation
  • use-curtain.ts — animation state
  • use-french-mentalist-countdown.ts — countdown
  • use-payment-countdown.ts — countdown
  • use-menu-book.ts — page state
  • use-french-mentalist-pricing.ts — pricing display
  • use-sticky-cart-pricing.ts — price calculation
  • use-payment-state.ts — payment UI state
  • use-confirmation-modal-state.ts — modal state
  • use-availability-badge.ts — UI badge state
  • use-selected-bundle.ts — local selection
  • use-guest-count.ts — counter state
  • use-ticket-selection.ts — selection state
  • use-addon-selection.ts — selection state
  • use-table-order.ts — local order state

Category D: Wrappers Around Context — BANNED

These hooks wrap context access. They must be deleted — use useContextSelector directly.

Already deleted:

  • use-reservation-step-state.ts
  • use-payment-handlers.ts
  • use-reservation-step.ts

Category E: Hooks with Business Logic — Move to Services

These hooks contain business logic that should be in lib/services/.

Examples:

  • use-schedule-data.ts — contains data transformation logic
  • use-confirmation-details-formatter.ts — formatting logic
  • use-reservation-status.ts — status display logic
  • use-qr-canvas.ts — QR generation (could be lib utility)

Category F: Dead Code / Unused — Delete

Find and delete hooks that have no consumers.


Migration Strategy

Phase 1: Delete Banned Hooks (Quick Wins)

Task 1: Delete Category D wrappers (already done)

Task 2: Find and delete dead code hooks

# Find hooks with no imports
for f in apps/frontend/hooks/*.ts; do
  name=$(basename "$f" .ts)
  count=$(grep -r "$name" apps/frontend --include="*.tsx" --include="*.ts" | grep -v "^$f" | wc -l)
  if [ "$count" -eq 0 ]; then echo "$f"; fi
done

Phase 2: Category C — Pure UI Hooks (Safe to Keep)

These are already compliant. Just verify they don't have hidden violations.

Phase 3: Category B — Form Hooks (Review & Fix)

For each form hook:

  1. Check if it contains useQuery/useMutation
  2. If yes → move Convex calls to component
  3. If no → keep as-is

Phase 4: Category A — Hooks with Convex Calls (Major Refactor)

Pattern to implement:

// BEFORE (BANNED)
function useReservationDetail(reservationId: string) {
  const reservation = useQuery(api.reservations.get, { id: reservationId });
  return { reservation };
}
 
// AFTER (CORRECT)
function ReservationDetail({ reservationId }: { reservationId: string }) {
  const reservation = useQuery(api.reservations.get, { id: reservationId });
  return <div>{reservation.data?.title}</div>;
}

Steps per hook:

  1. Find all components using the hook
  2. Move useQuery/useMutation calls to each component
  3. Keep pure UI logic in the hook (or inline it)
  4. Delete the hook file
  5. Update imports in components

Phase 5: Category E — Business Logic (Service Extraction)

Extract business logic to lib/services/:

  • Data transformations → services
  • Calculations → services
  • Formatting → utilities

File Structure After Migration

apps/frontend/
├── hooks/                           # Pure UI hooks only
│   ├── use-modal-state.ts
│   ├── use-carousel.ts
│   ├── use-countdown.ts
│   └── ...
├── lib/
│   └── services/                   # Business logic
│       ├── reservation.service.ts
│       ├── pricing.service.ts
│       └── ...
├── contexts/                       # Shared state
│   ├── reservation-draft.context.tsx
│   ├── dashboard.context.tsx
│   └── ...
└── components/                    # Components call useQuery/useMutation directly
    ├── booking/
    │   ├── step-tickets.tsx       # ← useQuery here
    │   └── ...

Implementation Order

  1. Phase 1 (delete banned + dead code) — Quick, low risk
  2. Phase 2 (verify pure UI hooks) — Quick review
  3. Phase 3 (review form hooks) — Medium effort
  4. Phase 4 (refactor Convex hooks) — High effort, most impact
  5. Phase 5 (extract services) — Can be done in parallel with Phase 4

Verification Commands

# Find hooks with useQuery/useMutation
grep -l "useQuery\|useMutation" apps/frontend/hooks/*.ts
 
# Find hooks with context wrapping
grep -l "useContextSelector\|Context)" apps/frontend/hooks/*.ts
 
# Find unused hooks
for f in apps/frontend/hooks/*.ts; do
  name=$(basename "$f" .ts)
  count=$(grep -r "$name" apps/frontend --include="*.tsx" --include="*.ts" | grep -v "^$f" | wc -l)
  [ "$count" -eq 0 ] && echo "$f"
done