feat: OurTeam block component & fetching

This commit is contained in:
RizqiSyahrendra 2025-02-07 16:10:08 +07:00
parent ba04b73c4f
commit 2f7303d000
12 changed files with 183 additions and 8 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@ -4,8 +4,8 @@ import Image from "next/image";
import { Suspense } from "react"; import { Suspense } from "react";
export const metadata = { export const metadata = {
title: "Page | Cochise Oncology", title: "Cochise Oncology",
description: "Page | Cochise Oncology", description: "Cochise Oncology",
}; };
export default async function CustomPage({ params }: { params?: Promise<{ pageslug?: string }> }) { export default async function CustomPage({ params }: { params?: Promise<{ pageslug?: string }> }) {

13
src/blocks/OurTeam.ts Normal file
View File

@ -0,0 +1,13 @@
import { Block } from "payload";
export const OurTeamBlock: Block = {
slug: "ourTeamBlock",
fields: [
{
name: "team",
type: "relationship",
relationTo: "teams",
hasMany: true,
},
],
};

View File

@ -1,5 +1,6 @@
import { BeforeFooterBlock } from "@/blocks/BeforeFooter"; import { BeforeFooterBlock } from "@/blocks/BeforeFooter";
import { ContentBlock } from "@/blocks/Content"; import { ContentBlock } from "@/blocks/Content";
import { OurTeamBlock } from "@/blocks/OurTeam";
import formatSlug from "@/utils/formatSlug"; import formatSlug from "@/utils/formatSlug";
import { CollectionConfig } from "payload"; import { CollectionConfig } from "payload";
@ -34,7 +35,7 @@ export const Pages: CollectionConfig = {
label: "Page Layout", label: "Page Layout",
type: "blocks", type: "blocks",
minRows: 1, minRows: 1,
blocks: [ContentBlock, BeforeFooterBlock], blocks: [ContentBlock, BeforeFooterBlock, OurTeamBlock],
}, },
{ {
name: "meta", name: "meta",

34
src/collections/Teams.ts Normal file
View File

@ -0,0 +1,34 @@
import type { CollectionConfig } from "payload";
import { lexicalEditor } from "@payloadcms/richtext-lexical";
export const Teams: CollectionConfig = {
slug: "teams",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "role",
type: "text",
required: true,
},
{
name: "img",
label: "Image",
type: "upload",
relationTo: "media",
required: true,
},
{
name: "biography",
type: "richText",
editor: lexicalEditor({}),
},
],
admin: {
hideAPIURL: true,
useAsTitle: "name",
},
};

View File

@ -10,10 +10,10 @@ export interface BeforeFooterBlockProps {
export function BeforeFooterBlock({ title, description, buttonText }: BeforeFooterBlockProps) { export function BeforeFooterBlock({ title, description, buttonText }: BeforeFooterBlockProps) {
return ( return (
<section <section
className={`page-section text-white text-center scrollSpysection bg-dark-1 light-content bg-scroll`} className={`page-section text-white text-center scrollSpysection bg-dark-1 light-content bg-scroll relative`}
id="about" id="about"
> >
<div className="container mx-auto px-6"> <div className="container mx-auto px-6 z-50">
<h2 className="text-3xl font-bold mb-4">{title}</h2> <h2 className="text-3xl font-bold mb-4">{title}</h2>
<p className="text-lg mb-6">{description}</p> <p className="text-lg mb-6">{description}</p>
{!!buttonText && ( {!!buttonText && (

View File

@ -0,0 +1,39 @@
import { CardTeam } from "@/components/Teams/CardTeam";
type Team = {
id: number;
name: string;
role: string;
img: { url: string; alt: string };
biography: string;
};
export interface OurTeamProps {
team: Team[];
}
export function OurTeamBlock({ team }: OurTeamProps) {
return (
<section className="page-section bg-gray-light-1 relative">
{/* Decoration Circles */}
<div className="decoration-12" />
<div className="decoration-13" />
{/* End Decoration Circles */}
<div className="container mx-auto px-6 text-center">
<h2 className="text-4xl font-semibold text-gray-800 mb-8">Our Team</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
{team.map((member, idx) => (
<CardTeam
key={idx}
data={{
name: member.name,
img: member.img.url,
role: member.role,
}}
/>
))}
</div>
</div>
</section>
);
}

View File

@ -3,10 +3,12 @@ import React, { Fragment } from "react";
import type { Page } from "@/payload-types"; import type { Page } from "@/payload-types";
import { ContentBlock } from "./Content"; import { ContentBlock } from "./Content";
import { BeforeFooterBlock } from "./BeforeFooter"; import { BeforeFooterBlock } from "./BeforeFooter";
import { OurTeamBlock } from "./OurTeam";
const blockComponents = { const blockComponents = {
contentBlock: ContentBlock, contentBlock: ContentBlock,
beforeFooterBlock: BeforeFooterBlock, beforeFooterBlock: BeforeFooterBlock,
ourTeamBlock: OurTeamBlock,
}; };
export const RenderBlocks: React.FC<{ export const RenderBlocks: React.FC<{

View File

@ -30,9 +30,9 @@ export default async function Page({ slug }: PageProps) {
</div> </div>
)} )}
{!page?.heroImg?.url && ( {!page?.heroImg?.url && (
<div className="absolute top-0 left-0 w-full h-full opacity-003"> <div className="absolute top-0 left-0 w-full h-full opacity-20">
<Image <Image
src="/assets/images/demo-fancy/bg-shape-1.svg" src="/assets/images/hero-default.webp"
width="0" width="0"
height="0" height="0"
sizes="100vw" sizes="100vw"

View File

@ -0,0 +1,27 @@
import Image from "next/image";
export interface CardTeamProps {
data: {
name: string;
role: string;
img: string;
};
}
export function CardTeam({ data }: CardTeamProps) {
return (
<div className="bg-white p-6 rounded-lg shadow-md">
<Image
src={data.img}
alt={data.name}
width={80}
height={80}
className="rounded-full object-cover mx-auto"
style={{ width: "80px", height: "80px" }}
/>
<h3 className="mt-4 text-lg font-medium text-gray-900">{data.name}</h3>
<p className="text-gray-600">{data.role}</p>
<button className="bg-slate-400 rounded-full p-2 font-semibold text-slate-50 text-xs">BIOGRAPHY</button>
</div>
);
}

View File

@ -15,6 +15,7 @@ export interface Config {
media: Media; media: Media;
blogs: Blog; blogs: Blog;
pages: Page; pages: Page;
teams: Team;
forms: Form; forms: Form;
'form-submissions': FormSubmission; 'form-submissions': FormSubmission;
'payload-locked-documents': PayloadLockedDocument; 'payload-locked-documents': PayloadLockedDocument;
@ -27,6 +28,7 @@ export interface Config {
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>; pages: PagesSelect<false> | PagesSelect<true>;
teams: TeamsSelect<false> | TeamsSelect<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>;
@ -168,6 +170,12 @@ export interface Page {
blockName?: string | null; blockName?: string | null;
blockType: 'beforeFooterBlock'; blockType: 'beforeFooterBlock';
} }
| {
team?: (number | Team)[] | null;
id?: string | null;
blockName?: string | null;
blockType: 'ourTeamBlock';
}
)[] )[]
| null; | null;
meta?: { meta?: {
@ -178,6 +186,33 @@ export interface Page {
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "teams".
*/
export interface Team {
id: number;
name: string;
role: string;
img: number | Media;
biography?: {
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;
} | 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".
@ -371,6 +406,10 @@ export interface PayloadLockedDocument {
relationTo: 'pages'; relationTo: 'pages';
value: number | Page; value: number | Page;
} | null) } | null)
| ({
relationTo: 'teams';
value: number | Team;
} | null)
| ({ | ({
relationTo: 'forms'; relationTo: 'forms';
value: number | Form; value: number | Form;
@ -494,6 +533,13 @@ export interface PagesSelect<T extends boolean = true> {
id?: T; id?: T;
blockName?: T; blockName?: T;
}; };
ourTeamBlock?:
| T
| {
team?: T;
id?: T;
blockName?: T;
};
}; };
meta?: meta?:
| T | T
@ -505,6 +551,18 @@ export interface PagesSelect<T extends boolean = true> {
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "teams_select".
*/
export interface TeamsSelect<T extends boolean = true> {
name?: T;
role?: T;
img?: T;
biography?: 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".

View File

@ -11,6 +11,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 { Pages } from "@/collections/Pages";
import { Teams } from "@/collections/Teams";
import { Users } from "@/collections/Users"; import { Users } from "@/collections/Users";
import { import {
BoldFeature, BoldFeature,
@ -46,7 +47,7 @@ export default buildConfig({
}, },
theme: "dark", theme: "dark",
}, },
collections: [Users, Media, Blogs, Pages], collections: [Users, Media, Blogs, Pages, Teams],
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"),