Fix: Preserve print area when editing products

PhotoPrintAreaField now accepts and loads existing print area coordinates
when editing products. Previously, the component always initialized to
DEFAULT_BOX, causing the saved print area to be lost when editing.

Changes:
- Export Box type from PhotoPrintAreaField
- Add existingPrintArea prop to PhotoPrintAreaField
- Initialize box state with existing print area if provided
- Convert print area from database format (0-1 decimals) to component format (0-100 percentages)
- Update edit page to parse and pass existing print area values

Result: Print area masks now persist when editing products and adding them
to different catalogs (ready-made, plain, etc).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-20 20:35:24 +01:00
co-authored by Claude Haiku 4.5
parent 9ce0930a54
commit c81f434a0b
2 changed files with 23 additions and 5 deletions
+19 -3
View File
@@ -6,7 +6,7 @@ import { updateProduct } from '../../actions';
import AdminNav from '@/components/AdminNav';
import ColorPicker from '@/components/ColorPicker';
import SizePicker from '@/components/SizePicker';
import PhotoPrintAreaField from '@/components/PhotoPrintAreaField';
import PhotoPrintAreaField, { type Box } from '@/components/PhotoPrintAreaField';
import { MOCKUP_OPTIONS } from '@/lib/mockupDefaults';
export default async function EditProductPage({ params }: { params: { id: string } }) {
@@ -21,6 +21,22 @@ export default async function EditProductPage({ params }: { params: { id: string
const recipients = collections.filter((c) => c.group === 'RECIPIENT');
const selectedCollectionIds = new Set(row.collections.map((c) => c.id));
// Parse print areas from database (stored as 0-1 decimals, component expects 0-100 percentages)
const printAreaData = row.printArea ? JSON.parse(row.printArea) : null;
const printAreaBack = row.printAreaBack ? JSON.parse(row.printAreaBack) : null;
const existingPrintArea = printAreaData ? {
xPct: printAreaData.xPct * 100,
yPct: printAreaData.yPct * 100,
wPct: printAreaData.wPct * 100,
hPct: printAreaData.hPct * 100,
} : undefined;
const existingPrintAreaBack = printAreaBack ? {
xPct: printAreaBack.xPct * 100,
yPct: printAreaBack.yPct * 100,
wPct: printAreaBack.wPct * 100,
hPct: printAreaBack.hPct * 100,
} : undefined;
return (
<div className="mx-auto max-w-2xl px-6 py-12">
<AdminNav />
@@ -286,12 +302,12 @@ export default async function EditProductPage({ params }: { params: { id: string
<div>
<label className="tag-label mb-2 block">Front photo</label>
<PhotoPrintAreaField existingImageUrl={product.imageUrl} />
<PhotoPrintAreaField existingImageUrl={product.imageUrl} existingPrintArea={existingPrintArea} />
</div>
<div>
<label className="tag-label mb-2 block">Back photo</label>
<PhotoPrintAreaField variant="back" existingImageUrl={product.imageUrlBack} />
<PhotoPrintAreaField variant="back" existingImageUrl={product.imageUrlBack} existingPrintArea={existingPrintAreaBack} />
</div>
<div>
+4 -2
View File
@@ -2,7 +2,7 @@
import { useRef, useState } from 'react';
type Box = { xPct: number; yPct: number; wPct: number; hPct: number }; // 0-100
export type Box = { xPct: number; yPct: number; wPct: number; hPct: number }; // 0-100
const DEFAULT_BOX: Box = { xPct: 30, yPct: 25, wPct: 40, hPct: 35 };
const MIN_SIZE = 6; // percent
@@ -10,12 +10,14 @@ const MIN_SIZE = 6; // percent
export default function PhotoPrintAreaField({
variant = 'front',
existingImageUrl,
existingPrintArea,
}: {
variant?: 'front' | 'back';
existingImageUrl?: string;
existingPrintArea?: Box;
}) {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [box, setBox] = useState<Box>(DEFAULT_BOX);
const [box, setBox] = useState<Box>(existingPrintArea || DEFAULT_BOX);
const [showPrintAreaEditor, setShowPrintAreaEditor] = useState(false);
const [isRemoved, setIsRemoved] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);