fix: Create petition: Downgraded back to Next 15, removed revalidation on first draft save, chaged reavlidation patter to factory mode to support a revalidation tag per document

This commit is contained in:
Francisco Ignácio Fontoura Solla 2026-03-08 22:53:57 -03:00
parent 4c59c965b0
commit 5460eeee3c
14 changed files with 446 additions and 396 deletions

View file

@ -2,7 +2,6 @@ import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */
const nextConfig = {
cacheComponents: true,
images: {
remotePatterns: [new URL('https://jorgesolla.com.br/**')],
},

View file

@ -36,12 +36,12 @@
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@payloadcms/db-postgres": "3.76.1",
"@payloadcms/live-preview-react": "3.76.1",
"@payloadcms/next": "3.76.1",
"@payloadcms/richtext-lexical": "3.76.1",
"@payloadcms/storage-vercel-blob": "3.76.1",
"@payloadcms/ui": "3.76.1",
"@payloadcms/db-postgres": "3.79.0",
"@payloadcms/live-preview-react": "3.79.0",
"@payloadcms/next": "3.79.0",
"@payloadcms/richtext-lexical": "3.79.0",
"@payloadcms/storage-vercel-blob": "3.79.0",
"@payloadcms/ui": "3.79.0",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.8",
@ -54,9 +54,9 @@
"dotenv": "16.4.7",
"graphql": "^16.8.1",
"lucide-react": "^0.570.0",
"next": "^16.1.6",
"next": "^15.5.12",
"next-themes": "^0.4.6",
"payload": "3.76.1",
"payload": "3.79.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-hook-form": "^7.71.1",
@ -76,7 +76,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "4.5.2",
"eslint": "^9.39.2",
"eslint-config-next": "^16.1.6",
"eslint-config-next": "^15.5.12",
"eslint-config-prettier": "^10.1.8",
"jsdom": "28.0.0",
"postcss": "^8.5.6",

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@ export async function generateStaticParams() {
}
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const petition = await getCachedDocumentById('petition', (await params).id)
const petition = await getCachedDocumentById('petition', (await params).id)()
if (!petition || !petition.enabled) {
return notFound()

View file

@ -14,12 +14,12 @@ import { Analytics } from '@vercel/analytics/next'
const inter = Inter({ subsets: ['latin'], variable: '--font-sans' })
export async function generateMetadata(): Promise<Metadata> {
const payload = await getCachedGlobal('metadata')
const payload = await getCachedGlobal('metadata')()
let image = payload.image
if (typeof image === 'number') {
image = await getCachedDocumentById('media', String(payload.image))
image = await getCachedDocumentById('media', String(payload.image))()
}
return {

View file

@ -4,12 +4,12 @@ import { getCachedGlobal } from '@/utilities/globals'
import Image from 'next/image'
export default async function HomePage() {
const payload = await getCachedGlobal('home', 2)
const payload = await getCachedGlobal('home', 2)()
let image: Media
if (typeof payload.image === 'number') {
image = await getCachedDocumentById('media', `${payload.image}`)
image = await getCachedDocumentById('media', `${payload.image}`)()
} else {
image = payload.image
}

View file

@ -4,7 +4,7 @@ import config from '@payload-config'
import '@payloadcms/next/css'
import type { ServerFunctionClient } from 'payload'
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
import React, { Suspense } from 'react'
import React from 'react'
import { importMap } from './admin/importMap.js'
import './custom.scss'
@ -23,11 +23,9 @@ const serverFunction: ServerFunctionClient = async function (args) {
}
const Layout = ({ children }: Args) => (
<Suspense>
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
{children}
</RootLayout>
</Suspense>
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
{children}
</RootLayout>
)
export default Layout

View file

@ -29,7 +29,15 @@ export const Petition: CollectionConfig<typeof slug> = {
read: () => true,
},
hooks: {
beforeChange: [({ data }) => revalidateDocumentById(slug, data.id)],
afterChange: [
({ doc, previousDoc, operation }) => {
// Admin create view creates the initial draft during render.
// Skip cache invalidation only for that first draft creation.
if (operation === 'create' && doc._status !== 'published') return
revalidateDocumentById(slug, previousDoc?.id ?? doc.id)
},
],
},
fields: [
{

View file

@ -2,7 +2,7 @@ import { getCachedGlobal } from '@/utilities/globals'
import { SocialLinks } from './socialLinks'
export const Header = async () => {
const settings = await getCachedGlobal('site-settings', 2)
const settings = await getCachedGlobal('site-settings', 2)()
return (
<header className="flex items-center justify-between p-4 absolute top-0 left-0 right-0">

View file

@ -79,7 +79,7 @@ type SocialLinksProps = {
}
export const SocialLinks = async ({ ariaLabel }: SocialLinksProps) => {
const { socialLinks: links } = await getCachedGlobal('site-settings', 2)
const { socialLinks: links } = await getCachedGlobal('site-settings', 2)()
if (!links?.length) return null

View file

@ -108,6 +108,9 @@ export interface Config {
metadata: MetadataSelect<false> | MetadataSelect<true>;
};
locale: null;
widgets: {
collections: CollectionsWidget;
};
user: User;
jobs: {
tasks: {
@ -751,6 +754,16 @@ export interface MetadataSelect<T extends boolean = true> {
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "collections_widget".
*/
export interface CollectionsWidget {
data?: {
[k: string]: unknown;
};
width: 'full';
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "TaskSchedulePublish".

View file

@ -1,7 +1,7 @@
import { Config } from '@/payload-types'
import type { Config } from '@/payload-types'
import configPromise from '@payload-config'
import { cacheTag, revalidateTag } from 'next/cache'
import { revalidateTag, unstable_cache } from 'next/cache'
import { getPayload } from 'payload'
type Collection = keyof Config['collections']
@ -21,15 +21,14 @@ export const getDocumentById = <Slug extends Collection>(
const getTag = <Slug extends Collection>(collection: Slug, id: string) =>
`document_${collection}:${id}`
export const getCachedDocumentById = async <Slug extends Collection>(
export const getCachedDocumentById = <Slug extends Collection>(
collection: Slug,
id: string,
depth?: number,
) => {
'use cache'
cacheTag(getTag(collection, id))
return await getDocumentById(collection, id, depth)
}
) =>
unstable_cache(() => getDocumentById(collection, id, depth), [getTag(collection, id)], {
tags: [getTag(collection, id)],
})
export const revalidateDocumentById = <Slug extends Collection>(collection: Slug, id: string) =>
revalidateTag(getTag(collection, id), 'max')
revalidateTag(getTag(collection, id))

View file

@ -1,7 +1,7 @@
import type { Config } from 'src/payload-types'
import configPromise from '@payload-config'
import { cacheTag, revalidateTag } from 'next/cache'
import { revalidateTag, unstable_cache } from 'next/cache'
import { getPayload } from 'payload'
type Global = keyof Config['globals']
@ -19,11 +19,7 @@ export async function getGlobal<Slug extends Global>(slug: Slug, depth?: number)
const getTag = (slug: string) => `global_${slug}`
export const getCachedGlobal = async <Slug extends Global>(slug: Slug, depth?: number) => {
'use cache'
cacheTag(getTag(slug))
return await getGlobal(slug, depth)
}
export const getCachedGlobal = <Slug extends Global>(slug: Slug, depth?: number) =>
unstable_cache(async () => getGlobal(slug, depth), [getTag(slug)])
export const revalidateGlobal = <Slug extends Global>(slug: Slug) =>
revalidateTag(getTag(slug), 'max')
export const revalidateGlobal = <Slug extends Global>(slug: Slug) => revalidateTag(getTag(slug))

View file

@ -15,7 +15,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"plugins": [
{