commit
25c8e4f125
1
env
1
env
@ -14,3 +14,4 @@ S3_SECRET_ACCESS_KEY=9b4e412850582aab32ffdadbe23bb7ea972b39aaf79c34da0c19d3fcafe
|
||||
S3_REGION=ap-southeast-1
|
||||
S3_ENDPOINT=https://jswmbraeandqttpcdfmj.supabase.co/storage/v1/s3
|
||||
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
|
||||
SITE_URL=http://localhost:3000
|
||||
|
@ -15,6 +15,7 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
let publishedAt = "";
|
||||
let updatedAt = "";
|
||||
let imgUrl = "";
|
||||
let createdByName = "";
|
||||
|
||||
const slug = (await params).slug;
|
||||
const blog = await fetchBlogDetail(slug);
|
||||
@ -26,6 +27,9 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
imgUrl = blog.imgUrl;
|
||||
publishedAt = blog.data.createdAt;
|
||||
updatedAt = blog.data.updatedAt;
|
||||
if (!!blog?.data?.createdBy && typeof blog.data.createdBy !== "number") {
|
||||
createdByName = blog.data.createdBy?.name ?? "";
|
||||
}
|
||||
} else {
|
||||
// check for page data when blog is not found
|
||||
const page = await fetchPageBySlug({ slug });
|
||||
@ -35,22 +39,35 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
||||
imgUrl = page.heroImg?.url;
|
||||
publishedAt = page.createdAt;
|
||||
updatedAt = page.updatedAt;
|
||||
|
||||
if (!!page?.createdBy && typeof page.createdBy !== "number") {
|
||||
createdByName = page?.createdBy?.name ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.openGraph.description = description;
|
||||
defaultMetadata.openGraph.images = !!imgUrl ? [imgUrl] : undefined;
|
||||
}
|
||||
defaultMetadata.twitter = {
|
||||
card: "summary_large_image",
|
||||
title: title,
|
||||
description: description,
|
||||
images: !!imgUrl ? [imgUrl] : undefined,
|
||||
};
|
||||
defaultMetadata.other = {
|
||||
"article:published_time": publishedAt,
|
||||
"article:modified_time": updatedAt,
|
||||
"twitter:label1": "Written by",
|
||||
"twitter:data1": !!createdByName ? createdByName : "Admin",
|
||||
"twitter:label2": "Est. reading time",
|
||||
"twitter:data2": "3 minutes",
|
||||
};
|
||||
|
||||
return defaultMetadata;
|
||||
|
@ -1,36 +1,45 @@
|
||||
import { BeforeFooterBlock } from "@/components/Blocks/BeforeFooter";
|
||||
import HeroOther from "@/components/HeroOther";
|
||||
import { fetchTeamDetail } from "@/services/payload/team";
|
||||
import { getDefaultMetadata } from "@/utils/metadata";
|
||||
import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||
import Image from "next/image";
|
||||
import { Metadata } from "next/types";
|
||||
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 imgUrl = "";
|
||||
|
||||
const slug = (await params).slug;
|
||||
const blog = await fetchTeamDetail(decodeURIComponent(slug));
|
||||
const team = await fetchTeamDetail(decodeURIComponent(slug));
|
||||
|
||||
// check for blog data
|
||||
if (!!blog) {
|
||||
title = `${name} Staff - ${blog.data.name}`;
|
||||
description = `${name} Staff - ${blog.data.name}`;
|
||||
imgUrl = blog.imgUrl;
|
||||
if (!!team) {
|
||||
title = `${team.data.name} - ${name}`;
|
||||
imgUrl = team.imgUrl;
|
||||
}
|
||||
|
||||
return {
|
||||
defaultMetadata.title = title;
|
||||
if (!!defaultMetadata.openGraph) {
|
||||
// @ts-ignore
|
||||
defaultMetadata.openGraph.type = "article";
|
||||
defaultMetadata.openGraph.title = title;
|
||||
defaultMetadata.openGraph.images = !!imgUrl ? [imgUrl] : undefined;
|
||||
}
|
||||
defaultMetadata.twitter = {
|
||||
card: "summary_large_image",
|
||||
title: title,
|
||||
description: description,
|
||||
openGraph: {
|
||||
title: title,
|
||||
description: description,
|
||||
images: !!imgUrl ? { url: imgUrl } : undefined,
|
||||
},
|
||||
images: !!imgUrl ? [imgUrl] : undefined,
|
||||
};
|
||||
defaultMetadata.other = {
|
||||
"twitter:label1": "Est. reading time",
|
||||
"twitter:data1": "1 minute",
|
||||
};
|
||||
|
||||
return defaultMetadata;
|
||||
}
|
||||
|
||||
export default async function BiographySinglePage({ params }: { params: Promise<{ slug: string }> }) {
|
13
src/app/robots.ts
Normal file
13
src/app/robots.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
const siteUrl = process.env.SITE_URL || "http://localhost:3000";
|
||||
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: `${siteUrl}/sitemap.xml`,
|
||||
};
|
||||
}
|
18
src/app/sitemap.ts
Normal file
18
src/app/sitemap.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const siteUrl = process.env.SITE_URL || "http://localhost:3000";
|
||||
|
||||
// Define your static routes
|
||||
const routes: string[] = ["", "/blog"];
|
||||
|
||||
// Create sitemap entries for static routes
|
||||
const staticRoutesSitemap = routes.map((route) => ({
|
||||
url: `${siteUrl}${route}`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "weekly" as const,
|
||||
priority: route === "" ? 1 : 0.8,
|
||||
}));
|
||||
|
||||
return [...staticRoutesSitemap];
|
||||
}
|
@ -97,5 +97,6 @@ export const Blogs: CollectionConfig = {
|
||||
admin: {
|
||||
hideAPIURL: true,
|
||||
group: "Blogs",
|
||||
useAsTitle: "title",
|
||||
},
|
||||
};
|
||||
|
@ -104,5 +104,6 @@ export const Pages: CollectionConfig = {
|
||||
admin: {
|
||||
hideAPIURL: true,
|
||||
group: "General",
|
||||
useAsTitle: "title",
|
||||
},
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { CollectionConfig } from "payload";
|
||||
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||
import formatSlug from "@/utils/payload/formatSlug";
|
||||
|
||||
export const Teams: CollectionConfig = {
|
||||
slug: "teams",
|
||||
@ -9,6 +10,13 @@ export const Teams: CollectionConfig = {
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "slug",
|
||||
type: "text",
|
||||
hooks: {
|
||||
beforeValidate: [formatSlug("name")],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role",
|
||||
type: "text",
|
||||
|
@ -2,6 +2,7 @@ import Team from "@/components/Team";
|
||||
|
||||
type Team = {
|
||||
id: number;
|
||||
slug: string;
|
||||
name: string;
|
||||
role: string;
|
||||
img: { url: string; alt: string };
|
||||
|
@ -6,6 +6,7 @@ import { toggleMobileMenu } from "@/utils/toggleMobileMenu";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { FaFacebook, FaLinkedin, FaPhone } from "react-icons/fa";
|
||||
|
||||
const shareIcons: Record<string, any> = {
|
||||
phone: {
|
||||
link: "tel:+15208036644",
|
||||
@ -18,11 +19,21 @@ const shareIcons: Record<string, any> = {
|
||||
},
|
||||
facebook: {
|
||||
link: "https://www.facebook.com/p/Cochise-Oncology-61556262839823",
|
||||
dom: <FaFacebook className="social-nav text-2xl lg:text-[#00898b]" />,
|
||||
dom: (
|
||||
<span className="social-nav flex gap-3 text-2xl lg:text-[#00898b]">
|
||||
<FaFacebook />
|
||||
<b className="text-sm lg:hidden">Facebook</b>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
linkedin: {
|
||||
link: "https://linkedin.com/company/cochise-oncology",
|
||||
dom: <FaLinkedin className="social-nav text-2xl lg:text-[#00898b]" />,
|
||||
dom: (
|
||||
<span className="social-nav flex gap-3 text-2xl lg:text-[#00898b]">
|
||||
<FaLinkedin />
|
||||
<b className="text-sm lg:hidden">Linkedin</b>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2,25 +2,32 @@
|
||||
import Link from "next/link";
|
||||
import { CardTeam } from "./Teams/CardTeam";
|
||||
|
||||
export default function Team({ data }: any) {
|
||||
type Team = {
|
||||
id: number;
|
||||
slug: string;
|
||||
name: string;
|
||||
role: string;
|
||||
img: { url: string; alt: string };
|
||||
biography: string;
|
||||
};
|
||||
|
||||
export default function Team({ data }: { data: Team[] }) {
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-12 offset-md-2 col-lg-6 offset-lg-3 text-center">
|
||||
<h2 className="section-title mb-30 mb-sm-20">
|
||||
<span className="text-gray">Our</span> Team
|
||||
<span className="text-gray">.</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<h2 className="text-4xl mb-30 mb-sm-20">
|
||||
<span className="text-gray">Our</span> Team
|
||||
<span className="text-gray">.</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-5">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 xl:grid-cols-4 gap-x-5 gap-y-2">
|
||||
{/* Team item */}
|
||||
{data.map((member: any, index: any) => (
|
||||
<div key={index} className="text-center">
|
||||
<div key={index} className="flex flex-col text-center justify-between">
|
||||
<CardTeam data={member} />
|
||||
<Link href={`/biography/${member.name}`} passHref>
|
||||
<button className="bg-[#64B3B4] text-white px-5 py-1 m-3 rounded-3xl hover:opacity-[0.7]">
|
||||
Biography
|
||||
<Link href={`/staff_member/${member.slug}`} passHref>
|
||||
<button className="bg-extColorPrimary6 text-white px-5 py-1 m-3 rounded-3xl hover:bg-extColorPrimary4 transition-colors duration-500">
|
||||
BIOGRAPHY
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -21,20 +21,6 @@ export function CardTeam({ data }: CardTeamProps) {
|
||||
data-wow-duration="1.2s"
|
||||
alt={`Image of ${data.name}`}
|
||||
/>
|
||||
<div className="team-item-detail">
|
||||
<div className="team-social-links">
|
||||
{[
|
||||
{ platform: "Facebook", icon: "fa-facebook-f", url: "#" },
|
||||
{ platform: "Twitter", icon: "fa-twitter", url: "#" },
|
||||
{ platform: "Pinterest", icon: "fa-pinterest-p", url: "#" },
|
||||
].map((social, idx) => (
|
||||
<a key={idx} href={social.url} target="_blank" rel="noopener nofollow">
|
||||
<div className="visually-hidden">{social.platform}</div>
|
||||
<i className={social.icon} />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="team-item-descr">
|
||||
<div className="team-item-name">{data.name}</div>
|
||||
|
@ -319,6 +319,7 @@ export interface Page {
|
||||
export interface Team {
|
||||
id: number;
|
||||
name: string;
|
||||
slug?: string | null;
|
||||
role: string;
|
||||
img: number | Media;
|
||||
biography?: {
|
||||
@ -762,6 +763,7 @@ export interface PagesSelect<T extends boolean = true> {
|
||||
*/
|
||||
export interface TeamsSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
slug?: T;
|
||||
role?: T;
|
||||
img?: T;
|
||||
biography?: T;
|
||||
|
@ -114,11 +114,14 @@ export default buildConfig({
|
||||
fields: undefined,
|
||||
admin: {
|
||||
group: "General",
|
||||
useAsTitle: "title",
|
||||
},
|
||||
},
|
||||
formSubmissionOverrides: {
|
||||
fields: undefined,
|
||||
admin: {
|
||||
group: "General",
|
||||
useAsTitle: "form",
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
@ -2,17 +2,16 @@ import payloadConfig from "@/payload.config";
|
||||
import { formatDate } from "@/utils/datetime";
|
||||
import { getPayload } from "payload";
|
||||
|
||||
export async function fetchTeamDetail(name: string | undefined) {
|
||||
export async function fetchTeamDetail(slug: string) {
|
||||
const payload = await getPayload({ config: payloadConfig });
|
||||
const blogDataQuery = await payload.find({
|
||||
collection: "teams",
|
||||
where: {
|
||||
name: { like: `%${name}%` },
|
||||
slug: { equals: slug },
|
||||
},
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
});
|
||||
console.log("data", name);
|
||||
|
||||
if (!blogDataQuery?.docs?.[0]) return null;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user