fix(admin): render visual editor as ui field inside default form
All checks were successful
Build & Deploy to K3s / build-and-deploy (push) Successful in 2m48s

The views.edit.default override replaced Payload's <Form> wrapper, so
useField had no form-state context — every field returned undefined
and setValue threw "N is not a function" during autosave.

Flatten the collection into a single ui field that renders
ProductPreviewEditor, with every real field marked admin.hidden:true.
The panel now lives inside Payload's default form, so useField gets
real values and autosave works.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ordinarthur 2026-04-21 14:17:26 +02:00
parent 8f3a26e883
commit 94fdb37dc3

View File

@ -10,15 +10,6 @@ export const Products: CollectionConfig = {
useAsTitle: 'productDisplayName', useAsTitle: 'productDisplayName',
defaultColumns: ['productDisplayName', 'index', 'type', 'price', 'isPublished'], defaultColumns: ['productDisplayName', 'index', 'type', 'price', 'isPublished'],
group: 'Contenu', group: 'Contenu',
components: {
views: {
edit: {
default: {
Component: '@/components/admin/ProductPreviewEditor#default',
},
},
},
},
}, },
access: { access: {
read: () => true, read: () => true,
@ -40,24 +31,27 @@ export const Products: CollectionConfig = {
}, },
fields: [ fields: [
{ {
type: 'tabs', name: 'previewPanel',
tabs: [ type: 'ui',
{ admin: {
label: 'Identité', components: {
fields: [ Field: '@/components/admin/ProductPreviewEditor#default',
},
},
},
{ {
name: 'productDisplayName', name: 'productDisplayName',
label: 'Nom affiché', label: 'Nom affiché',
type: 'text', type: 'text',
required: true, required: true,
admin: { description: 'Le nom visible par le public (ex: Solar Altar)' }, admin: { hidden: true },
}, },
{ {
name: 'name', name: 'name',
label: 'Nom technique', label: 'Nom technique',
type: 'text', type: 'text',
required: true, required: true,
admin: { description: 'Nom interne sans espaces (ex: Solar_Altar)' }, admin: { hidden: true },
}, },
{ {
name: 'slug', name: 'slug',
@ -66,27 +60,28 @@ export const Products: CollectionConfig = {
required: true, required: true,
unique: true, unique: true,
index: true, index: true,
admin: { description: 'Ex: solar-altar → /collection/solar-altar' }, admin: { hidden: true },
}, },
{ {
name: 'index', name: 'index',
label: 'Index projet', label: 'Index projet',
type: 'text', type: 'text',
required: true, required: true,
admin: { description: 'Ex: PROJET_001' }, admin: { hidden: true },
}, },
{ {
name: 'type', name: 'type',
label: 'Type', label: 'Type',
type: 'text', type: 'text',
required: true, required: true,
admin: { description: 'Ex: LAMPE DE TABLE' }, admin: { hidden: true },
}, },
{ {
name: 'materials', name: 'materials',
label: 'Matériaux', label: 'Matériaux',
type: 'text', type: 'text',
required: true, required: true,
admin: { hidden: true },
}, },
{ {
name: 'year', name: 'year',
@ -94,58 +89,55 @@ export const Products: CollectionConfig = {
type: 'text', type: 'text',
required: true, required: true,
defaultValue: '2026', defaultValue: '2026',
admin: { hidden: true },
}, },
{ {
name: 'status', name: 'status',
label: 'Statut', label: 'Statut',
type: 'text', type: 'text',
required: true, required: true,
admin: { description: 'Ex: PROTOTYPE [80%]' }, admin: { hidden: true },
}, },
{ {
name: 'sortOrder', name: 'sortOrder',
label: 'Ordre d\u2019affichage', label: 'Ordre d\u2019affichage',
type: 'number', type: 'number',
defaultValue: 0, defaultValue: 0,
admin: { hidden: true },
}, },
{ {
name: 'isPublished', name: 'isPublished',
label: 'Publié', label: 'Publié',
type: 'checkbox', type: 'checkbox',
defaultValue: true, defaultValue: true,
admin: { hidden: true },
}, },
],
},
{
label: 'Contenu',
fields: [
{ {
name: 'description', name: 'description',
label: 'Description', label: 'Description',
type: 'textarea', type: 'textarea',
required: true, required: true,
admin: { hidden: true },
}, },
{ {
name: 'specs', name: 'specs',
label: 'Spécifications', label: 'Spécifications',
type: 'textarea', type: 'textarea',
admin: { hidden: true },
}, },
{ {
name: 'notes', name: 'notes',
label: 'Notes', label: 'Notes',
type: 'textarea', type: 'textarea',
admin: { hidden: true },
}, },
],
},
{
label: 'Images',
fields: [
{ {
name: 'images', name: 'images',
label: 'Images', label: 'Images',
type: 'array', type: 'array',
minRows: 1, minRows: 1,
required: true, required: true,
admin: { hidden: true },
fields: [ fields: [
{ {
name: 'image', name: 'image',
@ -155,18 +147,11 @@ export const Products: CollectionConfig = {
}, },
], ],
}, },
],
},
{
label: 'Commerce',
fields: [
{ {
name: 'price', name: 'price',
label: 'Prix (en centimes)', label: 'Prix (en centimes)',
type: 'number', type: 'number',
admin: { admin: { hidden: true },
description: '180000 = 1 800 EUR. Vide = non disponible à la vente.',
},
}, },
{ {
name: 'currency', name: 'currency',
@ -177,6 +162,7 @@ export const Products: CollectionConfig = {
{ label: 'EUR', value: 'EUR' }, { label: 'EUR', value: 'EUR' },
{ label: 'USD', value: 'USD' }, { label: 'USD', value: 'USD' },
], ],
admin: { hidden: true },
}, },
{ {
name: 'availability', name: 'availability',
@ -189,34 +175,24 @@ export const Products: CollectionConfig = {
{ label: 'Sur commande', value: 'https://schema.org/PreOrder' }, { label: 'Sur commande', value: 'https://schema.org/PreOrder' },
{ label: 'Indisponible', value: 'https://schema.org/OutOfStock' }, { label: 'Indisponible', value: 'https://schema.org/OutOfStock' },
], ],
admin: { hidden: true },
}, },
{ {
name: 'stripeProductID', name: 'stripeProductID',
type: 'text', type: 'text',
admin: { admin: { hidden: true, readOnly: true },
readOnly: true,
description: 'Synchronisé automatiquement avec Stripe',
}, },
},
],
},
{
label: 'SEO',
fields: [
{ {
name: 'seoTitle', name: 'seoTitle',
label: 'Titre SEO', label: 'Titre SEO',
type: 'text', type: 'text',
admin: { description: 'Laissez vide pour utiliser le nom du produit' }, admin: { hidden: true },
}, },
{ {
name: 'seoDescription', name: 'seoDescription',
label: 'Description SEO', label: 'Description SEO',
type: 'textarea', type: 'textarea',
}, admin: { hidden: true },
],
},
],
}, },
], ],
} }