Files
GearBox/.planning/phases/21-item-catalog-detail-pages/21-03-PLAN.md

17 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
21-item-catalog-detail-pages 03 execute 2
21-01
21-02
src/client/components/ItemCard.tsx
src/client/components/CandidateCard.tsx
src/client/components/CandidateListItem.tsx
src/client/components/CatalogSearchOverlay.tsx
src/client/routes/__root.tsx
src/client/stores/uiStore.ts
true
DETAIL-04
DETAIL-05
truths artifacts key_links
Clicking an ItemCard navigates to /items/:id instead of opening a slide-out panel
Clicking a CandidateCard navigates to /threads/:threadId/candidates/:candidateId
Clicking a CandidateListItem navigates to the candidate detail page
Clicking a catalog search result card navigates to /global-items/:id
Item slide-out panel is removed from __root.tsx
Candidate slide-out panel is removed from __root.tsx
Panel-related state is removed from UIStore
SlideOutPanel.tsx, ItemForm.tsx, and CandidateForm.tsx files still exist
path provides
src/client/components/ItemCard.tsx ItemCard with navigation instead of panel open
path provides
src/client/components/CandidateCard.tsx CandidateCard with navigation instead of panel open
path provides
src/client/components/CandidateListItem.tsx CandidateListItem with navigation instead of panel open
path provides
src/client/routes/__root.tsx Root layout without slide-out panels
path provides
src/client/stores/uiStore.ts UIStore without panel state properties
from to via pattern
src/client/components/ItemCard.tsx /items/$itemId route useNavigate → /items/$itemId navigate.*items.*itemId
from to via pattern
src/client/components/CandidateCard.tsx /threads/$threadId/candidates/$candidateId route useNavigate → /threads/$threadId/candidates/$candidateId navigate.*threads.*candidates
from to via pattern
src/client/components/CatalogSearchOverlay.tsx /global-items/$globalItemId route useNavigate → /global-items/$globalItemId navigate.*global-items
Rewire all card click handlers to navigate to detail pages instead of opening slide-out panels, then remove the slide-out panels from the root layout and clean up the UIStore.

Purpose: Completes the transition from panel-based editing to full detail pages. This is the final step — navigation targets from Plans 01 and 02 must exist first. Output: All cards navigate to detail pages, panels removed, UIStore cleaned

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/21-item-catalog-detail-pages/21-CONTEXT.md @.planning/phases/21-item-catalog-detail-pages/21-RESEARCH.md

@src/client/components/ItemCard.tsx @src/client/components/CandidateCard.tsx @src/client/components/CandidateListItem.tsx @src/client/components/CatalogSearchOverlay.tsx @src/client/routes/__root.tsx @src/client/stores/uiStore.ts

@.planning/phases/21-item-catalog-detail-pages/21-01-SUMMARY.md @.planning/phases/21-item-catalog-detail-pages/21-02-SUMMARY.md

ItemCard currently uses:

const openEditPanel = useUIStore((s) => s.openEditPanel);
onClick={() => openEditPanel(id)}
// Also: duplicateItem onSuccess calls openEditPanel(newItem.id)

CandidateCard currently uses:

const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);
onClick={() => openCandidateEditPanel(id)}
// Props include: threadId (available for navigation)

CandidateListItem currently uses:

const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);
onClick={() => openCandidateEditPanel(candidate.id)}
// candidate.threadId is available

__root.tsx panel instances (lines 189-221):

<SlideOutPanel isOpen={isItemPanelOpen} onClose={closePanel} title={...}>
  <ItemForm mode="add" | mode="edit" itemId={editingItemId} />
</SlideOutPanel>
<SlideOutPanel isOpen={isCandidatePanelOpen} onClose={closeCandidatePanel} title={...}>
  <CandidateForm mode="add" | mode="edit" threadId={...} candidateId={...} />
</SlideOutPanel>

UIStore properties to REMOVE:

panelMode, editingItemId, openAddPanel, openEditPanel, closePanel
candidatePanelMode, editingCandidateId, openCandidateAddPanel, openCandidateEditPanel, closeCandidatePanel

UIStore properties to KEEP:

confirmDeleteItemId, openConfirmDelete, closeConfirmDelete
confirmDeleteCandidateId, openConfirmDeleteCandidate, closeConfirmDeleteCandidate
resolveThreadId, resolveCandidateId, openResolveDialog, closeResolveDialog
// all other non-panel state
Task 1: Rewire card click handlers to navigate to detail pages src/client/components/ItemCard.tsx src/client/components/CandidateCard.tsx src/client/components/CandidateListItem.tsx src/client/components/CatalogSearchOverlay.tsx - src/client/components/ItemCard.tsx (full file — find openEditPanel usage) - src/client/components/CandidateCard.tsx (full file — find openCandidateEditPanel usage) - src/client/components/CandidateListItem.tsx (full file — find openCandidateEditPanel usage) - src/client/components/CatalogSearchOverlay.tsx (full file — find card rendering, add click navigation) - src/client/stores/uiStore.ts (verify which store properties each component uses) Per D-17: **ItemCard.tsx** — Replace panel open with navigation. 1. Remove: `const openEditPanel = useUIStore((s) => s.openEditPanel);` 2. Add: `import { useNavigate } from "@tanstack/react-router";` and `const navigate = useNavigate();` 3. Change main button `onClick`: `() => navigate({ to: "/items/$itemId", params: { itemId: String(id) } })` 4. Change duplicate onSuccess: `(newItem) => navigate({ to: "/items/$itemId", params: { itemId: String(newItem.id) } })` (navigate to the new item's detail page instead of opening edit panel) 5. Keep all other UIStore usage (openExternalLink, etc.) 6. If the component no longer imports anything from useUIStore, remove the import entirely. If it still uses openExternalLink, keep the import.
Per D-18: **CandidateCard.tsx** — Replace panel open with navigation.
1. Remove: `const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);`
2. Add: `import { useNavigate } from "@tanstack/react-router";` and `const navigate = useNavigate();`
3. Change main button `onClick`: `() => navigate({ to: "/threads/$threadId/candidates/$candidateId", params: { threadId: String(threadId), candidateId: String(id) } })`
4. Keep: openConfirmDeleteCandidate, openResolveDialog, openExternalLink from UIStore.

Per D-20: **CandidateListItem.tsx** — Replace panel open with navigation.
1. Remove: `const openCandidateEditPanel = useUIStore((s) => s.openCandidateEditPanel);`
2. Add: `import { useNavigate } from "@tanstack/react-router";` and `const navigate = useNavigate();`
3. Change the click handler: `() => navigate({ to: "/threads/$threadId/candidates/$candidateId", params: { threadId: String(candidate.threadId), candidateId: String(candidate.id) } })`
4. Keep all other UIStore usage.

Per D-19: **CatalogSearchOverlay.tsx** — Add card click navigation to `/global-items/:id`.
1. Add: `import { useNavigate } from "@tanstack/react-router";` and `const navigate = useNavigate();`
2. Find the card/grid item rendering for search results. Wrap the card body (not the "Add" button) in a clickable element that:
   - Calls `closeCatalogSearch()` then `navigate({ to: "/global-items/$globalItemId", params: { globalItemId: String(item.id) } })`
   - The existing "Add" button stays separate with `e.stopPropagation()` to prevent navigation when clicking Add
3. The card body should have `cursor-pointer` and hover styling to indicate clickability
cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5 - grep -q "useNavigate" src/client/components/ItemCard.tsx - grep -q "items.*itemId" src/client/components/ItemCard.tsx - grep -qv "openEditPanel" src/client/components/ItemCard.tsx - grep -q "useNavigate" src/client/components/CandidateCard.tsx - grep -q "threads.*candidates" src/client/components/CandidateCard.tsx - grep -qv "openCandidateEditPanel" src/client/components/CandidateCard.tsx - grep -q "useNavigate" src/client/components/CandidateListItem.tsx - grep -qv "openCandidateEditPanel" src/client/components/CandidateListItem.tsx - grep -q "useNavigate" src/client/components/CatalogSearchOverlay.tsx - grep -q "global-items" src/client/components/CatalogSearchOverlay.tsx - ItemCard click navigates to /items/:id - CandidateCard click navigates to /threads/:threadId/candidates/:candidateId - CandidateListItem click navigates to candidate detail page - Catalog search result card click navigates to /global-items/:id (closing overlay first) - "Add" button on catalog cards still works independently - No component references openEditPanel or openCandidateEditPanel Task 2: Remove slide-out panels from root layout and clean UIStore src/client/routes/__root.tsx src/client/stores/uiStore.ts - src/client/routes/__root.tsx (full file — identify panel JSX to remove, imports to clean) - src/client/stores/uiStore.ts (full file — identify panel state to remove) - src/client/components/ItemCard.tsx (verify openEditPanel no longer imported — done in Task 1) - src/client/components/CandidateCard.tsx (verify openCandidateEditPanel no longer imported) - src/client/routes/threads/$threadId/index.tsx (verify openCandidateAddPanel no longer imported — done in Plan 02) Per D-21, D-22: **__root.tsx** — Remove slide-out panel instances. 1. Remove the Item SlideOutPanel block (lines ~189-199 in current file): ``` {panelMode === "add" && } {panelMode === "edit" && } ``` 2. Remove the Candidate SlideOutPanel block (lines ~202-221 in current file): ``` {currentThreadId != null && ( )} ``` 3. Remove all panel-related state reads from the component: - `const panelMode = useUIStore((s) => s.panelMode);` - `const editingItemId = useUIStore((s) => s.editingItemId);` - `const closePanel = useUIStore((s) => s.closePanel);` - `const candidatePanelMode = useUIStore((s) => s.candidatePanelMode);` - `const editingCandidateId = useUIStore((s) => s.editingCandidateId);` - `const closeCandidatePanel = useUIStore((s) => s.closeCandidatePanel);` - `const isItemPanelOpen = panelMode !== "closed";` - `const isCandidatePanelOpen = candidatePanelMode !== "closed";` 4. Remove unused imports: `SlideOutPanel`, `ItemForm`, `CandidateForm` (from the import block) 5. Per D-25: Keep the `SlideOutPanel.tsx` component FILE — just remove its usage from __root.tsx 6. Per D-26: Keep `ItemForm.tsx` and `CandidateForm.tsx` files — just remove their import from __root.tsx 7. The `currentThreadId` variable may still be needed by CandidateDeleteDialog and ResolveDialog — check if it's still referenced. If those dialogs use it, keep the `threadMatch` and `currentThreadId` logic. If not, remove.
Per D-23, D-24: **uiStore.ts** — Remove panel state.
Remove from UIState interface AND implementation:
- `panelMode: "closed" | "add" | "edit"`
- `editingItemId: number | null`
- `openAddPanel: () => void`
- `openEditPanel: (itemId: number) => void`
- `closePanel: () => void`
- `candidatePanelMode: "closed" | "add" | "edit"`
- `editingCandidateId: number | null`
- `openCandidateAddPanel: () => void`
- `openCandidateEditPanel: (id: number) => void`
- `closeCandidatePanel: () => void`

KEEP all other state:
- confirmDeleteItemId, openConfirmDelete, closeConfirmDelete
- confirmDeleteCandidateId, openConfirmDeleteCandidate, closeConfirmDeleteCandidate
- resolveThreadId, resolveCandidateId, openResolveDialog, closeResolveDialog
- itemPickerOpen, openItemPicker, closeItemPicker
- confirmDeleteSetupId, openConfirmDeleteSetup, closeConfirmDeleteSetup
- createThreadModalOpen, openCreateThreadModal, closeCreateThreadModal
- externalLinkUrl, openExternalLink, closeExternalLink
- candidateViewMode, setCandidateViewMode
- selectedSetupId, setSelectedSetupId
- fabMenuOpen, openFabMenu, closeFabMenu
- catalogSearchOpen, catalogSearchMode, openCatalogSearch, closeCatalogSearch

After cleanup, do a project-wide search for any remaining references to the removed properties:
`grep -r "openEditPanel\|openAddPanel\|closePanel\|openCandidateEditPanel\|openCandidateAddPanel\|closeCandidatePanel\|panelMode\|editingItemId\|editingCandidateId\|candidatePanelMode" src/client/ --include="*.tsx" --include="*.ts"`
If any references remain, update those files to remove the dead references (likely just removing unused imports or store selectors).
cd /home/jean-luc-makiola/Development/projects/GearBox && bun run lint 2>&1 | tail -5 - grep -qv "SlideOutPanel" src/client/routes/__root.tsx - grep -qv "ItemForm" src/client/routes/__root.tsx - grep -qv "CandidateForm" src/client/routes/__root.tsx - grep -qv "panelMode" src/client/routes/__root.tsx - grep -qv "openEditPanel" src/client/stores/uiStore.ts - grep -qv "openAddPanel" src/client/stores/uiStore.ts - grep -qv "openCandidateEditPanel" src/client/stores/uiStore.ts - grep -qv "openCandidateAddPanel" src/client/stores/uiStore.ts - grep -qv "candidatePanelMode" src/client/stores/uiStore.ts - grep -q "openConfirmDelete" src/client/stores/uiStore.ts - grep -q "openResolveDialog" src/client/stores/uiStore.ts - test -f src/client/components/SlideOutPanel.tsx - test -f src/client/components/ItemForm.tsx - test -f src/client/components/CandidateForm.tsx - Item and candidate SlideOutPanel instances removed from __root.tsx - SlideOutPanel, ItemForm, CandidateForm imports removed from __root.tsx - Panel-related state (panelMode, editingItemId, candidatePanelMode, editingCandidateId) removed from UIStore - Panel-related actions (openEditPanel, openAddPanel, closePanel, openCandidateEditPanel, openCandidateAddPanel, closeCandidatePanel) removed from UIStore - Non-panel state preserved (confirm delete, resolve dialog, FAB, catalog search, etc.) - SlideOutPanel.tsx, ItemForm.tsx, CandidateForm.tsx files still exist on disk - No remaining references to removed properties anywhere in src/client/ - Lint passes cleanly - `bun run lint` passes with no errors - `bun run dev` starts and the full flow works: - Click an item card → navigates to `/items/:id` detail page - Click a candidate card → navigates to `/threads/:threadId/candidates/:candidateId` - Click a catalog search result → closes overlay, navigates to `/global-items/:id` - No slide-out panels appear anywhere in the app - Confirm delete, resolve dialog, FAB menu, catalog search overlay all still work - `grep -r "openEditPanel\|openCandidateEditPanel\|panelMode\|candidatePanelMode" src/client/ --include="*.tsx" --include="*.ts"` returns no results

<success_criteria>

  • All card components navigate to detail pages instead of opening panels
  • Slide-out panels completely removed from the application
  • UIStore cleaned of all panel-related state
  • All non-panel functionality preserved (dialogs, FAB, catalog search)
  • No broken references or dead imports
  • Lint passes cleanly </success_criteria>
After completion, create `.planning/phases/21-item-catalog-detail-pages/21-03-SUMMARY.md`