Archive v1.1 artifacts (roadmap, requirements, phases) to milestones/. Evolve PROJECT.md with shipped requirements and new key decisions. Reorganize ROADMAP.md with collapsed milestone groupings. Update retrospective with v1.1 lessons. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
238 lines
12 KiB
Markdown
238 lines
12 KiB
Markdown
---
|
|
phase: 04-database-planning-fixes
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on: [04-01]
|
|
files_modified:
|
|
- src/client/stores/uiStore.ts
|
|
- src/client/components/CreateThreadModal.tsx
|
|
- src/client/components/ThreadCard.tsx
|
|
- src/client/routes/collection/index.tsx
|
|
autonomous: false
|
|
requirements: [PLAN-01, PLAN-02]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "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"
|
|
artifacts:
|
|
- path: "src/client/components/CreateThreadModal.tsx"
|
|
provides: "Modal dialog for thread creation with name + category picker"
|
|
min_lines: 60
|
|
- path: "src/client/routes/collection/index.tsx"
|
|
provides: "PlanningView with empty state, pill tabs, category filter, modal trigger"
|
|
contains: "CreateThreadModal"
|
|
- path: "src/client/components/ThreadCard.tsx"
|
|
provides: "Thread card with category display"
|
|
contains: "categoryEmoji"
|
|
key_links:
|
|
- from: "src/client/components/CreateThreadModal.tsx"
|
|
to: "src/client/hooks/useThreads.ts"
|
|
via: "useCreateThread mutation with { name, categoryId }"
|
|
pattern: "useCreateThread"
|
|
- from: "src/client/routes/collection/index.tsx"
|
|
to: "src/client/components/CreateThreadModal.tsx"
|
|
via: "createThreadModalOpen state from uiStore"
|
|
pattern: "CreateThreadModal"
|
|
- from: "src/client/components/ThreadCard.tsx"
|
|
to: "ThreadListItem"
|
|
via: "categoryName and categoryEmoji props"
|
|
pattern: "categoryEmoji|categoryName"
|
|
---
|
|
|
|
<objective>
|
|
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.
|
|
</objective>
|
|
|
|
<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>
|
|
|
|
<context>
|
|
@.planning/ROADMAP.md
|
|
@.planning/phases/04-database-planning-fixes/04-CONTEXT.md
|
|
@.planning/phases/04-database-planning-fixes/04-01-SUMMARY.md
|
|
|
|
<interfaces>
|
|
<!-- From Plan 01: updated types the executor will consume -->
|
|
|
|
From src/client/hooks/useThreads.ts (after Plan 01):
|
|
```typescript
|
|
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:
|
|
```typescript
|
|
export function useCategories(): UseQueryResult<Category[]>;
|
|
// Category = { id: number; name: string; emoji: string; createdAt: Date }
|
|
```
|
|
|
|
From src/client/stores/uiStore.ts (needs createThreadModal state added):
|
|
```typescript
|
|
// Existing pattern for dialogs:
|
|
// resolveThreadId: number | null;
|
|
// openResolveDialog: (threadId, candidateId) => void;
|
|
// closeResolveDialog: () => void;
|
|
```
|
|
|
|
From src/client/routes/collection/index.tsx (CollectionView empty state pattern):
|
|
```typescript
|
|
// Lines 58-93: empty state with emoji, heading, description, CTA button
|
|
// Follow this pattern for planning empty state
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create thread modal and update uiStore</name>
|
|
<files>src/client/stores/uiStore.ts, src/client/components/CreateThreadModal.tsx</files>
|
|
<action>
|
|
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.
|
|
|
|
2. 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).
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>CreateThreadModal component renders a modal with name input and category dropdown, submits via useCreateThread, uiStore has createThreadModalOpen state</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Overhaul PlanningView with empty state, pill tabs, category filter, and thread card category display</name>
|
|
<files>src/client/routes/collection/index.tsx, src/client/components/ThreadCard.tsx</files>
|
|
<action>
|
|
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.
|
|
|
|
2. 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.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>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</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<files>src/client/routes/collection/index.tsx</files>
|
|
<name>Task 3: Verify planning tab overhaul</name>
|
|
<what-built>Complete planning tab overhaul: thread creation modal, educational empty state, Active/Resolved pill tabs, category filter, and category display on thread cards.</what-built>
|
|
<how-to-verify>
|
|
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
|
|
</how-to-verify>
|
|
<resume-signal>Type "approved" or describe issues</resume-signal>
|
|
<action>Human verifies the planning tab UI overhaul by testing the complete flow in browser.</action>
|
|
<verify>
|
|
<automated>cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>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</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `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
|
|
</verification>
|
|
|
|
<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>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/04-database-planning-fixes/04-02-SUMMARY.md`
|
|
</output>
|