templates: fix issue with populateAuthors hook breaking live-preview on website template (#11608)
Fixes https://github.com/payloadcms/payload/issues/11468 The populateAuthors hook could break live preview if it returned a notFound error as we didn't catch these properly
This commit is contained in:
@@ -6,26 +6,31 @@ import { User } from 'src/payload-types'
|
|||||||
// GraphQL will not return mutated user data that differs from the underlying schema
|
// GraphQL will not return mutated user data that differs from the underlying schema
|
||||||
// So we use an alternative `populatedAuthors` field to populate the user data, hidden from the admin UI
|
// So we use an alternative `populatedAuthors` field to populate the user data, hidden from the admin UI
|
||||||
export const populateAuthors: CollectionAfterReadHook = async ({ doc, req, req: { payload } }) => {
|
export const populateAuthors: CollectionAfterReadHook = async ({ doc, req, req: { payload } }) => {
|
||||||
if (doc?.authors) {
|
if (doc?.authors && doc?.authors?.length > 0) {
|
||||||
const authorDocs: User[] = []
|
const authorDocs: User[] = []
|
||||||
|
|
||||||
for (const author of doc.authors) {
|
for (const author of doc.authors) {
|
||||||
const authorDoc = await payload.findByID({
|
try {
|
||||||
id: typeof author === 'object' ? author?.id : author,
|
const authorDoc = await payload.findByID({
|
||||||
collection: 'users',
|
id: typeof author === 'object' ? author?.id : author,
|
||||||
depth: 0,
|
collection: 'users',
|
||||||
req,
|
depth: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (authorDoc) {
|
if (authorDoc) {
|
||||||
authorDocs.push(authorDoc)
|
authorDocs.push(authorDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorDocs.length > 0) {
|
||||||
|
doc.populatedAuthors = authorDocs.map((authorDoc) => ({
|
||||||
|
id: authorDoc.id,
|
||||||
|
name: authorDoc.name,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// swallow error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doc.populatedAuthors = authorDocs.map((authorDoc) => ({
|
|
||||||
id: authorDoc.id,
|
|
||||||
name: authorDoc.name,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|||||||
@@ -1700,4 +1700,4 @@ export interface Auth {
|
|||||||
|
|
||||||
declare module 'payload' {
|
declare module 'payload' {
|
||||||
export interface GeneratedTypes extends Config {}
|
export interface GeneratedTypes extends Config {}
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ export const Checkbox: React.FC<
|
|||||||
{label}
|
{label}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const Country: React.FC<
|
|||||||
}}
|
}}
|
||||||
rules={{ required }}
|
rules={{ required }}
|
||||||
/>
|
/>
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const Email: React.FC<
|
|||||||
{...register(name, { pattern: /^\S[^\s@]*@\S+$/, required })}
|
{...register(name, { pattern: /^\S[^\s@]*@\S+$/, required })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import * as React from 'react'
|
'use client'
|
||||||
|
|
||||||
export const Error: React.FC = () => {
|
import * as React from 'react'
|
||||||
return <div className="mt-2 text-red-500 text-sm">This field is required</div>
|
import { useFormContext } from 'react-hook-form'
|
||||||
|
|
||||||
|
export const Error = ({ name }: { name: string }) => {
|
||||||
|
const {
|
||||||
|
formState: { errors },
|
||||||
|
} = useFormContext()
|
||||||
|
return (
|
||||||
|
<div className="mt-2 text-red-500 text-sm">
|
||||||
|
{(errors[name]?.message as string) || 'This field is required'}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const Number: React.FC<
|
|||||||
type="number"
|
type="number"
|
||||||
{...register(name, { required })}
|
{...register(name, { required })}
|
||||||
/>
|
/>
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const Select: React.FC<
|
|||||||
}}
|
}}
|
||||||
rules={{ required }}
|
rules={{ required }}
|
||||||
/>
|
/>
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const State: React.FC<
|
|||||||
}}
|
}}
|
||||||
rules={{ required }}
|
rules={{ required }}
|
||||||
/>
|
/>
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const Text: React.FC<
|
|||||||
)}
|
)}
|
||||||
</Label>
|
</Label>
|
||||||
<Input defaultValue={defaultValue} id={name} type="text" {...register(name, { required })} />
|
<Input defaultValue={defaultValue} id={name} type="text" {...register(name, { required })} />
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export const Textarea: React.FC<
|
|||||||
{...register(name, { required: required })}
|
{...register(name, { required: required })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{errors[name] && <Error />}
|
{errors[name] && <Error name={name} />}
|
||||||
</Width>
|
</Width>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,31 @@ import { User } from 'src/payload-types'
|
|||||||
// GraphQL will not return mutated user data that differs from the underlying schema
|
// GraphQL will not return mutated user data that differs from the underlying schema
|
||||||
// So we use an alternative `populatedAuthors` field to populate the user data, hidden from the admin UI
|
// So we use an alternative `populatedAuthors` field to populate the user data, hidden from the admin UI
|
||||||
export const populateAuthors: CollectionAfterReadHook = async ({ doc, req, req: { payload } }) => {
|
export const populateAuthors: CollectionAfterReadHook = async ({ doc, req, req: { payload } }) => {
|
||||||
if (doc?.authors) {
|
if (doc?.authors && doc?.authors?.length > 0) {
|
||||||
const authorDocs: User[] = []
|
const authorDocs: User[] = []
|
||||||
|
|
||||||
for (const author of doc.authors) {
|
for (const author of doc.authors) {
|
||||||
const authorDoc = await payload.findByID({
|
try {
|
||||||
id: typeof author === 'object' ? author?.id : author,
|
const authorDoc = await payload.findByID({
|
||||||
collection: 'users',
|
id: typeof author === 'object' ? author?.id : author,
|
||||||
depth: 0,
|
collection: 'users',
|
||||||
req,
|
depth: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (authorDoc) {
|
if (authorDoc) {
|
||||||
authorDocs.push(authorDoc)
|
authorDocs.push(authorDoc)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorDocs.length > 0) {
|
||||||
|
doc.populatedAuthors = authorDocs.map((authorDoc) => ({
|
||||||
|
id: authorDoc.id,
|
||||||
|
name: authorDoc.name,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// swallow error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doc.populatedAuthors = authorDocs.map((authorDoc) => ({
|
|
||||||
id: authorDoc.id,
|
|
||||||
name: authorDoc.name,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|||||||
Reference in New Issue
Block a user