Removed the rotation/zoom adjustment modal feature. Approach was too complex and
time-consuming without delivering stable results.
New simplified flow:
1. User extracts item with AI
2. Item saved with original image (resized/compressed by backend)
3. No rotation adjustments in frontend
4. Image editing can be implemented as a future feature
This unblocks the workflow and gets users to a working state.
Backend still applies compression/resizing, just no rotation processing.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Root cause: Image was being rotated TWICE:
1. Frontend rotated it in the modal and sent processed blob
2. Backend rotated it AGAIN based on rotation_degrees
This double rotation made the image appear unrotated or distorted.
Solution: Remove frontend image processing entirely.
- Modal now sends ONLY the rotation value
- No imageBlob from modal (uses original)
- Backend receives original image + rotation value
- Backend applies rotation ONCE
Now image is rotated correctly by backend without duplication.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Root cause found: setState is async, so hookConfirmSingleItem was called
before extractedItems updated, causing it to use OLD image_processing values.
Fixed by:
1. Building the final newItem directly in handleImageAdjustmentConfirm
2. Using the UPDATED image_processing values (with user adjustments)
3. Calling onComplete synchronously with correct values
4. Not relying on async setState ordering
This ensures backend receives the user-adjusted crop_bounds and rotation_degrees,
not the original AI-detected values.
Backend logs will now show user adjustments, not original AI values.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added detailed console logging across entire image adjustment pipeline:
1. ImageAdjustmentModal.handleConfirm():
- Original image dimensions
- User inputs (rotation, zoom, pan, crop)
- Canvas processing steps
- Final blob size
2. AIOnboarding.handleImageAdjustmentConfirm():
- Adjustments received from modal
- Item being updated
- extractedImageBlob status before/after
3. useAIExtraction.confirmSingleItem():
- newItem being built
- extractedImageBlob attached
- imageProcessing attached
This will help identify where values are lost or incorrect in the flow.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Critical fix: modal processes image and returns blob, but AIOnboarding
was not actually using that blob. Now properly calls setExtractedImageBlob()
so confirmSingleItem sends the processed image to backend.
Before: Backend received original image, applied original AI crop/rotation
After: Backend receives processed image (already cropped/rotated by user)
Now the saved image matches exactly what user sees after adjusting.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Critical fixes:
1. Modal now applies rotation and crop to image, returns processed blob
2. Frontend sends processed image to backend (not original)
3. Zoom slider min/max now calculated based on image size
4. Initial zoom shows entire image in canvas
5. Zoom constraints prevent over-zooming or under-zooming
User experience improved:
- Sees full item at start (auto-fit zoom)
- Can adjust rotation/crop smoothly
- Adjusted image is what gets saved (not original)
- Zoom slider works correctly for any image size
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Fixed two critical issues:
1. Adjustments now properly override image_processing values
2. State updates explicitly ensure extractedItems are modified before confirm
Changes:
- handleImageAdjustmentConfirm now updates extractedItems state
- Adjustments properly stored in image_processing (rotation_degrees, crop_bounds)
- user_adjusted flag added to mark user-modified values
- Backend will use adjusted values instead of AI detection
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added user-controlled image adjustment modal that displays after item
confirmation, allowing users to adjust rotation/crop before final save.
Changes:
- AIOnboarding: wrapper confirmSingleItem to show modal post-selection
- State: showImageAdjustment, adjustingItemIndex, pendingItemData
- Handlers: confirm/cancel for applying or discarding adjustments
- Flow: item save → modal display → adjustments applied → DB commit
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Update photo save checkbox to match app design (border-slate-600, htmlFor label)
- Remove success popup overlay - modal closes immediately after save
- Simplify confirmSingleItem to remove setTimeout logic
- Toast notification used for user feedback instead
- Add savingIndex state to track saving operation
- Display success overlay with saved image for 1.5 seconds
- Show item name in confirmation message
- Prevents modal from closing immediately after save
Fixes user complaint about image disappearing too quickly without confirmation
- Add rotation_degrees parameter to ImageProcessor.process_photo()
- Pass rotation through _auto_save_photo_from_extraction() to processor
- Allow no-crop fallback when crop_bounds is None
- Add buildPhotoUrl() helper to resolve backend URLs correctly
- Update frontend components to use backend URL for image sources
- Replace Use/Skip Photo buttons with checkbox in AI extraction UI
- Add images/ to .gitignore to prevent accidental commits
Addresses: rotation never applied, image 404s (relative to Next.js not backend), preview blank in edit form
Users now see the extracted photo during item editing and can choose to:
- 'Use Photo': Auto-save the image with the item
- 'Skip Photo': Create item without saving the photo
Changes:
1. frontend/components/AIOnboarding.tsx: Added image preview panel in edit form
- Shows extracted image to user
- Buttons to accept/reject photo
- Visual feedback when photo is skipped
2. frontend/hooks/useAIExtraction.ts: Updated confirmSingleItem and confirmAllItems
- Respect user's photo decision (_skipPhoto flag)
- Only pass extractedImageBlob if user approved it
- Prevents unwanted auto-photo-save
This gives users full control over which extracted photos are auto-saved.
Replace font-bold, font-black, and font-semibold with font-normal throughout:
- 26 component files
- 1 CSS utility file (globals.css)
- 291 total occurrences
Text hierarchy now maintained through font-size differences only.
All tests passing (291/291).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Upgraded color palette with enhanced contrast (5.2:1 to 15:1 ratios)
- Replaced all text-slate-* utilities with semantic color tokens
- Added Fira Code + Fira Sans typography stack
- Converted CSS variables from SCSS to direct hex values
- Updated 26 components with improved color semantics
- Added cursor-pointer and focus states (accessibility phase 1)
- Added aria-labels to 35+ icon-only buttons
- Added prefers-reduced-motion support in globals.css
WCAG AA compliance verified across all text color combinations.
Fixes invisible text issues (slate-500 4.2:1 → muted 5.2:1).
- Add cursor-pointer to all clickable buttons and interactive elements
- Add focus:ring-2 focus:ring-primary/blue focus:outline-none to all buttons
- Add aria-label to icon-only buttons and actions
- Update focus states from focus-visible to focus for consistency
- Add disabled:cursor-not-allowed for disabled button states
- Improve keyboard navigation with proper focus indicators
Components updated:
- BottomNav: navigation buttons with aria-labels
- Scanner: try again, zoom, word selection, cancel buttons
- ItemComparisonModal: skip and update action buttons
- ConfirmationModal: close, cancel, delete buttons with input focus
- AIOnboarding: all mode toggles, camera, upload, capture, edit, delete buttons
- Plus interactive cards and list items
This ensures WCAG AA compliance for keyboard navigation and visual feedback.
- Fix null type error in AIOnboarding.tsx line 352: img src attribute
- Fix similar issue in Scanner.tsx line 237: capturedImage null handling
- Use '|| undefined' pattern to satisfy React 19/Next.js 15 type requirements
- Both components now properly handle null/undefined image states