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