feat: auto-fill mockup dimensions and family from Google Sheets
- Extend Sheets read range from A1:Z to A1:AZ (52 columns) - Parse longueur, largeur, marque, famille, sousFamille, prixRemise, specificFields - Add /api/products/sheet-info endpoint to fetch product data by ref - Auto-fill family and dimensions on product selection in all 3 mockup entry points - Strengthen carrelage mockup prompt with strict tile-size consistency rules Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,9 @@ interface Product {
|
||||
shopifyId: string
|
||||
title: string
|
||||
ref: string
|
||||
famille?: string
|
||||
longueur?: string
|
||||
largeur?: string
|
||||
}
|
||||
|
||||
export default function MockupPage() {
|
||||
@@ -91,7 +94,20 @@ export default function MockupPage() {
|
||||
<div className="absolute z-10 mt-1 w-full bg-slate-700 border border-slate-600 rounded shadow-lg max-h-56 overflow-y-auto">
|
||||
{filtered.map(p => (
|
||||
<button key={p.shopifyId} type="button"
|
||||
onMouseDown={() => { setSelectedProduct(p); setSearch(''); setShowDropdown(false) }}
|
||||
onMouseDown={() => {
|
||||
setSelectedProduct(p)
|
||||
setSearch('')
|
||||
setShowDropdown(false)
|
||||
fetch(`/api/products/sheet-info?ref=${encodeURIComponent(p.ref)}`)
|
||||
.then(r => r.ok ? r.json() : null)
|
||||
.then(data => {
|
||||
if (!data?.product) return
|
||||
const { famille, longueur, largeur } = data.product
|
||||
if (famille) setFamily(famille)
|
||||
if (longueur && largeur) setDimensions(`${longueur}x${largeur}cm`)
|
||||
else if (longueur) setDimensions(`${longueur}cm`)
|
||||
})
|
||||
}}
|
||||
className="w-full text-left px-3 py-2 text-sm text-white hover:bg-slate-600 flex justify-between gap-2">
|
||||
<span className="truncate">{p.title}</span>
|
||||
<span className="text-xs text-gray-400 shrink-0">{p.ref}</span>
|
||||
|
||||
@@ -6,17 +6,33 @@ import { getTemplateImagePath, listTemplates } from '@/lib/mockupTemplates'
|
||||
import type { MockupGenerateRequest } from '@/types/mockup'
|
||||
|
||||
function buildPrompt(req: MockupGenerateRequest): string {
|
||||
let carrelageContext = 'tiles covering the floor or wall of a modern room'
|
||||
if (req.family === 'Carrelage' && req.placement === 'mur') {
|
||||
carrelageContext = 'wall tiles (faïence) covering the wall of a modern bathroom or kitchen — applied only to the wall, not the floor'
|
||||
} else if (req.family === 'Carrelage' && req.placement === 'sol') {
|
||||
carrelageContext = 'floor tiles covering the floor of a modern room — applied only to the floor, not the walls'
|
||||
if (req.family === 'Carrelage') {
|
||||
let surface = 'floor or wall'
|
||||
let restriction = ''
|
||||
if (req.placement === 'mur') {
|
||||
surface = 'wall'
|
||||
restriction = ' Apply tiles only to the wall surface, not the floor.'
|
||||
} else if (req.placement === 'sol') {
|
||||
surface = 'floor'
|
||||
restriction = ' Apply tiles only to the floor surface, not the walls.'
|
||||
}
|
||||
const dimClause = req.dimensions
|
||||
? ` The real-world tile size is ${req.dimensions}.`
|
||||
: ''
|
||||
const instructionClause = req.instruction ? ` Additional instruction: ${req.instruction}.` : ''
|
||||
|
||||
return `Replace the ${surface} covering in the reference scene with the provided tile image (${req.productName}).${dimClause}${restriction} CRITICAL RULES — you MUST follow all of them:
|
||||
1. Every single tile in the entire image must be EXACTLY the same size — no exceptions anywhere in the scene.
|
||||
2. The tile pattern must be a perfectly uniform grid: identical tile dimensions repeated consistently across the entire ${surface}.
|
||||
3. Tiles may be partially cut at edges, corners, or where the ${surface} meets other surfaces — but each visible portion must match the same grid unit size.
|
||||
4. NEVER vary the tile scale or apparent size in different parts of the image, even for artistic or perspective reasons.
|
||||
5. Copy the tile design, texture, color, and proportions from the provided image exactly — do not alter them.
|
||||
6. Maintain realistic lighting and perspective consistent with the reference scene.${instructionClause}`
|
||||
}
|
||||
|
||||
const familyContext: Record<string, string> = {
|
||||
'Menuiserie': 'door installed in a residential entrance or hallway, visible wall and floor context',
|
||||
'Baies vitrées': 'bay window or sliding door installed in a living room with garden view',
|
||||
'Carrelage': carrelageContext,
|
||||
}
|
||||
const context = familyContext[req.family] ?? 'product installed in an appropriate room setting'
|
||||
const dimClause = req.dimensions
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getServerSession } from 'next-auth'
|
||||
import { authOptions } from '@/lib/auth'
|
||||
import { readSheetProducts } from '@/lib/googleSheets'
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions)
|
||||
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 })
|
||||
|
||||
const ref = new URL(req.url).searchParams.get('ref')
|
||||
if (!ref) return NextResponse.json({ error: 'Paramètre ref manquant' }, { status: 400 })
|
||||
|
||||
const products = await readSheetProducts()
|
||||
const product = products.find(p => p.ref.toLowerCase() === ref.toLowerCase())
|
||||
|
||||
if (!product) return NextResponse.json({ error: 'Produit non trouvé' }, { status: 404 })
|
||||
|
||||
return NextResponse.json({ product })
|
||||
}
|
||||
Reference in New Issue
Block a user