3.5 KiB
status, trigger, created, updated
| status | trigger | created | updated |
|---|---|---|---|
| diagnosed | crop editor opens on upload correctly, but after cropping the cropped image isn't shown in the edit state always — after clicking save it is shown correctly | 2026-04-13T12:30:00Z | 2026-04-13T12:35:00Z |
Current Focus
hypothesis: GearImage in ImageUpload receives no crop props after cropping — crop values are sent to server via onCropChange but never stored locally or passed to the preview GearImage test: trace data flow from ImageCropEditor.onSave through ImageUpload to GearImage rendering expecting: GearImage in ImageUpload has no cropZoom/cropX/cropY props next_action: return diagnosis
Symptoms
expected: After cropping in the crop editor, the image preview in edit mode should immediately reflect the crop actual: Cropped image not shown in edit state after cropping; shows correctly only after Save errors: None reproduction: Upload image to item -> crop editor opens -> adjust crop -> close editor -> preview shows uncropped image -> Save item -> page re-renders with crop applied started: Since Phase 29 implementation
Eliminated
(none needed — root cause found on first hypothesis)
Evidence
-
timestamp: 2026-04-13T12:32:00Z checked: ImageUpload.tsx lines 83-95 — ImageCropEditor onSave handler found: onSave calls onCropChange(result) then setShowCropEditor(false). The crop values are passed up to the parent but NOT stored in any local state within ImageUpload. implication: After crop editor closes, ImageUpload has no memory of what crop was applied.
-
timestamp: 2026-04-13T12:33:00Z checked: ImageUpload.tsx lines 109-114 — GearImage rendering after crop editor closes found: GearImage is rendered with only src, alt, and dominantColor props. NO cropZoom, cropX, or cropY props are passed. The component never receives crop values. implication: GearImage renders uncropped because it literally has no crop data to apply.
-
timestamp: 2026-04-13T12:34:00Z checked: $itemId.tsx lines 277-294 — onCropChange callback in item detail page found: onCropChange triggers updateItem.mutate() which sends crop values to the server immediately. This is a fire-and-forget mutation — it does NOT update local state or the React Query cache synchronously. implication: Crop values reach the server, but the local component tree has no access to them until the query is invalidated/refetched.
-
timestamp: 2026-04-13T12:34:30Z checked: $itemId.tsx lines 326-335 — GearImage in non-edit view mode found: Non-edit view reads cropZoom, cropX, cropY from item (React Query cache data). After Save, the mutation invalidates the query, item refetches with crop values, and GearImage renders correctly. implication: Confirms the "works after save" behavior — the query refetch provides the crop data.
Resolution
root_cause: ImageUpload component does not track crop values locally after the crop editor closes. When the crop editor's onSave fires, the crop values are forwarded to the parent ($itemId.tsx) which sends them to the server via updateItem.mutate(), but no local state is updated. The GearImage rendered inside ImageUpload receives zero crop-related props (cropZoom, cropX, cropY are never passed). So the preview always shows the uncropped/default image. After the user clicks Save on the item form, the React Query cache is invalidated, the item refetches with server-side crop values, and the page re-renders in view mode with the correct crop applied.
fix: (not applied — diagnosis only) verification: (not applied — diagnosis only) files_changed: []