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:
co-authored by
Claude Haiku 4.5
parent
9ce0930a54
commit
c81f434a0b
@@ -6,7 +6,7 @@ import { updateProduct } from '../../actions';
|
|||||||
import AdminNav from '@/components/AdminNav';
|
import AdminNav from '@/components/AdminNav';
|
||||||
import ColorPicker from '@/components/ColorPicker';
|
import ColorPicker from '@/components/ColorPicker';
|
||||||
import SizePicker from '@/components/SizePicker';
|
import SizePicker from '@/components/SizePicker';
|
||||||
import PhotoPrintAreaField from '@/components/PhotoPrintAreaField';
|
import PhotoPrintAreaField, { type Box } from '@/components/PhotoPrintAreaField';
|
||||||
import { MOCKUP_OPTIONS } from '@/lib/mockupDefaults';
|
import { MOCKUP_OPTIONS } from '@/lib/mockupDefaults';
|
||||||
|
|
||||||
export default async function EditProductPage({ params }: { params: { id: string } }) {
|
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 recipients = collections.filter((c) => c.group === 'RECIPIENT');
|
||||||
const selectedCollectionIds = new Set(row.collections.map((c) => c.id));
|
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 (
|
return (
|
||||||
<div className="mx-auto max-w-2xl px-6 py-12">
|
<div className="mx-auto max-w-2xl px-6 py-12">
|
||||||
<AdminNav />
|
<AdminNav />
|
||||||
@@ -286,12 +302,12 @@ export default async function EditProductPage({ params }: { params: { id: string
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="tag-label mb-2 block">Front photo</label>
|
<label className="tag-label mb-2 block">Front photo</label>
|
||||||
<PhotoPrintAreaField existingImageUrl={product.imageUrl} />
|
<PhotoPrintAreaField existingImageUrl={product.imageUrl} existingPrintArea={existingPrintArea} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="tag-label mb-2 block">Back photo</label>
|
<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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useRef, useState } from 'react';
|
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 DEFAULT_BOX: Box = { xPct: 30, yPct: 25, wPct: 40, hPct: 35 };
|
||||||
const MIN_SIZE = 6; // percent
|
const MIN_SIZE = 6; // percent
|
||||||
@@ -10,12 +10,14 @@ const MIN_SIZE = 6; // percent
|
|||||||
export default function PhotoPrintAreaField({
|
export default function PhotoPrintAreaField({
|
||||||
variant = 'front',
|
variant = 'front',
|
||||||
existingImageUrl,
|
existingImageUrl,
|
||||||
|
existingPrintArea,
|
||||||
}: {
|
}: {
|
||||||
variant?: 'front' | 'back';
|
variant?: 'front' | 'back';
|
||||||
existingImageUrl?: string;
|
existingImageUrl?: string;
|
||||||
|
existingPrintArea?: Box;
|
||||||
}) {
|
}) {
|
||||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
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 [showPrintAreaEditor, setShowPrintAreaEditor] = useState(false);
|
||||||
const [isRemoved, setIsRemoved] = useState(false);
|
const [isRemoved, setIsRemoved] = useState(false);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user