Add reference size fields to product admin editor

- Add referenceWidthCm and referenceHeightCm to ProductDTO
- Update toProductDTO to include reference size fields
- Add reference size inputs to admin product edit page
- Update updateProduct action to handle reference sizes
- Rulers on personalization page use product reference size

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-18 12:26:16 +01:00
co-authored by Claude Haiku 4.5
parent 740d2bbd29
commit 0e14fc7981
4 changed files with 47 additions and 0 deletions
+35
View File
@@ -285,6 +285,41 @@ export default async function EditProductPage({ params }: { params: { id: string
</label> </label>
</div> </div>
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="referenceWidthCm" className="tag-label mb-2 block">
Reference width (cm)
</label>
<input
id="referenceWidthCm"
name="referenceWidthCm"
type="number"
step="0.1"
min="0"
placeholder="e.g. 40"
defaultValue={product.referenceWidthCm ?? ''}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
<p className="mt-1 text-xs text-muted">Width of garment/object for ruler reference (optional)</p>
</div>
<div>
<label htmlFor="referenceHeightCm" className="tag-label mb-2 block">
Reference height (cm)
</label>
<input
id="referenceHeightCm"
name="referenceHeightCm"
type="number"
step="0.1"
min="0"
placeholder="e.g. 60"
defaultValue={product.referenceHeightCm ?? ''}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
<p className="mt-1 text-xs text-muted">Height of garment/object for ruler reference (optional)</p>
</div>
</div>
<div> <div>
<label className="tag-label mb-2 block">Colors</label> <label className="tag-label mb-2 block">Colors</label>
<ColorPicker <ColorPicker
+8
View File
@@ -168,6 +168,10 @@ export async function updateProduct(formData: FormData) {
const showOnPersonalised = String(formData.get('showOnPersonalised') ?? '') === '1'; const showOnPersonalised = String(formData.get('showOnPersonalised') ?? '') === '1';
const showOnProducts = String(formData.get('showOnProducts') ?? '') === '1'; const showOnProducts = String(formData.get('showOnProducts') ?? '') === '1';
const collectionIds = formData.getAll('collections').map((v) => String(v)); const collectionIds = formData.getAll('collections').map((v) => String(v));
const referenceWidthCmInput = String(formData.get('referenceWidthCm') ?? '').trim();
const referenceHeightCmInput = String(formData.get('referenceHeightCm') ?? '').trim();
const referenceWidthCm = referenceWidthCmInput ? Number(referenceWidthCmInput) : null;
const referenceHeightCm = referenceHeightCmInput ? Number(referenceHeightCmInput) : null;
if (!id) throw new Error('Missing product id.'); if (!id) throw new Error('Missing product id.');
if (!name || !category || !priceDollars) { if (!name || !category || !priceDollars) {
@@ -228,6 +232,8 @@ export async function updateProduct(formData: FormData) {
photoRecolorable: boolean; photoRecolorable: boolean;
showOnPersonalised: boolean; showOnPersonalised: boolean;
showOnProducts: boolean; showOnProducts: boolean;
referenceWidthCm: number | null;
referenceHeightCm: number | null;
imageUrl?: string; imageUrl?: string;
imageUrlBack?: string; imageUrlBack?: string;
printArea?: string; printArea?: string;
@@ -247,6 +253,8 @@ export async function updateProduct(formData: FormData) {
photoRecolorable, photoRecolorable,
showOnPersonalised, showOnPersonalised,
showOnProducts, showOnProducts,
referenceWidthCm,
referenceHeightCm,
}; };
// Only touch the front photo/print area if a new photo was actually uploaded — // Only touch the front photo/print area if a new photo was actually uploaded —
+2
View File
@@ -21,6 +21,8 @@ export function toProductDTO(p: PrismaProduct, activePromotions: ActivePromotion
printAreaBack: p.printAreaBack ? JSON.parse(p.printAreaBack) : null, printAreaBack: p.printAreaBack ? JSON.parse(p.printAreaBack) : null,
printAreaWidthMm: p.printAreaWidthMm, printAreaWidthMm: p.printAreaWidthMm,
printAreaHeightMm: p.printAreaHeightMm, printAreaHeightMm: p.printAreaHeightMm,
referenceWidthCm: p.referenceWidthCm,
referenceHeightCm: p.referenceHeightCm,
imageUrl: p.imageUrl, imageUrl: p.imageUrl,
imageUrlBack: p.imageUrlBack, imageUrlBack: p.imageUrlBack,
photoRecolorable: p.photoRecolorable, photoRecolorable: p.photoRecolorable,
+2
View File
@@ -45,6 +45,8 @@ export type ProductDTO = {
printAreaBack: PrintArea | null; printAreaBack: PrintArea | null;
printAreaWidthMm: number; printAreaWidthMm: number;
printAreaHeightMm: number; printAreaHeightMm: number;
referenceWidthCm: number | null;
referenceHeightCm: number | null;
imageUrl: string | null; imageUrl: string | null;
imageUrlBack: string | null; imageUrlBack: string | null;
photoRecolorable: boolean; photoRecolorable: boolean;