fix: dynamic page from payload
This commit is contained in:
parent
d6d41102a7
commit
dc3e009488
39
src/app/(main)/[pageslug]/page.tsx
Normal file
39
src/app/(main)/[pageslug]/page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { BlogDetailContentSkeleton } from "@/components/Blogs/BlogDetail";
|
||||||
|
import Page from "@/components/Pages/Page";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: "Page | Cochise Oncology",
|
||||||
|
description: "Page | Cochise Oncology",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function CustomPage({ params }: { params?: Promise<{ pageslug?: string }> }) {
|
||||||
|
const slug = (await params)?.pageslug;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Suspense fallback={<Loading />}>
|
||||||
|
<Page slug={slug} />
|
||||||
|
</Suspense>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Loading() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="page-section bg-dark-1 bg-gradient-gray-dark-1 light-content bg-scroll overflow-hidden">
|
||||||
|
{/* <!-- Background Shape --> */}
|
||||||
|
<div className="bg-shape-1 opacity-003">
|
||||||
|
<Image src="/assets/images/demo-fancy/bg-shape-1.svg" width={1443} height={844} alt="" />
|
||||||
|
</div>
|
||||||
|
{/* <!-- End Background Shape --> */}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Section */}
|
||||||
|
<BlogDetailContentSkeleton />
|
||||||
|
{/* End Section */}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -53,22 +53,6 @@ function Loading() {
|
|||||||
<Image src="/assets/images/demo-fancy/bg-shape-1.svg" width={1443} height={844} alt="" />
|
<Image src="/assets/images/demo-fancy/bg-shape-1.svg" width={1443} height={844} alt="" />
|
||||||
</div>
|
</div>
|
||||||
{/* <!-- End Background Shape --> */}
|
{/* <!-- End Background Shape --> */}
|
||||||
|
|
||||||
<div className="container position-relative pt-sm-40 text-center">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
|
||||||
<h1 className="hs-title-10 mb-10 wow fadeInUp">...</h1>
|
|
||||||
{/* Author, Categories, Comments */}
|
|
||||||
<div className="blog-item-data mb-0 wow fadeIn" data-wow-delay="0.2s">
|
|
||||||
<div className="flex justify-center items-center">
|
|
||||||
<i className="mi-clock mr-2" />
|
|
||||||
<a href="#">...</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* End Author, Categories, Comments */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Section */}
|
{/* Section */}
|
||||||
|
27
src/blocks/BeforeFooter.ts
Normal file
27
src/blocks/BeforeFooter.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Block } from "payload";
|
||||||
|
|
||||||
|
export const BeforeFooterBlock: Block = {
|
||||||
|
slug: "beforeFooterBlock",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
defaultValue: "Begin your path to healing with Cochise Oncology",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
type: "textarea",
|
||||||
|
required: true,
|
||||||
|
defaultValue:
|
||||||
|
"Our dedicated team in Sierra Vista, AZ is here to support you with hope, strength, and courage. We offer personalized cancer care using innovative treatments in our state-of-the-art facility. Take the first step towards comprehensive, patient-focused treatment by scheduling a consultation. Let us listen to your needs, answer your questions, and create a tailored plan for your journey. Fill out our form to connect with our compassionate experts and discover how Cochise Oncology can stand with you in your fight against cancer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "buttonText",
|
||||||
|
label: "CTA Button Text",
|
||||||
|
required: true,
|
||||||
|
defaultValue: "Get Started",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
14
src/blocks/Content.ts
Normal file
14
src/blocks/Content.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||||
|
import { Block } from "payload";
|
||||||
|
|
||||||
|
export const ContentBlock: Block = {
|
||||||
|
slug: "contentBlock",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "content",
|
||||||
|
type: "richText",
|
||||||
|
editor: lexicalEditor({}),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
62
src/collections/Pages.ts
Normal file
62
src/collections/Pages.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { BeforeFooterBlock } from "@/blocks/BeforeFooter";
|
||||||
|
import { ContentBlock } from "@/blocks/Content";
|
||||||
|
import formatSlug from "@/utils/formatSlug";
|
||||||
|
import { CollectionConfig } from "payload";
|
||||||
|
|
||||||
|
export const Pages: CollectionConfig = {
|
||||||
|
slug: "pages",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
label: "Page Title",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hero_img",
|
||||||
|
label: "Hero Image",
|
||||||
|
type: "upload",
|
||||||
|
relationTo: "media",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "slug",
|
||||||
|
label: "Page Slug",
|
||||||
|
type: "text",
|
||||||
|
admin: {
|
||||||
|
position: "sidebar",
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeValidate: [formatSlug("title")],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "layout",
|
||||||
|
label: "Page Layout",
|
||||||
|
type: "blocks",
|
||||||
|
minRows: 1,
|
||||||
|
blocks: [ContentBlock, BeforeFooterBlock],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "meta",
|
||||||
|
label: "Page Meta",
|
||||||
|
type: "group",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
label: "Title",
|
||||||
|
type: "text",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
label: "Description",
|
||||||
|
type: "textarea",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "keywords",
|
||||||
|
label: "Keywords",
|
||||||
|
type: "text",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
29
src/components/Blocks/BeforeFooter/index.tsx
Normal file
29
src/components/Blocks/BeforeFooter/index.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export interface BeforeFooterBlockProps {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
buttonText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BeforeFooterBlock({ title, description, buttonText }: BeforeFooterBlockProps) {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={`page-section text-white text-center scrollSpysection bg-dark-1 light-content bg-scroll`}
|
||||||
|
id="about"
|
||||||
|
>
|
||||||
|
<div className="container mx-auto px-6">
|
||||||
|
<h2 className="text-3xl font-bold mb-4">{title}</h2>
|
||||||
|
<p className="text-lg mb-6">{description}</p>
|
||||||
|
{!!buttonText && (
|
||||||
|
<div className="pt-5">
|
||||||
|
<Link href="/contact" className="bg-purple-600 hover:bg-purple-700 text-white py-3 px-6 rounded-lg text-lg">
|
||||||
|
{buttonText}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
26
src/components/Blocks/Content/index.tsx
Normal file
26
src/components/Blocks/Content/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||||
|
|
||||||
|
// type Props = extract
|
||||||
|
|
||||||
|
export function ContentBlock(props: any) {
|
||||||
|
return (
|
||||||
|
<div className="container relative">
|
||||||
|
<div className="row">
|
||||||
|
{/* Content */}
|
||||||
|
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
||||||
|
{/* Post */}
|
||||||
|
<div className="blog-item mb-80 mb-xs-40">
|
||||||
|
<div className="blog-item-body">
|
||||||
|
<div>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<RichText data={props.content} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* End Post */}
|
||||||
|
</div>
|
||||||
|
{/* End Content */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
44
src/components/Blocks/RenderBlocks.tsx
Normal file
44
src/components/Blocks/RenderBlocks.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import React, { Fragment } from "react";
|
||||||
|
|
||||||
|
import type { Page } from "@/payload-types";
|
||||||
|
import { ContentBlock } from "./Content";
|
||||||
|
import { BeforeFooterBlock } from "./BeforeFooter";
|
||||||
|
|
||||||
|
const blockComponents = {
|
||||||
|
contentBlock: ContentBlock,
|
||||||
|
beforeFooterBlock: BeforeFooterBlock,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RenderBlocks: React.FC<{
|
||||||
|
blocks: Page["layout"];
|
||||||
|
}> = (props) => {
|
||||||
|
const { blocks } = props;
|
||||||
|
|
||||||
|
const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0;
|
||||||
|
|
||||||
|
if (hasBlocks) {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{blocks.map((block, index) => {
|
||||||
|
const { blockType } = block;
|
||||||
|
|
||||||
|
if (blockType && blockType in blockComponents) {
|
||||||
|
const Block = blockComponents[blockType];
|
||||||
|
|
||||||
|
if (Block) {
|
||||||
|
return (
|
||||||
|
<div className="mt-16" key={index}>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Block {...block} disableInnerContainer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
58
src/components/Pages/Page.tsx
Normal file
58
src/components/Pages/Page.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { RenderBlocks } from "@/components/Blocks/RenderBlocks";
|
||||||
|
import { fetchPageBySlug } from "@/services/payload/page";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
|
export interface PageProps {
|
||||||
|
slug: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({ slug }: PageProps) {
|
||||||
|
const page = await fetchPageBySlug({ slug });
|
||||||
|
if (!page) {
|
||||||
|
return notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="page-section bg-dark-1 bg-gradient-gray-dark-1 light-content bg-scroll overflow-hidden">
|
||||||
|
{/* <!-- Background Shape --> */}
|
||||||
|
{!!page.heroImg?.url && (
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full opacity-20">
|
||||||
|
<Image
|
||||||
|
src={page.heroImg.url}
|
||||||
|
width="0"
|
||||||
|
height="0"
|
||||||
|
sizes="100vw"
|
||||||
|
className="w-full"
|
||||||
|
alt={page.heroImg.alt}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!page?.heroImg?.url && (
|
||||||
|
<div className="absolute top-0 left-0 w-full h-full opacity-003">
|
||||||
|
<Image
|
||||||
|
src="/assets/images/demo-fancy/bg-shape-1.svg"
|
||||||
|
width="0"
|
||||||
|
height="0"
|
||||||
|
sizes="100vw"
|
||||||
|
className="w-full"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* <!-- End Background Shape --> */}
|
||||||
|
|
||||||
|
<div className="container position-relative pt-sm-40 text-center">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
|
||||||
|
<h1 className="hs-title-10 mb-10 wow fadeInUp">{page.title}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<RenderBlocks blocks={page.layout} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -4,7 +4,7 @@ export const navMenuData = [
|
|||||||
href: "#",
|
href: "#",
|
||||||
text: "About",
|
text: "About",
|
||||||
child: [
|
child: [
|
||||||
{ href: "/slick-about-dark", text: "Our Oncology Center" },
|
{ href: "/our-oncology-center", text: "Our Oncology Center" },
|
||||||
{ href: "/our-staff", text: "Our Staff" },
|
{ href: "/our-staff", text: "Our Staff" },
|
||||||
{ href: "/announcements", text: "Announcements" },
|
{ href: "/announcements", text: "Announcements" },
|
||||||
],
|
],
|
||||||
|
@ -14,6 +14,7 @@ export interface Config {
|
|||||||
users: User;
|
users: User;
|
||||||
media: Media;
|
media: Media;
|
||||||
blogs: Blog;
|
blogs: Blog;
|
||||||
|
pages: Page;
|
||||||
forms: Form;
|
forms: Form;
|
||||||
'form-submissions': FormSubmission;
|
'form-submissions': FormSubmission;
|
||||||
'payload-locked-documents': PayloadLockedDocument;
|
'payload-locked-documents': PayloadLockedDocument;
|
||||||
@ -25,6 +26,7 @@ export interface Config {
|
|||||||
users: UsersSelect<false> | UsersSelect<true>;
|
users: UsersSelect<false> | UsersSelect<true>;
|
||||||
media: MediaSelect<false> | MediaSelect<true>;
|
media: MediaSelect<false> | MediaSelect<true>;
|
||||||
blogs: BlogsSelect<false> | BlogsSelect<true>;
|
blogs: BlogsSelect<false> | BlogsSelect<true>;
|
||||||
|
pages: PagesSelect<false> | PagesSelect<true>;
|
||||||
forms: FormsSelect<false> | FormsSelect<true>;
|
forms: FormsSelect<false> | FormsSelect<true>;
|
||||||
'form-submissions': FormSubmissionsSelect<false> | FormSubmissionsSelect<true>;
|
'form-submissions': FormSubmissionsSelect<false> | FormSubmissionsSelect<true>;
|
||||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||||
@ -127,6 +129,55 @@ export interface Blog {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "pages".
|
||||||
|
*/
|
||||||
|
export interface Page {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
hero_img?: (number | null) | Media;
|
||||||
|
slug?: string | null;
|
||||||
|
layout?:
|
||||||
|
| (
|
||||||
|
| {
|
||||||
|
content: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: string;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
id?: string | null;
|
||||||
|
blockName?: string | null;
|
||||||
|
blockType: 'contentBlock';
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
buttonText: string;
|
||||||
|
id?: string | null;
|
||||||
|
blockName?: string | null;
|
||||||
|
blockType: 'beforeFooterBlock';
|
||||||
|
}
|
||||||
|
)[]
|
||||||
|
| null;
|
||||||
|
meta?: {
|
||||||
|
title?: string | null;
|
||||||
|
description?: string | null;
|
||||||
|
keywords?: string | null;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "forms".
|
* via the `definition` "forms".
|
||||||
@ -316,6 +367,10 @@ export interface PayloadLockedDocument {
|
|||||||
relationTo: 'blogs';
|
relationTo: 'blogs';
|
||||||
value: number | Blog;
|
value: number | Blog;
|
||||||
} | null)
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'pages';
|
||||||
|
value: number | Page;
|
||||||
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'forms';
|
relationTo: 'forms';
|
||||||
value: number | Form;
|
value: number | Form;
|
||||||
@ -412,6 +467,44 @@ export interface BlogsSelect<T extends boolean = true> {
|
|||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "pages_select".
|
||||||
|
*/
|
||||||
|
export interface PagesSelect<T extends boolean = true> {
|
||||||
|
title?: T;
|
||||||
|
hero_img?: T;
|
||||||
|
slug?: T;
|
||||||
|
layout?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
contentBlock?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
content?: T;
|
||||||
|
id?: T;
|
||||||
|
blockName?: T;
|
||||||
|
};
|
||||||
|
beforeFooterBlock?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
title?: T;
|
||||||
|
description?: T;
|
||||||
|
buttonText?: T;
|
||||||
|
id?: T;
|
||||||
|
blockName?: T;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
meta?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
title?: T;
|
||||||
|
description?: T;
|
||||||
|
keywords?: T;
|
||||||
|
};
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "forms_select".
|
* via the `definition` "forms_select".
|
||||||
|
@ -10,6 +10,7 @@ import { fileURLToPath } from "url";
|
|||||||
|
|
||||||
import { Blogs } from "@/collections/Blogs";
|
import { Blogs } from "@/collections/Blogs";
|
||||||
import { Media } from "@/collections/Media";
|
import { Media } from "@/collections/Media";
|
||||||
|
import { Pages } from "@/collections/Pages";
|
||||||
import { Users } from "@/collections/Users";
|
import { Users } from "@/collections/Users";
|
||||||
import {
|
import {
|
||||||
BoldFeature,
|
BoldFeature,
|
||||||
@ -45,7 +46,7 @@ export default buildConfig({
|
|||||||
},
|
},
|
||||||
theme: "dark",
|
theme: "dark",
|
||||||
},
|
},
|
||||||
collections: [Users, Media, Blogs],
|
collections: [Users, Media, Blogs, Pages],
|
||||||
secret: process.env.PAYLOAD_SECRET || "",
|
secret: process.env.PAYLOAD_SECRET || "",
|
||||||
typescript: {
|
typescript: {
|
||||||
outputFile: path.resolve(dirname, "payload-types.ts"),
|
outputFile: path.resolve(dirname, "payload-types.ts"),
|
||||||
|
39
src/services/payload/page.ts
Normal file
39
src/services/payload/page.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import payloadConfig from "@/payload.config";
|
||||||
|
import { draftMode } from "next/headers";
|
||||||
|
import { getPayload } from "payload";
|
||||||
|
|
||||||
|
export const fetchPageBySlug = async ({ slug }: { slug: string | undefined }) => {
|
||||||
|
const { isEnabled: draft } = await draftMode();
|
||||||
|
|
||||||
|
const payload = await getPayload({ config: payloadConfig });
|
||||||
|
|
||||||
|
const result = await payload.find({
|
||||||
|
collection: "pages",
|
||||||
|
// draft,
|
||||||
|
limit: 1,
|
||||||
|
pagination: false,
|
||||||
|
// overrideAccess: draft,
|
||||||
|
where: {
|
||||||
|
slug: {
|
||||||
|
equals: slug,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.docs?.[0]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = result.docs[0];
|
||||||
|
|
||||||
|
const heroImgUrl = typeof data.hero_img !== "number" ? (data?.hero_img?.url ?? "") : "";
|
||||||
|
const heroImgAlt = typeof data.hero_img !== "number" ? (data?.hero_img?.alt ?? "") : "";
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
heroImg: {
|
||||||
|
url: heroImgUrl,
|
||||||
|
alt: heroImgAlt,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
24
src/utils/formatSlug.ts
Normal file
24
src/utils/formatSlug.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { FieldHook } from "payload";
|
||||||
|
|
||||||
|
const format = (val: string): string =>
|
||||||
|
val
|
||||||
|
.replace(/ /g, "-")
|
||||||
|
.replace(/[^\w-/]+/g, "")
|
||||||
|
.toLowerCase();
|
||||||
|
|
||||||
|
const formatSlug =
|
||||||
|
(fallback: string): FieldHook =>
|
||||||
|
({ value, originalDoc, data }) => {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return format(value);
|
||||||
|
}
|
||||||
|
const fallbackData = (data && data[fallback]) || (originalDoc && originalDoc[fallback]);
|
||||||
|
|
||||||
|
if (fallbackData && typeof fallbackData === "string") {
|
||||||
|
return format(fallbackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formatSlug;
|
Loading…
x
Reference in New Issue
Block a user