feat: implement CallToAction section with dynamic data fetching and UI integration
This commit is contained in:
@@ -1,10 +1,21 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Button } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
import { Button } from '@imphnen-frontend-service/shadcn-ui/atoms';
|
||||||
|
import { CallToActionSection } from 'apps/landing/src/payload-types';
|
||||||
import { motion, useInView } from 'framer-motion';
|
import { motion, useInView } from 'framer-motion';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
export function CallToAction() {
|
export function CallToAction(props: CallToActionSection) {
|
||||||
|
const {
|
||||||
|
title,
|
||||||
|
highlightedTitle,
|
||||||
|
subtitle,
|
||||||
|
primaryButtonLabel,
|
||||||
|
primaryButtonLink,
|
||||||
|
secondaryButtonLabel,
|
||||||
|
secondaryButtonLink,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
const isInView = useInView(ref, { once: true, amount: 0.2 });
|
||||||
|
|
||||||
@@ -28,30 +39,30 @@ export function CallToAction() {
|
|||||||
|
|
||||||
<div className="relative z-10 text-center">
|
<div className="relative z-10 text-center">
|
||||||
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-6">
|
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-6">
|
||||||
Siap Menjadi{' '}
|
{title}{' '}
|
||||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
<span className="bg-clip-text text-transparent bg-gradient-to-r from-primary to-blue-400">
|
||||||
Programmer Handal?
|
{highlightedTitle}
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-muted-foreground mb-8 max-w-2xl mx-auto">
|
<p className="text-lg text-muted-foreground mb-8 max-w-2xl mx-auto">
|
||||||
Bergabunglah dengan komunitas IMPHNEN sekarang dan mulai
|
{subtitle}
|
||||||
perjalanan programming mu dengan cara yang menyenangkan!
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
className="bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90
|
className="bg-gradient-to-r from-primary to-blue-400 hover:from-primary/90 hover:to-blue-400/90 font-bold text-black hover:text-white cursor-pointer"
|
||||||
font-bold text-black hover:text-white cursor-pointer"
|
onClick={() => window.open(primaryButtonLink, '_blank')}
|
||||||
>
|
>
|
||||||
Gabung Discord
|
{primaryButtonLabel}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="border-primary hover:bg-primary/10"
|
className="border-primary hover:bg-primary/10"
|
||||||
|
onClick={() => window.open(secondaryButtonLink, '_blank')}
|
||||||
>
|
>
|
||||||
Join Facebook Group
|
{secondaryButtonLabel}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { getGlobalsCallToActionSection } from '../../services/get-globals-call-to-action-section';
|
||||||
import { getGlobalsCommunitiesSection } from '../../services/get-globals-communitues-section';
|
import { getGlobalsCommunitiesSection } from '../../services/get-globals-communitues-section';
|
||||||
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';
|
||||||
@@ -19,12 +20,14 @@ export default async function Page() {
|
|||||||
communitiesData,
|
communitiesData,
|
||||||
learningResourcesData,
|
learningResourcesData,
|
||||||
testimonialsData,
|
testimonialsData,
|
||||||
|
callToActionData,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
getGlobalsHeroSection(),
|
getGlobalsHeroSection(),
|
||||||
getGlobalsFeaturesSection(),
|
getGlobalsFeaturesSection(),
|
||||||
getGlobalsCommunitiesSection(),
|
getGlobalsCommunitiesSection(),
|
||||||
getGlobalsLearningResourcesSection(),
|
getGlobalsLearningResourcesSection(),
|
||||||
getGlobalsTestimonialsSection(),
|
getGlobalsTestimonialsSection(),
|
||||||
|
getGlobalsCallToActionSection(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -34,7 +37,7 @@ export default async function Page() {
|
|||||||
<Community {...communitiesData} />
|
<Community {...communitiesData} />
|
||||||
<LearningResources {...learningResourcesData} />
|
<LearningResources {...learningResourcesData} />
|
||||||
<Testimonials {...testimonialsData} />
|
<Testimonials {...testimonialsData} />
|
||||||
<CallToAction />
|
<CallToAction {...callToActionData} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { GlobalConfig } from 'payload';
|
||||||
|
|
||||||
|
export const CallToActionSection: GlobalConfig = {
|
||||||
|
slug: 'call-to-action-section',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'Siap Menjadi',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'highlightedTitle',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'Programmer Handal?',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'subtitle',
|
||||||
|
type: 'textarea',
|
||||||
|
required: true,
|
||||||
|
defaultValue:
|
||||||
|
'Bergabunglah dengan komunitas IMPHNEN sekarang dan mulai perjalanan programming mu dengan cara yang menyenangkan!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'primaryButtonLabel',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'Gabung Discord',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'primaryButtonLink',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'https://discord.gg/imphnen',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'secondaryButtonLabel',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'Join Facebook Group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'secondaryButtonLink',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
defaultValue: 'https://facebook.com/groups/programmerhandal',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -15,7 +15,7 @@ export const CommunitiesSection: GlobalConfig = {
|
|||||||
description:
|
description:
|
||||||
'Bergabunglah dengan grup Facebook kami untuk diskusi santai dan berbagi artikel menarik.',
|
'Bergabunglah dengan grup Facebook kami untuk diskusi santai dan berbagi artikel menarik.',
|
||||||
buttonText: 'Gabung Sekarang',
|
buttonText: 'Gabung Sekarang',
|
||||||
buttonLink: 'https://facebook.com/groups/1032515944638255',
|
buttonLink: 'https://facebook.com/groups/programmerhandal',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
iconName: 'tabler:brand-instagram',
|
iconName: 'tabler:brand-instagram',
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const HeroSection: GlobalConfig = {
|
|||||||
label: 'Primary Button URL',
|
label: 'Primary Button URL',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
required: true,
|
required: true,
|
||||||
defaultValue: 'https://web.facebook.com/groups/1032515944638255',
|
defaultValue: 'https://facebook.com/groups/programmerhandal',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'secondaryLabel',
|
name: 'secondaryLabel',
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export interface Config {
|
|||||||
'communities-section': CommunitiesSection;
|
'communities-section': CommunitiesSection;
|
||||||
'learning-resources-section': LearningResourcesSection;
|
'learning-resources-section': LearningResourcesSection;
|
||||||
'testimonials-section': TestimonialsSection;
|
'testimonials-section': TestimonialsSection;
|
||||||
|
'call-to-action-section': CallToActionSection;
|
||||||
};
|
};
|
||||||
globalsSelect: {
|
globalsSelect: {
|
||||||
'hero-section': HeroSectionSelect<false> | HeroSectionSelect<true>;
|
'hero-section': HeroSectionSelect<false> | HeroSectionSelect<true>;
|
||||||
@@ -97,6 +98,7 @@ export interface Config {
|
|||||||
'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>;
|
'testimonials-section': TestimonialsSectionSelect<false> | TestimonialsSectionSelect<true>;
|
||||||
|
'call-to-action-section': CallToActionSectionSelect<false> | CallToActionSectionSelect<true>;
|
||||||
};
|
};
|
||||||
locale: null;
|
locale: null;
|
||||||
user: User & {
|
user: User & {
|
||||||
@@ -408,6 +410,22 @@ export interface TestimonialsSection {
|
|||||||
updatedAt?: string | null;
|
updatedAt?: string | null;
|
||||||
createdAt?: string | null;
|
createdAt?: string | null;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "call-to-action-section".
|
||||||
|
*/
|
||||||
|
export interface CallToActionSection {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
highlightedTitle: string;
|
||||||
|
subtitle: string;
|
||||||
|
primaryButtonLabel: string;
|
||||||
|
primaryButtonLink: string;
|
||||||
|
secondaryButtonLabel: string;
|
||||||
|
secondaryButtonLink: 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".
|
||||||
@@ -543,6 +561,22 @@ export interface TestimonialsSectionSelect<T extends boolean = true> {
|
|||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
globalType?: T;
|
globalType?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "call-to-action-section_select".
|
||||||
|
*/
|
||||||
|
export interface CallToActionSectionSelect<T extends boolean = true> {
|
||||||
|
title?: T;
|
||||||
|
highlightedTitle?: T;
|
||||||
|
subtitle?: T;
|
||||||
|
primaryButtonLabel?: T;
|
||||||
|
primaryButtonLink?: T;
|
||||||
|
secondaryButtonLabel?: T;
|
||||||
|
secondaryButtonLink?: 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".
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { buildConfig } from 'payload';
|
|||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
import { CallToActionSection } from './collections/CallToActionSection';
|
||||||
import { CommunitiesSection } from './collections/CommunitiesSection';
|
import { CommunitiesSection } from './collections/CommunitiesSection';
|
||||||
import { FeaturesSection } from './collections/FeaturesSection';
|
import { FeaturesSection } from './collections/FeaturesSection';
|
||||||
import { HeroSection } from './collections/HeroSection';
|
import { HeroSection } from './collections/HeroSection';
|
||||||
@@ -39,6 +40,7 @@ export default buildConfig({
|
|||||||
CommunitiesSection,
|
CommunitiesSection,
|
||||||
LearningResourcesSection,
|
LearningResourcesSection,
|
||||||
TestimonialsSection,
|
TestimonialsSection,
|
||||||
|
CallToActionSection
|
||||||
],
|
],
|
||||||
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 getGlobalsCallToActionSection() {
|
||||||
|
return await payload.findGlobal({
|
||||||
|
slug: 'call-to-action-section',
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user