From 285a8ab21f9191bc2f4d71e15ff3bb61f02bb0b0 Mon Sep 17 00:00:00 2001 From: Andymick Date: Sun, 19 Jul 2026 12:01:27 +0100 Subject: [PATCH] Fix: Handle image removal in product editor - Add support for removeImage/removeImageBack flags in updateProduct action - When Remove button is clicked, client sets isRemoved=true to hide UI - Server action checks removeImage/removeImageBack form fields and sets imageUrl/imageUrlBack to null - Also reset printArea to default when image is removed - Tested: Remove button now successfully clears images and persists changes to database --- .claude/settings.local.json | 10 +++++++++- src/app/admin/products/actions.ts | 16 ++++++++++++---- src/components/PhotoPrintAreaField.tsx | 8 +++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index e239836..cce4e2b 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -94,7 +94,15 @@ "mcp__visualize__show_widget", "Bash(git branch *)", "Bash(git remote *)", - "Bash(git commit -m 'Fix: Remove duplicate success variable in admin orders page *)" + "Bash(git commit -m 'Fix: Remove duplicate success variable in admin orders page *)", + "Bash(git commit -m 'UX: Reorder admin menu to highlight Design Approvals and Shipping rates *)", + "Bash(git commit -m 'Fix: Add Design Approvals and Shipping rates to admin dropdown menu *)", + "Bash(git log *)", + "Bash(git commit -m 'Fix: Set Classic Tee photoRecolorable to false for proper image display *)", + "Bash(git commit -m 'Fix: Remove encType from product edit form with Server Action *)", + "Bash(git commit -m 'Feature: Add file removal and print area edit toggles to photo upload *)", + "Bash(git commit -m 'Fix: Show Remove and Modify print area buttons for existing images *)", + "Bash(git commit -m 'Fix: Handle image removal in product editor *)" ] } } diff --git a/src/app/admin/products/actions.ts b/src/app/admin/products/actions.ts index adb0cb2..6396e79 100644 --- a/src/app/admin/products/actions.ts +++ b/src/app/admin/products/actions.ts @@ -268,9 +268,12 @@ export async function updateProduct(formData: FormData) { weightGrams, }; - // Only touch the front photo/print area if a new photo was actually uploaded — - // otherwise leave whatever's already there alone. - if (imageFile && imageFile.size > 0) { + // Handle front photo: new upload, removal, or keep existing + const removeImage = String(formData.get('removeImage') ?? '') === '1'; + if (removeImage) { + data.imageUrl = null; + data.printArea = JSON.stringify(DEFAULT_PRINT_AREAS[mockup] ?? DEFAULT_PRINT_AREAS.tshirt); + } else if (imageFile && imageFile.size > 0) { data.imageUrl = await fileToDataUrl(imageFile); const hasCustomPrintArea = String(formData.get('hasCustomPrintArea') ?? '') === '1'; @@ -286,7 +289,12 @@ export async function updateProduct(formData: FormData) { ); } - if (imageBackFile && imageBackFile.size > 0) { + // Handle back photo: new upload, removal, or keep existing + const removeImageBack = String(formData.get('removeImageBack') ?? '') === '1'; + if (removeImageBack) { + data.imageUrlBack = null; + data.printAreaBack = null; + } else if (imageBackFile && imageBackFile.size > 0) { data.imageUrlBack = await fileToDataUrl(imageBackFile); const hasCustomPrintAreaBack = String(formData.get('hasCustomPrintAreaBack') ?? '') === '1'; diff --git a/src/components/PhotoPrintAreaField.tsx b/src/components/PhotoPrintAreaField.tsx index b355eae..7d076a1 100644 --- a/src/components/PhotoPrintAreaField.tsx +++ b/src/components/PhotoPrintAreaField.tsx @@ -17,6 +17,7 @@ export default function PhotoPrintAreaField({ const [previewUrl, setPreviewUrl] = useState(null); const [box, setBox] = useState(DEFAULT_BOX); const [showPrintAreaEditor, setShowPrintAreaEditor] = useState(false); + const [isRemoved, setIsRemoved] = useState(false); const containerRef = useRef(null); const fileInputRef = useRef(null); const dragState = useRef<{ @@ -28,22 +29,26 @@ export default function PhotoPrintAreaField({ const fieldName = variant === 'front' ? 'image' : 'imageBack'; const suffix = variant === 'front' ? '' : 'Back'; + const removeFieldName = variant === 'front' ? 'removeImage' : 'removeImageBack'; const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) { setPreviewUrl(null); setShowPrintAreaEditor(false); + setIsRemoved(false); return; } setPreviewUrl(URL.createObjectURL(file)); setBox(DEFAULT_BOX); setShowPrintAreaEditor(true); + setIsRemoved(false); }; const handleClearFile = () => { setPreviewUrl(null); setShowPrintAreaEditor(false); + setIsRemoved(true); if (fileInputRef.current) { fileInputRef.current.value = ''; } @@ -53,7 +58,7 @@ export default function PhotoPrintAreaField({ setShowPrintAreaEditor(false); }; - const currentImageUrl = previewUrl || existingImageUrl; + const currentImageUrl = previewUrl || (isRemoved ? null : existingImageUrl); const onBoxMouseDown = (e: React.MouseEvent) => { e.preventDefault(); @@ -192,6 +197,7 @@ export default function PhotoPrintAreaField({ )} +