From 3631f59bba6de1769b87e817962382cbbc801c37 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 2 Oct 2026 09:05:58 +0700 Subject: [PATCH] x --- apps/admin/src/pages/ProductEditPage.tsx | 93 +++- .../migration.sql | 5 + apps/backend/prisma/schema.prisma | 2 + apps/backend/src/routes/products.ts | 5 + .../src/components/AddToCartSection.tsx | 448 +++++++++++++++--- .../components/ProductStickyPurchaseBar.tsx | 26 +- packages/types/index.ts | 2 + 7 files changed, 524 insertions(+), 57 deletions(-) create mode 100644 apps/backend/prisma/migrations/20261002012741_add_product_title_graphic_and_variant_image/migration.sql diff --git a/apps/admin/src/pages/ProductEditPage.tsx b/apps/admin/src/pages/ProductEditPage.tsx index d11d6fe..4ff32c0 100644 --- a/apps/admin/src/pages/ProductEditPage.tsx +++ b/apps/admin/src/pages/ProductEditPage.tsx @@ -127,6 +127,7 @@ export default function ProductEditPage() { const [options, setOptions] = useState<{name: Record, values: Record[]}[]>([]) const [variants, setVariants] = useState[]>([]) const [images, setImages] = useState([]) + const [titleGraphicUrl, setTitleGraphicUrl] = useState('') const [availableAttributes, setAvailableAttributes] = useState([]) const [attributes, setAttributes] = useState([]) const [selectedDefinitionId, setSelectedDefinitionId] = useState(0) @@ -211,6 +212,7 @@ export default function ProductEditPage() { setOptions(parseOptions(prodData.options)) setVariants(prodData.variants || []) setImages(prodData.images || []) + setTitleGraphicUrl(prodData.titleGraphicUrl || '') setAttributes((prodData.attributes || []).map(parseEditableAttribute)) await fetchAttributeDefinitions(prodData.categoryId) } else { @@ -219,6 +221,7 @@ export default function ProductEditPage() { setName({ th: '', en: '' }) setDescription({ th: '', en: '' }) setDetails({ th: '', en: '' }) + setTitleGraphicUrl('') setOptions([]) setVariants([]) setImages([]) @@ -384,6 +387,7 @@ export default function ProductEditPage() { body: JSON.stringify({ categoryId, name, + titleGraphicUrl: titleGraphicUrl.trim() || null, description, details, options, @@ -395,7 +399,8 @@ export default function ProductEditPage() { price: Number(v.price) || 0, stock: Number(v.stock) || 0, sku: v.sku || '', - barcode: v.barcode || '' + barcode: v.barcode || '', + imageUrl: v.imageUrl || null, })), images: images.filter(img => img.url).map((img, idx) => ({ ...(img.id ? { id: img.id } : {}), @@ -550,6 +555,57 @@ export default function ProductEditPage() { +
+
+
+ + +
+ {titleGraphicUrl && ( + + )} +
+ + {titleGraphicUrl ? ( +
+
+ Title graphic preview +
+ +
+ ) : ( + + )} +

+ Optional. Displays as a branded logo banner above the product title on the website. +

+
+