Commit Graph

63 Commits

Author SHA1 Message Date
e19d40e232 refactor: strip stats and unit switcher from top bar
Some checks failed
CI / ci (push) Failing after 19s
CI / e2e (push) Has been skipped
Remove weight unit switcher pills and collection stats (items, weight,
spent) from TotalsBar. Top bar now shows only logo/title and user menu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:32:02 +02:00
024e9f909b fix: make image read-only for reference items, rename delete to remove
- Reference items show catalog image as read-only in edit mode (no upload)
- "Delete" button renamed to "Remove from Collection" for reference items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:27:16 +02:00
69308e293f fix: restrict edit mode for reference items to personal fields only
Reference items (linked to global catalog) now show name, brand, weight,
and MSRP as read-only in edit mode with "from the catalog" hint. Only
personal fields (notes, category, quantity, image, product URL) are
editable. Standalone items retain full edit access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:22:09 +02:00
c33b7c7bdc feat(22-02): build AddToThreadModal with thread picker and new thread flow
- Create AddToThreadModal with pick/create modes for thread selection
- Support existing thread selection with category display
- Support new thread creation with candidate in one step
- Pre-select session thread via catalogSessionThreadId
- Auto-switch to create mode when no active threads exist
- Wire AddToThreadModal at root layout level
2026-04-06 16:00:34 +02:00
ed76236294 feat(22-01): wire catalog search and detail page to collection/thread modals
- Replace handleAddStub with handleAdd dispatching to correct modal by mode
- Global item detail page: add both "Add to Collection" and "Add to Thread" buttons
- Remove console.log stub from detail page
- Import useUIStore in both components

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:56:40 +02:00
f309c73304 feat(22-01): add UIStore modal states, AddToCollectionModal, and sonner toasts
- Extend UIStore with addToCollectionModal, addToThreadModal, catalogSessionThreadId
- Create AddToCollectionModal with category dropdown, notes, purchase price
- Install sonner and add Toaster + AddToCollectionModal to root layout
- closeCatalogSearch now resets catalogSessionThreadId

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:55:44 +02:00
a62357c063 Merge branch 'worktree-agent-a00c5cfa' into Develop
# Conflicts:
#	.planning/REQUIREMENTS.md
#	.planning/STATE.md
#	src/client/components/CatalogSearchOverlay.tsx
#	src/client/routes/threads/$threadId.tsx
2026-04-06 15:15:57 +02:00
4c79735426 feat(21-03): remove slide-out panels from root layout and clean UIStore
- Remove Item and Candidate SlideOutPanel instances from __root.tsx
- Remove SlideOutPanel, ItemForm, CandidateForm imports from root
- Remove panel state (panelMode, editingItemId, candidatePanelMode, editingCandidateId) from UIStore
- Remove panel actions (openEditPanel, openAddPanel, closePanel, etc.) from UIStore
- Preserve currentThreadId derivation for CandidateDeleteDialog
- Update CollectionView empty state to use catalog search instead of add panel
- Update ItemForm/CandidateForm with onClose prop replacing store panel close
- Clean all dead panel references across src/client/
2026-04-06 15:12:59 +02:00
a5a40b2068 Merge branch 'worktree-agent-a4608610' into Develop
# Conflicts:
#	.planning/ROADMAP.md
#	.planning/STATE.md
#	src/client/routes/threads/$threadId.tsx
2026-04-06 15:04:13 +02:00
6474033414 Merge branch 'worktree-agent-a1363a63' into Develop
# Conflicts:
#	.planning/ROADMAP.md
#	.planning/STATE.md
2026-04-06 15:04:00 +02:00
52c9ec3fe2 docs: stage before wave 1 merge 2026-04-06 15:03:45 +02:00
47b416effd feat(21-02): replace slide-out panel with add-candidate modal on thread page
- Add local AddCandidateModal component with all candidate form fields
- Remove openCandidateAddPanel UIStore dependency
- Modal includes image upload, category picker, pros/cons, validation
2026-04-06 15:02:13 +02:00
408025bb36 feat(21-01): enhance catalog detail page with Add to Collection button
- Add image placeholder (package icon) when no imageUrl exists
- Add 'Add to Collection' button stub between specs and description
- Button styled per D-10, logs to console (actual flow wired in Phase 22)
- Consistent layout with item detail page
2026-04-06 15:02:07 +02:00
3228bcadbe feat(21-01): create private item detail page with edit mode toggle
- Full detail page at /items/:id with hero image, name, spec badges, notes, product link
- Edit mode toggle: read-only by default, editable inputs when Edit clicked
- Save persists via useUpdateItem, Cancel reverts to read-only
- Duplicate and Delete actions via existing hooks/dialogs
- Back link to /collection, loading shimmer, error state
- CategoryPicker and ImageUpload in edit mode
2026-04-06 15:01:10 +02:00
cecaf78ead feat(21-02): restructure thread route and create candidate detail page
- Move $threadId.tsx to $threadId/index.tsx for nested route support
- Create candidate detail page at /threads/:threadId/candidates/:candidateId
- Edit mode toggle with form fields for all candidate properties
- Back navigation, pick-as-winner, and delete actions
2026-04-06 15:00:25 +02:00
e13f9584fa feat(20-02): wire FabMenu and CatalogSearchOverlay into root layout
- Replace old single-action FAB with FabMenu component
- Add CatalogSearchOverlay to root layout
- FAB now visible on all authenticated non-public routes
- Detect setups page for conditional New Setup menu item
- Remove unused openAddPanel reference
2026-04-06 08:04:10 +02:00
574a12e6fa fix: OIDC auth flow, Vite proxy, and PostgreSQL query compat
- Add auth redirect in root layout for unauthenticated users
- Proxy OIDC routes (/login, /callback, /logout) through Vite dev server
- Strip Secure flag from OIDC cookies in dev mode (HTTP localhost)
- Disable retry on auth query to prevent stale cookie loops
- Fix SQLite .get()/.all()/.run() calls in category and global-item
  services for PostgreSQL compatibility
- Add userId scoping to category service functions
- Add OIDC error logging in auth middleware
- Apply linter auto-formatting across affected files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:25:31 +02:00
b2936b098e Merge branch 'worktree-agent-af80e237' into Develop
# Conflicts:
#	.planning/REQUIREMENTS.md
#	.planning/STATE.md
2026-04-05 13:21:56 +02:00
a9956681ba feat(18-05): add public profile page and setup visibility toggle
- Create public profile page at /users/$userId with avatar, name, bio, setups
- Create PublicSetupCard component for profile page setup listing
- Add isPublic toggle button on setup detail page
- Add Public badge to SetupCard in list view
- Update useSetups hook with isPublic field on interfaces
2026-04-05 13:19:36 +02:00
f53f66d321 feat(18-04): add global item hooks, catalog browse page, and detail page
- useGlobalItems/useGlobalItem/useLinkItem/useUnlinkItem hooks
- Global catalog browse page with search, debounce, and skeleton loading
- Global item detail page with owner count badge
- GlobalItemCard component with brand, model, specs badges
2026-04-05 13:17:39 +02:00
f120d179f7 feat(18-05): add profile hooks and profile edit UI in settings
- Create usePublicProfile and useUpdateProfile hooks
- Create ProfileSection component with avatar upload, display name, bio
- Add Profile section to settings page (visible when authenticated)
2026-04-05 13:17:31 +02:00
8c64bf9fbf feat(17-03): update client components to use imageUrl from API responses
- Replace all /uploads/ path construction with imageUrl presigned URLs
- Add imageUrl prop to ItemCard, CandidateCard, CandidateListItem, ComparisonTable
- Update ImageUpload to use presigned URLs + local preview for new uploads
- Pass imageUrl through from parent components (CollectionView, forms, routes)
2026-04-05 12:27:34 +02:00
79b27b6bcc feat(15-03): rewrite login page and auth hooks for OIDC
- Login page redirects to Logto instead of showing credential form
- AuthState uses string id (Logto sub claim) instead of number
- Remove useLogin, useSetup, useChangePassword hooks
- useLogout redirects to /logout (server-side OIDC logout)
- Remove ChangePasswordSection from settings page
- Update UserMenu to use new useLogout API
- Settings page shows API keys section when authenticated
2026-04-04 20:52:58 +02:00
70e7cd2f0f fix: show Add Candidate button in comparison view
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:51:49 +02:00
f8a1a00e0a fix: prevent snap-back after drag and click-opens-edit during drag
Two fixes:
- Remove onSettled clearing tempItems before refetch completes,
  let useEffect clear it when fresh server data arrives
- Track isDragging ref to suppress edit panel click after drag
- Remove layout="position" which interfered with reorder detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:49:39 +02:00
684cfd3789 fix: stabilize drag-to-reorder with layout animation fixes
- Remove transition-all from list items (fights framer-motion layout)
- Add layout="position" to Reorder.Item for proper sibling tracking
- Replace CSS gap with marginBottom (gap confuses layout engine)
- Add explicit short transition duration for snappy reorder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:44:39 +02:00
52751ae9d4 fix: use onDragEnd on Reorder.Item instead of onPointerUp on Group
The previous approach used onPointerUp on the Reorder.Group which
fired unreliably — triggering on non-drag clicks and sometimes not
at all after a drag. Moving to onDragEnd on each Reorder.Item gives
clean, predictable drag-to-reorder behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:42:16 +02:00
3fc737c872 fix: add tab navigation to collection page and skip 404 retries
Adds Gear/Planning/Setups pill tabs to the collection page so users
can switch tabs without going back to the dashboard. Also skips
React Query retries on 404 responses for immediate error display.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:31:57 +02:00
15f146ee89 feat: add CSV import/export for gear collection
Some checks failed
CI / ci (pull_request) Failing after 22s
CI / e2e (pull_request) Has been skipped
Adds export (GET /api/items/export) and import (POST /api/items/import) routes
backed by a pure csv.service with no external deps, plus useExportItems/useImportItems
hooks and an Import/Export section in the Settings page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:12:07 +02:00
8c1fe47a99 feat: add setup impact preview UI with delta badges across all views
Adds SetupImpactSelector dropdown and ImpactDeltaBadge inline badge, wired into the thread detail page. Delta badges appear on CandidateListItem, CandidateCard, and ComparisonTable (Weight Impact / Price Impact rows) whenever a setup is selected for comparison.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:11:57 +02:00
1a5e6a303e feat: add quantity support to totals, UI, and thread resolution
- totals.service: multiply weight/cost sums by quantity in category and global totals
- setup.service: multiply by quantity in getAllSetups SQL subqueries; expose quantity in getSetupWithItems item list
- thread.service: explicitly pass quantity: 1 when inserting resolved item
- ItemForm: add Quantity number input (min=1, default=1) after price field
- ItemCard: show ×N badge next to item name when quantity > 1
- CollectionView: pass quantity prop to ItemCard in both filtered and grouped views
- $setupId.tsx: pass quantity to ItemCard; multiply by quantity in client-side per-setup totals
- WeightSummaryCard: multiply by quantity in all chart and legend weight calculations
- useItems / useSetups: add quantity to ItemWithCategory / SetupItemWithCategory interfaces

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:04:27 +02:00
e9d33e59e9 refactor: add useFormatters hook to reduce boilerplate across 14 components
Created useFormatters() combining useWeightUnit + useCurrency + formatWeight/formatPrice
into a single hook returning weight(grams) and price(cents) bound functions plus
raw unit and currency values. Updated all 14 consumer files to use the new hook,
removing the repeated 4-import + 2-hook-call pattern from each.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:49:16 +02:00
a3061b22ca refactor: extract tab views from collection route into separate components
Moves CollectionView, PlanningView, and SetupsView out of the 634-line collection/index.tsx into dedicated component files. Pure extraction — zero logic changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 15:37:44 +02:00
1dff6abb3b feat: add error boundary to root route for crash resilience
Adds a TanStack Router error boundary to the root route so rendering errors or uncaught React Query failures show a friendly error page instead of white-screening the app. The error boundary displays a professional error message with a "Try again" button that resets state and invalidates router data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:36:11 +02:00
9191f0fe24 fix: resolve all lint errors — exclude generated dirs, auto-fix source
Some checks failed
CI / ci (push) Failing after 20s
Exclude drizzle/ and .planning/ from Biome (generated files with
incompatible formatting). Auto-fix import ordering and formatting
in existing source files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:05:10 +02:00
4148833644 fix: only show onboarding wizard after account setup
The wizard creates categories via POST which requires auth.
Gate the wizard on isAuthenticated so users create their
account first via Sign In, then the wizard appears.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:49:44 +02:00
5bb728e545 feat: add password change and API key management to settings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:30:50 +02:00
511fece4c7 feat: add login button to header and conditional edit UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:29:01 +02:00
87a367d41b feat: add useAuth hook and login page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 13:27:23 +02:00
5b4026d36f feat(12-01): wire compare toggle and ComparisonTable into thread detail
- Extend uiStore candidateViewMode union to include "compare" value
- Add columns-3 compare toggle button, shown only when thread has 2+ candidates
- Hide "Add Candidate" button when in compare view (read-only intent)
- Import and render ComparisonTable when candidateViewMode === "compare"
- Pass displayItems so compare view reflects any pending reorder state
- Existing list/grid views unchanged; all 135 tests pass
2026-03-17 15:30:38 +01:00
7e06c8526b fix(11): wire handleDragEnd to Reorder.Group for active threads
onPointerUp was incorrectly placed on the resolved-thread div instead
of the active-thread Reorder.Group, causing drag reorder to not persist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 22:36:40 +01:00
94c07e79c2 feat(11-02): add view toggle, Reorder.Group drag-to-reorder, and rank badges in grid view
- Thread detail page: list/grid view toggle with LayoutList/LayoutGrid icons
- List view (active threads): Reorder.Group with CandidateListItem for drag-to-reorder
- List view (resolved threads): static CandidateListItem with rank badges, no drag handles
- Grid view: CandidateCard components with rank badges (gold/silver/bronze)
- tempItems pattern prevents React Query flicker during drag
- handleDragEnd fires PATCH /candidates/reorder after drag completes
- View toggle defaults to list view via uiStore candidateViewMode
2026-03-16 22:28:53 +01:00
4f2aefe7a4 feat(10-01): wire pros/cons through client hooks, form, and card indicator
- CandidateResponse: add pros/cons string|null fields
- CandidateForm: add pros/cons to FormData, INITIAL_FORM, pre-fill, payload
- CandidateForm: add Pros/Cons textarea inputs (after Notes, before Product Link)
- CandidateCard: add pros/cons props, render purple +/- Notes badge when present
- Thread detail route: pass pros/cons props to CandidateCard
2026-03-16 21:36:10 +01:00
9647f5759d feat: redesign weight summary legend and add currency selector
Redesign WeightSummaryCard stats from a disconnected 4-column grid to a
compact legend-style list with color dots, percentages, and a divider
before the total row. Switch chart and legend colors to a neutral gray
palette.

Add a currency selector to settings (USD, EUR, GBP, JPY, CAD, AUD) that
changes the displayed symbol across the app. This is visual only — no
value conversion is performed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:33:07 +01:00
d098277797 feat(09-02): add WeightSummaryCard with donut chart and classification subtotals
- Install recharts dependency for donut chart visualization
- Create WeightSummaryCard component with pill toggle (category/classification views)
- Compute base/worn/consumable/total weight subtotals from items array
- Render donut chart with colored segments, center total, and hover tooltips
- Wire WeightSummaryCard into setup detail page below sticky bar
2026-03-16 15:20:41 +01:00
fb738d7cc2 feat(09-01): add classification API route, client hook, badge component, and setup detail wiring
- Add PATCH /:id/items/:itemId/classification endpoint with Zod validation
- Add apiPatch helper to client API library
- Add useUpdateItemClassification mutation hook
- Add classification field to SetupItemWithCategory interface
- Create ClassificationBadge click-to-cycle component (base/worn/consumable)
- Wire ClassificationBadge into setup detail page item grid
- Add integration tests for PATCH classification route (valid + invalid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 15:13:08 +01:00
25956ed3ee feat(08-01): create StatusBadge component and wire into CandidateCard
- StatusBadge: clickable pill badge with popup menu (researching/ordered/arrived)
- Muted gray styling, LucideIcon per status, click-outside dismiss, Escape key support
- CandidateCard: status + onStatusChange props, StatusBadge in pill row after category
- Thread detail page: passes candidate.status and useUpdateCandidate for onStatusChange
- Fix Biome formatting for candidateStatusSchema enum

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:12:02 +01:00
5f89acd503 feat(08-02): add search/filter toolbar to gear tab and upgrade planning filter
- Sticky search/filter toolbar with text input and CategoryFilterDropdown
- useMemo-based filtering by name (search) and categoryId (dropdown)
- "Showing X of Y items" count when filters active
- Flat grid (no category headers) when any filter is active
- "No items match your search" empty state for filtered results
- Replace PlanningView native select with CategoryFilterDropdown
2026-03-16 14:09:51 +01:00
faa437896f feat(07-02): add weight unit toggle and wire all formatWeight call sites
- Add segmented g/oz/lb/kg toggle to TotalsBar with settings persistence
- Pass unit parameter to all 8 formatWeight call sites across components and routes
- Import useWeightUnit hook in ItemCard, CandidateCard, CategoryHeader, SetupCard, ItemPicker, Dashboard, SetupDetail

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 12:23:19 +01:00
94ebd84cc7 refactor: move setups list into collection page as third tab
All checks were successful
CI / ci (push) Successful in 13s
Setups now lives alongside My Gear and Planning under /collection?tab=setups
instead of its own /setups route. Dashboard card updated to link to the new
tab. Setup detail pages (/setups/:id) remain unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 00:07:48 +01:00