Files
GearBox/.planning/phases/04-database-planning-fixes/04-02-PLAN.md

12 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
04-database-planning-fixes 02 execute 2
04-01
src/client/stores/uiStore.ts
src/client/components/CreateThreadModal.tsx
src/client/components/ThreadCard.tsx
src/client/routes/collection/index.tsx
false
PLAN-01
PLAN-02
truths artifacts key_links
User can create a thread via a modal dialog with name and category fields
User sees an inviting empty state explaining the 3-step planning workflow when no threads exist
User can switch between Active and Resolved threads using pill tabs
Thread cards display category icon and name
path provides min_lines
src/client/components/CreateThreadModal.tsx Modal dialog for thread creation with name + category picker 60
path provides contains
src/client/routes/collection/index.tsx PlanningView with empty state, pill tabs, category filter, modal trigger CreateThreadModal
path provides contains
src/client/components/ThreadCard.tsx Thread card with category display categoryEmoji
from to via pattern
src/client/components/CreateThreadModal.tsx src/client/hooks/useThreads.ts useCreateThread mutation with { name, categoryId } useCreateThread
from to via pattern
src/client/routes/collection/index.tsx src/client/components/CreateThreadModal.tsx createThreadModalOpen state from uiStore CreateThreadModal
from to via pattern
src/client/components/ThreadCard.tsx ThreadListItem categoryName and categoryEmoji props categoryEmoji|categoryName
Build the frontend for thread creation modal, polished empty state, Active/Resolved pill tabs, category filter, and category display on thread cards.

Purpose: PLAN-01 (user can create threads without errors via modal) and PLAN-02 (polished empty state with CTA). This completes the planning tab UX overhaul. Output: Working planning tab with modal-based thread creation, educational empty state, pill tab filtering, and category-aware thread cards.

<execution_context> @/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md @/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/ROADMAP.md @.planning/phases/04-database-planning-fixes/04-CONTEXT.md @.planning/phases/04-database-planning-fixes/04-01-SUMMARY.md

From src/client/hooks/useThreads.ts (after Plan 01):

interface ThreadListItem {
  id: number;
  name: string;
  status: "active" | "resolved";
  resolvedCandidateId: number | null;
  createdAt: string;
  updatedAt: string;
  candidateCount: number;
  minPriceCents: number | null;
  maxPriceCents: number | null;
  categoryId: number;
  categoryName: string;
  categoryEmoji: string;
}

// useCreateThread expects { name: string; categoryId: number }

From src/client/hooks/useCategories.ts:

export function useCategories(): UseQueryResult<Category[]>;
// Category = { id: number; name: string; emoji: string; createdAt: Date }

From src/client/stores/uiStore.ts (needs createThreadModal state added):

// Existing pattern for dialogs:
// resolveThreadId: number | null;
// openResolveDialog: (threadId, candidateId) => void;
// closeResolveDialog: () => void;

From src/client/routes/collection/index.tsx (CollectionView empty state pattern):

// Lines 58-93: empty state with emoji, heading, description, CTA button
// Follow this pattern for planning empty state
Task 1: Create thread modal and update uiStore src/client/stores/uiStore.ts, src/client/components/CreateThreadModal.tsx 1. In `src/client/stores/uiStore.ts`, add create-thread modal state following the existing dialog pattern: ``` createThreadModalOpen: boolean; openCreateThreadModal: () => void; closeCreateThreadModal: () => void; ``` Initialize `createThreadModalOpen: false` and wire up the actions.
  1. Create src/client/components/CreateThreadModal.tsx:
    • A modal overlay (fixed inset-0, bg-black/50 backdrop, centered white panel) following the same pattern as the app's existing dialog styling.
    • Form fields: Thread name (text input, required, min 1 char) and Category (select dropdown populated from useCategories() hook).
    • Category select shows emoji + name for each option. Pre-select the first category.
    • Submit calls useCreateThread().mutate({ name, categoryId }).
    • On success: close modal (via closeCreateThreadModal from uiStore), reset form.
    • On error: show inline error message.
    • Cancel button and clicking backdrop closes modal.
    • Disable submit button while isPending.
    • Use Tailwind classes consistent with existing app styling (rounded-xl, text-sm, blue-600 primary buttons, gray-200 borders). cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5 CreateThreadModal component renders a modal with name input and category dropdown, submits via useCreateThread, uiStore has createThreadModalOpen state
Task 2: Overhaul PlanningView with empty state, pill tabs, category filter, and thread card category display src/client/routes/collection/index.tsx, src/client/components/ThreadCard.tsx 1. In `src/client/components/ThreadCard.tsx`: - Add `categoryName: string` and `categoryEmoji: string` props to `ThreadCardProps`. - Display category as a pill badge (emoji + name) in the card's badge row, using a style like `bg-blue-50 text-blue-700` to distinguish from existing badges.
  1. In src/client/routes/collection/index.tsx, rewrite the PlanningView function:

    Remove: The inline text input + button form for thread creation. Remove the showResolved checkbox.

    Add state:

    • activeTab: "active" | "resolved" (default "active") for the pill tab selector.
    • categoryFilter: number | null (default null = all categories) for filtering.
    • Import useCategories hook, useUIStore, and CreateThreadModal.

    Layout (top to bottom):

    a. Header row: "Planning Threads" heading on the left, "New Thread" button on the right. Button calls openCreateThreadModal() from uiStore. Use a plus icon (inline SVG, same pattern as collection empty state button).

    b. Filter row: Active/Resolved pill tab selector on the left, category filter dropdown on the right.

    • Pill tabs: Two buttons styled as a segment control. Active pill gets bg-blue-600 text-white, inactive gets bg-gray-100 text-gray-600 hover:bg-gray-200. Rounded-full, px-4 py-1.5, text-sm font-medium. Wrap in a flex bg-gray-100 rounded-full p-0.5 gap-0.5 container.
    • Category filter: A <select> dropdown with "All categories" as default option, then each category with emoji + name. Filter threads client-side by matching thread.categoryId === categoryFilter.

    c. Thread list or empty state:

    • Pass activeTab === "resolved" as includeResolved to useThreads. When activeTab === "active", show only active threads. When activeTab === "resolved", filter the results to show only resolved threads (since includeResolved=true returns both).
    • Apply categoryFilter on the client side if set.

    d. Empty state (when filtered threads array is empty AND activeTab is "active" AND no category filter):

    • Guided + educational tone per user decision.
    • Max-width container (max-w-lg mx-auto), centered, py-16.
    • Heading: "Plan your next purchase" (text-xl font-semibold).
    • Three illustrated steps showing the workflow, each as a row with a step number circle (1, 2, 3), a short title, and a description:
      1. "Create a thread" -- "Start a research thread for gear you're considering"
      2. "Add candidates" -- "Add products you're comparing with prices and weights"
      3. "Pick a winner" -- "Resolve the thread and the winner joins your collection"
    • Style each step: flex row, step number in a 8x8 rounded-full bg-blue-100 text-blue-700 font-bold circle, title in font-medium, description in text-sm text-gray-500.
    • CTA button below steps: "Create your first thread" -- calls openCreateThreadModal(). Blue-600 bg, white text, same style as collection empty state button.
    • If empty because of active filter (category or "resolved" tab), show a simpler "No threads found" message instead of the full educational empty state.

    e. Render <CreateThreadModal /> at the bottom of PlanningView (it reads its own open/close state from uiStore).

    f. Thread grid: Keep existing grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4. Pass categoryName and categoryEmoji as new props to ThreadCard. cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5 PlanningView shows educational empty state with 3-step workflow, pill tabs for Active/Resolved, category filter dropdown, "New Thread" button opens modal, ThreadCard shows category badge, inline form is removed

src/client/routes/collection/index.tsx Task 3: Verify planning tab overhaul Complete planning tab overhaul: thread creation modal, educational empty state, Active/Resolved pill tabs, category filter, and category display on thread cards. 1. Start both dev servers: `bun run dev:server` and `bun run dev:client` 2. Visit http://localhost:5173/collection?tab=planning 3. Verify the educational empty state appears with 3 illustrated steps and a "Create your first thread" CTA button 4. Click "Create your first thread" -- a modal should open with name input and category dropdown 5. Create a thread (enter a name, select a category, submit) 6. Verify the thread appears as a card with category emoji + name badge 7. Verify the "New Thread" button appears in the header area 8. Create a second thread in a different category 9. Test the category filter dropdown -- filtering should show only matching threads 10. Test the Active/Resolved pill tabs -- should toggle between active and resolved views Type "approved" or describe issues Human verifies the planning tab UI overhaul by testing the complete flow in browser. cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5 User confirms: empty state shows 3-step workflow, modal creates threads with category, pill tabs filter Active/Resolved, category filter works, thread cards show category - `bun run lint` passes with no errors - Planning tab shows educational empty state when no threads exist - Thread creation modal opens from both empty state CTA and header button - Creating a thread with name + category succeeds and thread appears in list - Thread cards show category emoji and name - Active/Resolved pill tabs filter correctly - Category filter narrows the thread list

<success_criteria>

  • Inline thread creation form is replaced with modal dialog
  • Empty state educates users about the 3-step planning workflow
  • Active/Resolved pill tabs replace the "Show archived" checkbox
  • Category filter allows narrowing thread list by category
  • Thread cards display category information
  • No lint errors </success_criteria>
After completion, create `.planning/phases/04-database-planning-fixes/04-02-SUMMARY.md`