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
| Category | Count | Rule Violated |
|---|---|---|
Hooks with useQuery/useMutation | 17 | Forbidden in hooks |
| Hooks wrapping context | 2 | No wrapper hooks |
| Potential dead code hooks | ~10+ | Unused or one-time use |
Hook Rules (from hooks.md)
Forbidden in use-* Hooks
| Forbidden | Reason |
|---|---|
useQuery, useMutation | Must be called directly in components |
| Direct API/network calls | Hides data dependencies |
| Business logic | Belongs in lib/services/ |
Allowed in use-* Hooks
| Allowed | Examples |
|---|---|
| React state | useState, useCallback, useMemo, useRef |
| Form state | useForm (react-hook-form) |
| Local UI logic | modal open/close, scroll position, countdown |
| Custom context | useContext (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— ConvexuseQueryfor showsuse-ticket-detail.ts— ConvexuseQueryfor ticketuse-table-order.ts— ConvexuseQuery+useMutationuse-staff-order.ts— ConvexuseQuery+useMutationuse-spin-wheel.ts— ConvexuseQuery+useMutationuse-shows-list.ts— ConvexuseQuery+useMutationuse-show-reminder.ts— ConvexuseQueryuse-show-event-list.ts— ConvexuseQuery+useMutationuse-reservations-list.ts— ConvexuseQuery+useMutationuse-reservation-filters.ts— ConvexuseQueryuse-reservation-detail.ts— ConvexuseQuery+useMutationuse-photo-wall.ts— ConvexuseQueryuse-photo-submit.ts— ConvexuseMutationuse-photo-like.ts— ConvexuseMutationuse-live-viewer-count.ts— ConvexuseQuery+useMutationuse-guest-wall.ts— ConvexuseQueryuse-addons-list.ts— ConvexuseQuery
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.tsuse-form-session.tsuse-reservation-form.tsuse-dinner-theater-form.tsuse-booking-reservation-form.tsuse-addon-form.tsuse-contact-form.tsuse-checkout-form.tsuse-artist-proposal-form.tsuse-profile-form.tsuse-batch-generation-form.tsuse-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 stateuse-mobile-menu.ts— local UI stateuse-carousel.ts— local UI stateuse-countdown.ts— timer logicuse-scroll-lock.ts— DOM scrolluse-escape-key.ts— keyboard listeneruse-active-section.ts— scroll trackinguse-is-mobile.ts— breakpoint checkuse-header-scroll.ts— scroll stateuse-scroll-header.ts— scroll stateuse-scroll-navigation.ts— navigationuse-curtain.ts— animation stateuse-french-mentalist-countdown.ts— countdownuse-payment-countdown.ts— countdownuse-menu-book.ts— page stateuse-french-mentalist-pricing.ts— pricing displayuse-sticky-cart-pricing.ts— price calculationuse-payment-state.ts— payment UI stateuse-confirmation-modal-state.ts— modal stateuse-availability-badge.ts— UI badge stateuse-selected-bundle.ts— local selectionuse-guest-count.ts— counter stateuse-ticket-selection.ts— selection stateuse-addon-selection.ts— selection stateuse-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 logicuse-confirmation-details-formatter.ts— formatting logicuse-reservation-status.ts— status display logicuse-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
donePhase 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:
- Check if it contains
useQuery/useMutation - If yes → move Convex calls to component
- 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:
- Find all components using the hook
- Move
useQuery/useMutationcalls to each component - Keep pure UI logic in the hook (or inline it)
- Delete the hook file
- 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
- Phase 1 (delete banned + dead code) — Quick, low risk
- Phase 2 (verify pure UI hooks) — Quick review
- Phase 3 (review form hooks) — Medium effort
- Phase 4 (refactor Convex hooks) — High effort, most impact
- 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