feat: implement Testimonials section with dynamic data fetching and UI integration
This commit is contained in:
@@ -1,87 +1,64 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { QuoteIcon } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
import { QuoteIcon } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||||
|
import { formatCMSImageDataToMedia } from 'apps/landing/src/lib/format';
|
||||||
|
import { TestimonialsSection } from 'apps/landing/src/payload-types';
|
||||||
import { motion, useInView } from 'framer-motion';
|
import { motion, useInView } from 'framer-motion';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
export function Testimonials() {
|
export function Testimonials(props: TestimonialsSection) {
|
||||||
const ref = useRef(null);
|
const { title, subtitle, items, stats, joinTitle, joinText } = props;
|
||||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
|
||||||
|
|
||||||
const testimonials = [
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
{
|
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||||
quote:
|
|
||||||
'Saya yang tadinya tidak mengerti apa-apa tentang programming, sekarang bisa membuat website sendiri dengan mudah. Terima kasih IMPHNEN!',
|
|
||||||
name: 'Budi Santoso',
|
|
||||||
role: 'Web Developer Pemula',
|
|
||||||
avatar: '/placeholder.svg?height=64&width=64',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quote:
|
|
||||||
'Komunitas yang sangat supportif! Setiap pertanyaan selalu dijawab dengan cepat dan jelas. Diskusi programnya mudah dipahami.',
|
|
||||||
name: 'Anita Ratna',
|
|
||||||
role: 'Mobile App Developer',
|
|
||||||
avatar: '/placeholder.svg?height=64&width=64',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
quote:
|
|
||||||
'Server Discord IMPHNEN adalah tempat belajar terbaik untuk programmer pemula seperti saya. Materinya lengkap dan komunitasnya sangat membantu!',
|
|
||||||
name: 'Dedi Permana',
|
|
||||||
role: 'Data Scientist',
|
|
||||||
avatar: '/placeholder.svg?height=64&width=64',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const containerVariants = {
|
const containerVariants = {
|
||||||
hidden: { opacity: 0 },
|
hidden: { opacity: 0 },
|
||||||
visible: {
|
visible: { opacity: 1, transition: { staggerChildren: 0.1 } },
|
||||||
opacity: 1,
|
|
||||||
transition: {
|
|
||||||
staggerChildren: 0.1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const itemVariants = {
|
const itemVariants = {
|
||||||
hidden: { y: 20, opacity: 0 },
|
hidden: { y: 20, opacity: 0 },
|
||||||
visible: {
|
visible: { y: 0, opacity: 1, transition: { duration: 0.5 } },
|
||||||
y: 0,
|
|
||||||
opacity: 1,
|
|
||||||
transition: { duration: 0.5 },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="testimoni"
|
id="testimoni"
|
||||||
className="w-full py-20 md:py-32 bg-muted relative overflow-hidden"
|
className="w-full py-20 md:py-32 bg-muted relative overflow-hidden"
|
||||||
|
ref={ref}
|
||||||
>
|
>
|
||||||
{/* Background Elements */}
|
|
||||||
<div className="absolute inset-0 -z-10">
|
<div className="absolute inset-0 -z-10">
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,rgba(59,130,246,0.1),transparent_50%)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,rgba(59,130,246,0.1),transparent_50%)]" />
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom,rgba(96,165,250,0.1),transparent_50%)]" />
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_bottom,rgba(96,165,250,0.1),transparent_50%)]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="container px-4 md:px-6" ref={ref}>
|
<div className="container px-4 md:px-6">
|
||||||
<div className="flex flex-col items-center justify-center space-y-4 text-center mb-16">
|
<motion.div
|
||||||
<motion.div
|
className="flex flex-col items-center justify-center space-y-4 text-center mb-16"
|
||||||
className="space-y-2"
|
initial={{ opacity: 0, y: 20 }}
|
||||||
initial={{ opacity: 0, y: 20 }}
|
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
||||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
transition={{ duration: 0.5 }}
|
||||||
transition={{ duration: 0.5 }}
|
>
|
||||||
>
|
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl lg:text-5xl">
|
||||||
<h2 className="text-3xl font-bold tracking-tighter md:text-4xl/tight lg:text-5xl">
|
{title.split(' ').map((word, i) =>
|
||||||
Testimoni{' '}
|
i === title.split(' ').length - 1 ? (
|
||||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
<span
|
||||||
Member
|
key={i}
|
||||||
</span>
|
className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400"
|
||||||
</h2>
|
>
|
||||||
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
{word}
|
||||||
Apa kata mereka yang telah bergabung dengan komunitas IMPHNEN?
|
</span>
|
||||||
</p>
|
) : (
|
||||||
</motion.div>
|
<span key={i}>{word} </span>
|
||||||
</div>
|
)
|
||||||
|
)}
|
||||||
|
</h2>
|
||||||
|
<p className="max-w-[800px] mx-auto text-muted-foreground md:text-lg">
|
||||||
|
{subtitle}
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="grid gap-8 md:grid-cols-3"
|
className="grid gap-8 md:grid-cols-3"
|
||||||
@@ -89,98 +66,79 @@ export function Testimonials() {
|
|||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate={isInView ? 'visible' : 'hidden'}
|
animate={isInView ? 'visible' : 'hidden'}
|
||||||
>
|
>
|
||||||
{testimonials.map((testimonial, index) => (
|
{items?.map((t, idx) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={index}
|
key={idx}
|
||||||
className="group relative overflow-hidden rounded-xl border bg-background p-6 transition-all hover:shadow-lg"
|
className="group relative overflow-hidden rounded-xl border bg-background p-6 transition-all hover:shadow-lg"
|
||||||
variants={itemVariants}
|
variants={itemVariants}
|
||||||
>
|
>
|
||||||
<div className="absolute top-6 right-6 text-primary/20 group-hover:text-primary/40 transition-colors">
|
<div className="absolute top-6 right-6 text-primary/20 group-hover:text-primary/40 transition-colors">
|
||||||
<QuoteIcon className="h-8 w-8" />
|
<QuoteIcon className="h-8 w-8" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative z-10">
|
<div className="relative z-10">
|
||||||
<p className="mb-6 text-muted-foreground italic">
|
<p className="mb-6 text-muted-foreground italic">
|
||||||
“{testimonial.quote}”
|
“{t.quote}”
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="relative h-12 w-12 overflow-hidden rounded-full border-2 border-primary/20">
|
<div className="relative h-12 w-12 overflow-hidden rounded-full border-2 border-primary/20">
|
||||||
<Image
|
{(() => {
|
||||||
src={testimonial.avatar || '/placeholder.svg'}
|
const media = formatCMSImageDataToMedia(t.avatar);
|
||||||
alt={testimonial.name}
|
if (!media) return null;
|
||||||
width={48}
|
return (
|
||||||
height={48}
|
<Image
|
||||||
className="object-cover"
|
src={media.url!}
|
||||||
/>
|
alt={media.alt}
|
||||||
|
width={600}
|
||||||
|
height={500}
|
||||||
|
className="object-cover"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-bold">{testimonial.name}</h4>
|
<h4 className="font-bold">{t.name}</h4>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">{t.role}</p>
|
||||||
{testimonial.role}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute -bottom-1 -left-1 w-20 h-20 bg-gradient-to-tr from-primary/10 to-transparent rounded-tr-full opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
<div className="absolute -bottom-1 -left-1 w-20 h-20 bg-gradient-to-tr from-primary/10 to-transparent rounded-tr-full opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Testimonial Stats */}
|
|
||||||
<motion.div
|
<motion.div
|
||||||
className="mt-20 rounded-xl overflow-hidden border bg-background/50 backdrop-blur-sm p-8 md:p-12"
|
className="mt-20 rounded-xl overflow-hidden border bg-background/50 backdrop-blur-sm p-8 md:p-12"
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
||||||
transition={{ duration: 0.5, delay: 0.3 }}
|
transition={{ duration: 0.5, delay: 0.3 }}
|
||||||
>
|
>
|
||||||
<div className="grid md:grid-cols-2 gap-8 items-center">
|
<div className="grid md:grid-cols-2 gap-8 items-center">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-2xl md:text-3xl font-bold mb-4">
|
<h3 className="text-2xl md:text-3xl font-bold mb-4">
|
||||||
Bergabunglah dengan{' '}
|
{joinTitle.split(' ').map((word, i) =>
|
||||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
i === 1 ? (
|
||||||
10,000+
|
<span
|
||||||
</span>{' '}
|
key={i}
|
||||||
programmer Indonesia lainnya
|
className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400"
|
||||||
|
>
|
||||||
|
{word}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span key={i}>{word} </span>
|
||||||
|
)
|
||||||
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">{joinText}</p>
|
||||||
Komunitas kami terus berkembang dengan programmer dari berbagai
|
|
||||||
latar belakang dan tingkat keahlian. Bersama-sama, kita belajar,
|
|
||||||
berbagi, dan tumbuh sebagai profesional.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div className="rounded-lg border p-4 text-center">
|
{stats?.map((s, idx) => (
|
||||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
<div key={idx} className="rounded-lg border p-4 text-center">
|
||||||
98%
|
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||||
|
{s.value}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-muted-foreground">{s.label}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">
|
))}
|
||||||
Tingkat Kemalasan
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-lg border p-4 text-center">
|
|
||||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
|
||||||
4.9/5
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
Rating Drama
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-lg border p-4 text-center">
|
|
||||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
|
||||||
85%
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
Mendapat Pekerjaan
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="rounded-lg border p-4 text-center">
|
|
||||||
<div className="text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
|
||||||
24/7
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-muted-foreground">Yapping</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { getGlobalsCommunitiesSection } from '../../services/get-globals-communi
|
|||||||
import { getGlobalsFeaturesSection } from '../../services/get-globals-features-section';
|
import { getGlobalsFeaturesSection } from '../../services/get-globals-features-section';
|
||||||
import { getGlobalsHeroSection } from '../../services/get-globals-hero-section';
|
import { getGlobalsHeroSection } from '../../services/get-globals-hero-section';
|
||||||
import { getGlobalsLearningResourcesSection } from '../../services/get-globals-learning-resources-section';
|
import { getGlobalsLearningResourcesSection } from '../../services/get-globals-learning-resources-section';
|
||||||
|
import { getGlobalsTestimonialsSection } from '../../services/get-globals-testimonials-section';
|
||||||
import { CallToAction } from './_components/call-to-action';
|
import { CallToAction } from './_components/call-to-action';
|
||||||
import { Community } from './_components/community';
|
import { Community } from './_components/community';
|
||||||
import { Features } from './_components/features';
|
import { Features } from './_components/features';
|
||||||
@@ -12,13 +13,19 @@ import { Testimonials } from './_components/testimonials';
|
|||||||
export const revalidate = 10; // Seconds
|
export const revalidate = 10; // Seconds
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const [heroData, featuresData, communitiesData, learningResourcesData] =
|
const [
|
||||||
await Promise.all([
|
heroData,
|
||||||
getGlobalsHeroSection(),
|
featuresData,
|
||||||
getGlobalsFeaturesSection(),
|
communitiesData,
|
||||||
getGlobalsCommunitiesSection(),
|
learningResourcesData,
|
||||||
getGlobalsLearningResourcesSection(),
|
testimonialsData,
|
||||||
]);
|
] = await Promise.all([
|
||||||
|
getGlobalsHeroSection(),
|
||||||
|
getGlobalsFeaturesSection(),
|
||||||
|
getGlobalsCommunitiesSection(),
|
||||||
|
getGlobalsLearningResourcesSection(),
|
||||||
|
getGlobalsTestimonialsSection(),
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -26,7 +33,7 @@ export default async function Page() {
|
|||||||
<Features {...featuresData} />
|
<Features {...featuresData} />
|
||||||
<Community {...communitiesData} />
|
<Community {...communitiesData} />
|
||||||
<LearningResources {...learningResourcesData} />
|
<LearningResources {...learningResourcesData} />
|
||||||
<Testimonials />
|
<Testimonials {...testimonialsData} />
|
||||||
<CallToAction />
|
<CallToAction />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { GlobalConfig } from 'payload';
|
||||||
|
|
||||||
|
export const TestimonialsSection: GlobalConfig = {
|
||||||
|
slug: 'testimonials-section',
|
||||||
|
label: 'Testimonials Section',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
label: 'Section Title',
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: 'Testimoni Member',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'subtitle',
|
||||||
|
label: 'Section Subtitle',
|
||||||
|
type: 'textarea',
|
||||||
|
defaultValue:
|
||||||
|
'Apa kata mereka yang telah bergabung dengan komunitas IMPHNEN?',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'items',
|
||||||
|
label: 'Testimonials Items',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'quote', type: 'textarea', label: 'Quote', required: true },
|
||||||
|
{ name: 'name', type: 'text', label: 'Name', required: true },
|
||||||
|
{ name: 'role', type: 'text', label: 'Role', required: true },
|
||||||
|
{
|
||||||
|
name: 'avatar',
|
||||||
|
type: 'upload',
|
||||||
|
label: 'Avatar',
|
||||||
|
relationTo: 'media',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultValue: [
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
'Saya yang tadinya tidak mengerti apa-apa tentang programming, sekarang bisa membuat website sendiri dengan mudah. Terima kasih IMPHNEN!',
|
||||||
|
name: 'Budi Santoso',
|
||||||
|
role: 'Web Developer Pemula',
|
||||||
|
avatar: { id: '', relationTo: 'media' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
'Komunitas yang sangat supportif! Setiap pertanyaan selalu dijawab dengan cepat dan jelas. Diskusi programnya mudah dipahami.',
|
||||||
|
name: 'Anita Ratna',
|
||||||
|
role: 'Mobile App Developer',
|
||||||
|
avatar: { id: '', relationTo: 'media' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
'Server Discord IMPHNEN adalah tempat belajar terbaik untuk programmer pemula seperti saya. Materinya lengkap dan komunitasnya sangat membantu!',
|
||||||
|
name: 'Dedi Permana',
|
||||||
|
role: 'Data Scientist',
|
||||||
|
avatar: { id: '', relationTo: 'media' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'stats',
|
||||||
|
label: 'Statistics',
|
||||||
|
type: 'array',
|
||||||
|
fields: [
|
||||||
|
{ name: 'value', type: 'text', label: 'Value', required: true },
|
||||||
|
{ name: 'label', type: 'text', label: 'Label', required: true },
|
||||||
|
],
|
||||||
|
defaultValue: [
|
||||||
|
{ value: '98%', label: 'Tingkat Kemalasan' },
|
||||||
|
{ value: '4.9/5', label: 'Rating Drama' },
|
||||||
|
{ value: '85%', label: 'Mendapat Pekerjaan' },
|
||||||
|
{ value: '24/7', label: 'Yapping' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'joinTitle',
|
||||||
|
label: 'Join Section Title',
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: 'Bergabunglah dengan 10,000+ programmer Indonesia lainnya',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'joinText',
|
||||||
|
label: 'Join Section Text',
|
||||||
|
type: 'textarea',
|
||||||
|
defaultValue:
|
||||||
|
'Komunitas kami terus berkembang dengan programmer dari berbagai latar belakang dan tingkat keahlian. Bersama-sama, kita belajar, berbagi, dan tumbuh sebagai profesional.',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -89,12 +89,14 @@ export interface Config {
|
|||||||
'features-section': FeaturesSection;
|
'features-section': FeaturesSection;
|
||||||
'communities-section': CommunitiesSection;
|
'communities-section': CommunitiesSection;
|
||||||
'learning-resources-section': LearningResourcesSection;
|
'learning-resources-section': LearningResourcesSection;
|
||||||
|
'testimonials-section': TestimonialsSection;
|
||||||
};
|
};
|
||||||
globalsSelect: {
|
globalsSelect: {
|
||||||
'hero-section': HeroSectionSelect<false> | HeroSectionSelect<true>;
|
'hero-section': HeroSectionSelect<false> | HeroSectionSelect<true>;
|
||||||
'features-section': FeaturesSectionSelect<false> | FeaturesSectionSelect<true>;
|
'features-section': FeaturesSectionSelect<false> | FeaturesSectionSelect<true>;
|
||||||
'communities-section': CommunitiesSectionSelect<false> | CommunitiesSectionSelect<true>;
|
'communities-section': CommunitiesSectionSelect<false> | CommunitiesSectionSelect<true>;
|
||||||
'learning-resources-section': LearningResourcesSectionSelect<false> | LearningResourcesSectionSelect<true>;
|
'learning-resources-section': LearningResourcesSectionSelect<false> | LearningResourcesSectionSelect<true>;
|
||||||
|
'testimonials-section': TestimonialsSectionSelect<false> | TestimonialsSectionSelect<true>;
|
||||||
};
|
};
|
||||||
locale: null;
|
locale: null;
|
||||||
user: User & {
|
user: User & {
|
||||||
@@ -377,6 +379,35 @@ export interface LearningResourcesSection {
|
|||||||
updatedAt?: string | null;
|
updatedAt?: string | null;
|
||||||
createdAt?: string | null;
|
createdAt?: string | null;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "testimonials-section".
|
||||||
|
*/
|
||||||
|
export interface TestimonialsSection {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
items?:
|
||||||
|
| {
|
||||||
|
quote: string;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
avatar: number | Media;
|
||||||
|
id?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
stats?:
|
||||||
|
| {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
id?: string | null;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
joinTitle: string;
|
||||||
|
joinText: string;
|
||||||
|
updatedAt?: string | null;
|
||||||
|
createdAt?: string | null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "hero-section_select".
|
* via the `definition` "hero-section_select".
|
||||||
@@ -483,6 +514,35 @@ export interface LearningResourcesSectionSelect<T extends boolean = true> {
|
|||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
globalType?: T;
|
globalType?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "testimonials-section_select".
|
||||||
|
*/
|
||||||
|
export interface TestimonialsSectionSelect<T extends boolean = true> {
|
||||||
|
title?: T;
|
||||||
|
subtitle?: T;
|
||||||
|
items?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
quote?: T;
|
||||||
|
name?: T;
|
||||||
|
role?: T;
|
||||||
|
avatar?: T;
|
||||||
|
id?: T;
|
||||||
|
};
|
||||||
|
stats?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
value?: T;
|
||||||
|
label?: T;
|
||||||
|
id?: T;
|
||||||
|
};
|
||||||
|
joinTitle?: T;
|
||||||
|
joinText?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
globalType?: T;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "auth".
|
* via the `definition` "auth".
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { FeaturesSection } from './collections/FeaturesSection';
|
|||||||
import { HeroSection } from './collections/HeroSection';
|
import { HeroSection } from './collections/HeroSection';
|
||||||
import { LearningResourcesSection } from './collections/LearningResourcesSection';
|
import { LearningResourcesSection } from './collections/LearningResourcesSection';
|
||||||
import { Media } from './collections/Media';
|
import { Media } from './collections/Media';
|
||||||
|
import { TestimonialsSection } from './collections/TestimonialsSection';
|
||||||
import { Users } from './collections/Users';
|
import { Users } from './collections/Users';
|
||||||
|
|
||||||
const filename = fileURLToPath(import.meta.url);
|
const filename = fileURLToPath(import.meta.url);
|
||||||
@@ -37,6 +38,7 @@ export default buildConfig({
|
|||||||
FeaturesSection,
|
FeaturesSection,
|
||||||
CommunitiesSection,
|
CommunitiesSection,
|
||||||
LearningResourcesSection,
|
LearningResourcesSection,
|
||||||
|
TestimonialsSection,
|
||||||
],
|
],
|
||||||
editor: lexicalEditor(),
|
editor: lexicalEditor(),
|
||||||
secret: process.env.CMS_SECRET || '',
|
secret: process.env.CMS_SECRET || '',
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { payload } from '../lib/payload';
|
||||||
|
|
||||||
|
export async function getGlobalsTestimonialsSection() {
|
||||||
|
return await payload.findGlobal({
|
||||||
|
slug: 'testimonials-section',
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user