Merge pull request 'dev' (#10) from dev into main

Reviewed-on: #10
This commit is contained in:
RizqiSyahrendra 2025-03-04 22:43:48 +00:00
commit de6459c85a
13 changed files with 160 additions and 54 deletions

View File

@ -3,44 +3,57 @@ import HeroOther from "@/components/HeroOther";
import Page from "@/components/Pages/Page";
import { fetchBlogDetail } from "@/services/payload/blog";
import { fetchPageBySlug } from "@/services/payload/page";
import { getDefaultMetadata } from "@/utils/metadata";
import { Metadata } from "next";
import { Suspense } from "react";
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
const name = "Cochise Oncology";
const defaultMetadata = await getDefaultMetadata();
const name = defaultMetadata.openGraph?.siteName ?? "";
let title = "Page";
let description = "Page";
let publishedAt = "";
let updatedAt = "";
let imgUrl = "";
const slug = (await params).slug;
const blog = await fetchBlogDetail(slug);
// check for blog data
if (!!blog) {
// check for blog data
title = `${!!blog.data?.meta?.title ? blog.data?.meta?.title : blog.data.title} - ${name}`;
description = `${!!blog.data?.meta?.description ? blog.data?.meta?.description : blog.data.title} - ${name}`;
imgUrl = blog.imgUrl;
}
publishedAt = blog.data.createdAt;
updatedAt = blog.data.updatedAt;
} else {
// check for page data when blog is not found
if (!blog) {
const page = await fetchPageBySlug({ slug });
if (!!page) {
title = `${!!page?.meta?.title ? page?.meta?.title : page.title} - ${name}`;
description = `${!!page?.meta?.description ? page?.meta?.description : page.title} - ${name}`;
imgUrl = page.heroImg?.url;
publishedAt = page.createdAt;
updatedAt = page.updatedAt;
}
}
return {
title: title,
description: description,
openGraph: {
title: title,
description: description,
images: !!imgUrl ? { url: imgUrl } : undefined,
},
defaultMetadata.title = title;
defaultMetadata.description = description;
if (!!defaultMetadata.openGraph) {
defaultMetadata.openGraph.title = title;
// @ts-ignore
defaultMetadata.openGraph.type = "article";
defaultMetadata.openGraph.description = description;
defaultMetadata.openGraph.title = title;
defaultMetadata.openGraph.images = !!imgUrl ? { url: imgUrl } : undefined;
}
defaultMetadata.other = {
"article:published_time": publishedAt,
"article:modified_time": updatedAt,
};
return defaultMetadata;
}
export default async function SinglePage({ params }: { params: Promise<{ slug: string }> }) {

View File

@ -3,9 +3,11 @@ import Footer from "@/components/Footer";
import Header from "@/components/Header";
import InitialScript from "@/components/InitialScript";
import { navMenuData } from "@/data/menu";
import { getDefaultMetadata } from "@/utils/metadata";
import "@public/assets/css/styles.css";
import "jarallax/dist/jarallax.min.css";
import { Metadata } from "next";
import { Roboto } from "next/font/google";
import "photoswipe/dist/photoswipe.css";
import "react-modal-video/css/modal-video.css";
@ -15,6 +17,11 @@ import "tippy.js/dist/tippy.css";
const roboto = Roboto({ subsets: ["latin"] });
export async function generateMetadata(): Promise<Metadata> {
const metadata = await getDefaultMetadata();
return metadata;
}
export default function MainLayout({
children,
}: Readonly<{

View File

@ -1,4 +1,4 @@
import formatSlug from "@/utils/formatSlug";
import formatSlug from "@/utils/payload/formatSlug";
import type { CollectionConfig } from "payload";
export const BlogCategories: CollectionConfig = {

View File

@ -1,4 +1,4 @@
import formatSlug from "@/utils/formatSlug";
import formatSlug from "@/utils/payload/formatSlug";
import type { CollectionConfig } from "payload";
export const BlogTags: CollectionConfig = {

View File

@ -1,10 +1,16 @@
import type { CollectionConfig } from "payload";
import formatSlug from "@/utils/payload/formatSlug";
import setAuthor from "@/utils/payload/setAuthor";
import { lexicalEditor } from "@payloadcms/richtext-lexical";
import formatSlug from "@/utils/formatSlug";
import type { CollectionConfig } from "payload";
export const Blogs: CollectionConfig = {
slug: "blogs",
labels: { plural: "Posts", singular: "Post" },
versions: {
drafts: {
validate: true,
},
},
fields: [
{
name: "title",
@ -59,19 +65,32 @@ export const Blogs: CollectionConfig = {
type: "textarea",
},
{
name: "cannonical_url",
label: "Cannonical Url",
name: "canonical_url",
label: "Canonical Url",
type: "text",
},
],
},
{
name: "is_published",
label: "Published",
type: "checkbox",
defaultValue: true,
name: "createdBy",
type: "relationship",
relationTo: "users",
hooks: {
beforeChange: [setAuthor],
},
admin: {
position: "sidebar",
hidden: true,
},
},
{
name: "updatedBy",
type: "relationship",
relationTo: "users",
hooks: {
beforeChange: [setAuthor],
},
admin: {
hidden: true,
},
},
],

View File

@ -7,11 +7,17 @@ import { GoogleReviewBlock } from "@/blocks/GoogleReview";
import { HorizontalImageContentBlock } from "@/blocks/HorizontalImageContent";
import { ImageSliderBlock } from "@/blocks/ImageSlider";
import { OurTeamBlock } from "@/blocks/OurTeam";
import formatSlug from "@/utils/formatSlug";
import formatSlug from "@/utils/payload/formatSlug";
import setAuthor from "@/utils/payload/setAuthor";
import { CollectionConfig } from "payload";
export const Pages: CollectionConfig = {
slug: "pages",
versions: {
drafts: {
validate: true,
},
},
fields: [
{
name: "title",
@ -29,9 +35,6 @@ export const Pages: CollectionConfig = {
name: "slug",
label: "Page Slug",
type: "text",
admin: {
position: "sidebar",
},
hooks: {
beforeValidate: [formatSlug("title")],
},
@ -75,6 +78,28 @@ export const Pages: CollectionConfig = {
},
],
},
{
name: "createdBy",
type: "relationship",
relationTo: "users",
hooks: {
beforeChange: [setAuthor],
},
admin: {
hidden: true,
},
},
{
name: "updatedBy",
type: "relationship",
relationTo: "users",
hooks: {
beforeChange: [setAuthor],
},
admin: {
hidden: true,
},
},
],
admin: {
hideAPIURL: true,

View File

@ -11,5 +11,10 @@ export const Users: CollectionConfig = {
fields: [
// Email added by default
// Add more fields as needed
{
name: "name",
label: "Name",
type: "text",
},
],
};

View File

@ -8,7 +8,10 @@ export function middleware(request: NextRequest) {
const host = request.headers.get("x-forwarded-host") || request.nextUrl.hostname;
const path = request.nextUrl.pathname + request.nextUrl.search;
// Construct the full URL
const fullUrl = `${protocol}://${host}${path}`;
const mainUrl = `${protocol}://${host}`;
const fullUrl = `${mainUrl}${path}`;
request.headers.set("x-main-url", mainUrl);
request.headers.set("x-full-url", fullUrl);
return NextResponse.next({

View File

@ -83,6 +83,7 @@ export interface UserAuthOperations {
*/
export interface User {
id: number;
name?: string | null;
updatedAt: string;
createdAt: string;
email: string;
@ -143,11 +144,13 @@ export interface Blog {
meta?: {
title?: string | null;
description?: string | null;
cannonical_url?: string | null;
canonical_url?: string | null;
};
is_published?: boolean | null;
createdBy?: (number | null) | User;
updatedBy?: (number | null) | User;
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
@ -303,8 +306,11 @@ export interface Page {
description?: string | null;
cannonical_url?: string | null;
};
createdBy?: (number | null) | User;
updatedBy?: (number | null) | User;
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
@ -593,6 +599,7 @@ export interface PayloadMigration {
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
name?: T;
updatedAt?: T;
createdAt?: T;
email?: T;
@ -638,11 +645,13 @@ export interface BlogsSelect<T extends boolean = true> {
| {
title?: T;
description?: T;
cannonical_url?: T;
canonical_url?: T;
};
is_published?: T;
createdBy?: T;
updatedBy?: T;
updatedAt?: T;
createdAt?: T;
_status?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
@ -741,8 +750,11 @@ export interface PagesSelect<T extends boolean = true> {
description?: T;
cannonical_url?: T;
};
createdBy?: T;
updatedBy?: T;
updatedAt?: T;
createdAt?: T;
_status?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@ -10,25 +10,12 @@ export async function fetchBlog(page: number | undefined, search: string = "") {
pagination: true,
limit: 6,
where: !search
? {
is_published: {
equals: true,
},
}
? undefined
: {
and: [
{
is_published: {
equals: true,
},
},
{
title: {
contains: search,
},
},
],
},
});
const formattedData = blogDataQuery.docs.map((item) => {
@ -51,9 +38,6 @@ export async function fetchBlogDetail(slug: string | undefined) {
collection: "blogs",
where: {
slug: { equals: slug },
is_published: {
equals: true,
},
},
limit: 1,
pagination: false,

21
src/utils/metadata.ts Normal file
View File

@ -0,0 +1,21 @@
import { Metadata } from "next";
import { headers } from "next/headers";
export async function getDefaultMetadata(): Promise<Metadata> {
const headersList = await headers();
const mainUrl = headersList.get("x-main-url") ?? "";
const fullUrl = headersList.get("x-full-url") ?? "";
return {
metadataBase: new URL(mainUrl),
openGraph: {
type: "website",
locale: "en_US",
url: fullUrl,
siteName: "Cochise Oncology",
},
alternates: {
canonical: "./",
},
};
}

View File

@ -0,0 +1,17 @@
import { FieldHook } from "payload";
const setAuthor: FieldHook = ({ value, req, data, field, operation }) => {
if (req.user && !!data) {
if (operation === "create") {
return req.user.id;
} else {
if (field.name === "updatedBy") {
return req.user.id;
}
}
}
return value;
};
export default setAuthor;