feat: tag pages integration

This commit is contained in:
RizqiSyahrendra 2025-03-11 17:30:17 +07:00
parent e9c800ab95
commit d2b1384c2b
4 changed files with 188 additions and 2 deletions

View File

@ -111,7 +111,7 @@ export default async function Home() {
{ {
"@type": "Organization", "@type": "Organization",
"@id": `${fullUrl}#organization`, "@id": `${fullUrl}#organization`,
name: "Cochise Oncology", name: siteName,
url: fullUrl, url: fullUrl,
logo: { logo: {
"@type": "ImageObject", "@type": "ImageObject",

View File

@ -0,0 +1,157 @@
import { BeforeFooterBlock } from "@/components/Blocks/BeforeFooter";
import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem";
import Blogs from "@/components/Blogs/Blogs";
import HeroOther from "@/components/HeroOther";
import { fetchBlogTagBySlug } from "@/services/payload/blog";
import { getDefaultMetadata } from "@/utils/metadata";
import { sanitizePageNumber } from "@/utils/sanitize";
import { Metadata } from "next";
import { headers } from "next/headers";
import { notFound } from "next/navigation";
import { Suspense } from "react";
export async function generateMetadata({ params }: { params: Promise<{ path: string[0] }> }): Promise<Metadata> {
const path = (await params)?.path;
const paramsTag = path?.[0] ?? "";
const metadata = await getDefaultMetadata();
const tag = await fetchBlogTagBySlug(paramsTag);
if (!!tag?.data) {
metadata.title = `${tag.data.name} Archives - ${metadata.openGraph?.siteName}`;
}
return metadata;
}
export default async function TagPage({
params,
searchParams,
}: {
params?: Promise<{ path: string[] }>;
searchParams?: Promise<{ page?: string; s?: string }>;
}) {
const path = (await params)?.path;
const paramsTag = path?.[0] ?? "";
const paramsPage = path?.[2] ?? "";
const paramsSearch = (await searchParams)?.s;
const page = sanitizePageNumber(paramsPage);
const headersList = await headers();
const mainUrl = headersList.get("x-main-url");
const fullUrl = headersList.get("x-full-url");
const siteName = headersList.get("x-site-name");
const tag = await fetchBlogTagBySlug(paramsTag);
if (!tag) {
notFound();
}
const jsonLd = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "CollectionPage",
"@id": fullUrl,
url: fullUrl,
name: `${tag.data.name} - ${siteName}`,
isPartOf: {
"@id": `${mainUrl}/#website`,
},
primaryImageOfPage: {
"@id": `${fullUrl}#primaryimage`,
},
image: {
"@id": `${fullUrl}#primaryimage`,
},
inLanguage: "en-US",
},
{
"@type": "WebSite",
"@id": `${mainUrl}/#website`,
url: `${mainUrl}/`,
name: siteName,
description: "",
publisher: {
"@id": `${mainUrl}/#organization`,
},
potentialAction: [
{
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${mainUrl}/?s={search_term_string}`,
},
"query-input": {
"@type": "PropertyValueSpecification",
valueRequired: true,
valueName: "search_term_string",
},
},
],
inLanguage: "en-US",
},
{
"@type": "Organization",
"@id": `${mainUrl}/#organization`,
name: siteName,
url: `${mainUrl}/`,
logo: {
"@type": "ImageObject",
inLanguage: "en-US",
"@id": `${mainUrl}/#/schema/logo/image/`,
url: `${mainUrl}/assets/images/logo-dark.webp`,
contentUrl: `${mainUrl}/assets/images/logo-dark.webp`,
caption: siteName,
},
image: {
"@id": `${mainUrl}/#/schema/logo/image/`,
},
},
],
};
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<HeroOther title={`Tag: ${tag.data.name}`} />
<section className="page-section" id="blog">
<div className="w-full max-w-7xl mx-auto px-4 md:px-8">
<form action={`/tag/${paramsTag}`} method="GET">
<div className="input-group">
<input
type="text"
name="s"
defaultValue={paramsSearch ?? ""}
placeholder="Search blog..."
className="input-lg input-circle form-control h-12"
/>
<div className="input-group-append px-2">
<button className="btn btn-info text-white h-12 px-5" type="submit">
Search
</button>
</div>
</div>
</form>
</div>
<Suspense fallback={<Loading />}>
<Blogs preset="tags" tagId={tag.data.id} page={page} search={paramsSearch} />
</Suspense>
</section>
<BeforeFooterBlock />
</>
);
}
function Loading() {
return (
<div className="container position-relative">
<div className="row">
<BlogCardItemSkeleton />
<BlogCardItemSkeleton />
<BlogCardItemSkeleton />
</div>
</div>
);
}

View File

@ -14,6 +14,10 @@ export type BlogsProps = {
preset?: "categories"; preset?: "categories";
categoryId: number; categoryId: number;
} }
| {
preset?: "tags";
tagId: number;
}
); );
export default async function Blogs({ page, search, ...params }: BlogsProps) { export default async function Blogs({ page, search, ...params }: BlogsProps) {
@ -25,6 +29,9 @@ export default async function Blogs({ page, search, ...params }: BlogsProps) {
if (params.preset === "categories") { if (params.preset === "categories") {
fetchBlogParams.categoryId = params.categoryId; fetchBlogParams.categoryId = params.categoryId;
} }
if (params.preset === "tags") {
fetchBlogParams.tagId = params.tagId;
}
const data = await fetchBlog(fetchBlogParams); const data = await fetchBlog(fetchBlogParams);

View File

@ -6,9 +6,10 @@ type FetchBlogParams = {
page?: number; page?: number;
search?: string; search?: string;
categoryId?: number; categoryId?: number;
tagId?: number;
}; };
export async function fetchBlog({ page, search = "", categoryId }: FetchBlogParams = {}) { export async function fetchBlog({ page, search = "", categoryId, tagId }: FetchBlogParams = {}) {
const payload = await getPayload({ config: payloadConfig }); const payload = await getPayload({ config: payloadConfig });
const queryCondition: Where = {}; const queryCondition: Where = {};
@ -22,6 +23,11 @@ export async function fetchBlog({ page, search = "", categoryId }: FetchBlogPara
equals: categoryId, equals: categoryId,
}; };
} }
if (!!tagId) {
queryCondition["tags"] = {
equals: tagId,
};
}
const blogDataQuery = await payload.find({ const blogDataQuery = await payload.find({
collection: "blogs", collection: "blogs",
@ -86,3 +92,19 @@ export async function fetchBlogCategoryBySlug(slug: string) {
data: category.docs[0], data: category.docs[0],
}; };
} }
export async function fetchBlogTagBySlug(slug: string) {
const payload = await getPayload({ config: payloadConfig });
const tag = await payload.find({
collection: "blogTags",
where: {
slug: { equals: slug },
},
});
if (!tag?.docs?.[0]) return null;
return {
data: tag.docs[0],
};
}