From 39a57b4fed0c3502e5003e961789235085ccdede Mon Sep 17 00:00:00 2001 From: ArraysID Date: Sat, 10 May 2025 04:08:37 +0700 Subject: [PATCH] feat: add FeaturesSection global configuration and integrate with Features component --- .../app/(frontend)/_components/features.tsx | 64 ++++++++--------- apps/landing/src/app/(frontend)/page.tsx | 4 +- .../src/collections/FeaturesSection.ts | 72 +++++++++++++++++++ apps/landing/src/payload-types.ts | 40 +++++++++++ apps/landing/src/payload.config.ts | 3 +- .../get-globals-features-section.ts | 7 ++ 6 files changed, 152 insertions(+), 38 deletions(-) create mode 100644 apps/landing/src/collections/FeaturesSection.ts create mode 100644 apps/landing/src/repositories/get-globals-features-section.ts diff --git a/apps/landing/src/app/(frontend)/_components/features.tsx b/apps/landing/src/app/(frontend)/_components/features.tsx index 40ed3e1..20c82e8 100644 --- a/apps/landing/src/app/(frontend)/_components/features.tsx +++ b/apps/landing/src/app/(frontend)/_components/features.tsx @@ -6,40 +6,22 @@ import { LaptopIcon, UsersIcon, } from '@imphnen-frontend-service/shadcn-ui/atoms'; +import { FeaturesSection } from 'apps/landing/src/payload-types'; import { motion, useInView } from 'framer-motion'; import { useRef } from 'react'; -export function Features() { +export function Features(props: FeaturesSection) { + const { heading, subheading, features } = props; + + const featuresFormatted = features?.map((f) => ({ + icon: IconMapper(String(f.icon)), + title: f.title, + description: f.description, + })); + const ref = useRef(null); const isInView = useInView(ref, { once: true, amount: 0.2 }); - const features = [ - { - icon: , - title: 'Belajar Tanpa Koding', - description: - 'Pelajari konsep programming dengan cara yang mudah dipahami tanpa harus menulis kode yang rumit.', - }, - { - icon: , - title: 'Komunitas Supportif', - description: - 'Bergabunglah dengan komunitas programmer Indonesia yang siap membantu dan berbagi pengalaman.', - }, - { - icon: , - title: 'Tutorial Interaktif', - description: - 'Akses tutorial interaktif yang membuat konsep programming lebih mudah untuk dipahami.', - }, - { - icon: , - title: 'Proyek Praktis', - description: - 'Terapkan pengetahuan Anda dalam proyek nyata dengan panduan langkah demi langkah.', - }, - ]; - const containerVariants = { hidden: { opacity: 0 }, visible: { @@ -64,7 +46,6 @@ export function Features() { id="fitur" className="w-full py-20 md:py-32 relative overflow-hidden" > - {/* Background Elements */}
@@ -82,14 +63,10 @@ export function Features() { Fitur Unggulan

- Belajar programming dengan{' '} - - cara yang lebih baik - + {heading}

- IMPHNEN hadir dengan berbagai fitur untuk membantu kamu menjadi - programmer handal tanpa harus pusing dengan coding. + {subheading}

@@ -100,7 +77,7 @@ export function Features() { initial="hidden" animate={isInView ? 'visible' : 'hidden'} > - {features.map((feature, index) => ( + {featuresFormatted?.map((feature, index) => ( ); } + +function IconMapper(name: string) { + switch (name) { + case 'LaptopIcon': + return ; + case 'UsersIcon': + return ; + case 'BookOpenIcon': + return ; + case 'CodeIcon': + return ; + default: + return null; + } +} diff --git a/apps/landing/src/app/(frontend)/page.tsx b/apps/landing/src/app/(frontend)/page.tsx index ef7edd4..c0f9dfa 100644 --- a/apps/landing/src/app/(frontend)/page.tsx +++ b/apps/landing/src/app/(frontend)/page.tsx @@ -1,3 +1,4 @@ +import { getGlobalsFeaturesSection } from '../../repositories/get-globals-features-section'; import { getGlobalsHeroSection } from '../../repositories/get-globals-hero-section'; import { CallToAction } from './_components/call-to-action'; import { Community } from './_components/community'; @@ -10,13 +11,14 @@ import { Testimonials } from './_components/testimonials'; export default async function Page() { const heroData = await getGlobalsHeroSection(); + const featuresData = await getGlobalsFeaturesSection(); return (
- + diff --git a/apps/landing/src/collections/FeaturesSection.ts b/apps/landing/src/collections/FeaturesSection.ts new file mode 100644 index 0000000..8de4e31 --- /dev/null +++ b/apps/landing/src/collections/FeaturesSection.ts @@ -0,0 +1,72 @@ +import { GlobalConfig } from 'payload'; + +export const FeaturesSection: GlobalConfig = { + slug: 'features-section', + label: 'Features Section', + access: { + read: (): boolean => true, + }, + fields: [ + { + name: 'heading', + type: 'text', + defaultValue: 'Belajar programming dengan cara yang lebih baik', + }, + { + name: 'subheading', + type: 'text', + defaultValue: + 'IMPHNEN hadir dengan berbagai fitur untuk membantu kamu menjadi programmer handal tanpa harus pusing dengan coding.', + }, + { + name: 'features', + type: 'array', + defaultValue: [ + { + icon: 'LaptopIcon', + title: 'Belajar Tanpa Koding', + description: + 'Pelajari konsep programming dengan cara yang mudah dipahami tanpa harus menulis kode yang rumit.', + }, + { + icon: 'UsersIcon', + title: 'Komunitas Supportif', + description: + 'Bergabunglah dengan komunitas programmer Indonesia yang siap membantu dan berbagi pengalaman.', + }, + { + icon: 'BookOpenIcon', + title: 'Tutorial Interaktif', + description: + 'Akses tutorial interaktif yang membuat konsep programming lebih mudah untuk dipahami.', + }, + { + icon: 'CodeIcon', + title: 'Proyek Praktis', + description: + 'Terapkan pengetahuan Anda dalam proyek nyata dengan panduan langkah demi langkah.', + }, + ], + fields: [ + { + name: 'icon', + type: 'select', + options: [ + { label: 'LaptopIcon', value: 'LaptopIcon' }, + { label: 'UsersIcon', value: 'UsersIcon' }, + { label: 'BookOpenIcon', value: 'BookOpenIcon' }, + { label: 'CodeIcon', value: 'CodeIcon' }, + ], + }, + { + name: 'title', + type: 'text', + }, + { + name: 'description', + type: 'textarea', + }, + ], + }, + ], +}; diff --git a/apps/landing/src/payload-types.ts b/apps/landing/src/payload-types.ts index 865e21d..b1c50ce 100644 --- a/apps/landing/src/payload-types.ts +++ b/apps/landing/src/payload-types.ts @@ -86,9 +86,11 @@ export interface Config { }; globals: { 'hero-section': HeroSection; + 'features-section': FeaturesSection; }; globalsSelect: { 'hero-section': HeroSectionSelect | HeroSectionSelect; + 'features-section': FeaturesSectionSelect | FeaturesSectionSelect; }; locale: null; user: User & { @@ -301,6 +303,25 @@ export interface HeroSection { updatedAt?: string | null; createdAt?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "features-section". + */ +export interface FeaturesSection { + id: number; + heading?: string | null; + subheading?: string | null; + features?: + | { + icon?: ('LaptopIcon' | 'UsersIcon' | 'BookOpenIcon' | 'CodeIcon') | null; + title?: string | null; + description?: string | null; + id?: string | null; + }[] + | null; + updatedAt?: string | null; + createdAt?: string | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "hero-section_select". @@ -329,6 +350,25 @@ export interface HeroSectionSelect { createdAt?: T; globalType?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "features-section_select". + */ +export interface FeaturesSectionSelect { + heading?: T; + subheading?: T; + features?: + | T + | { + icon?: T; + title?: T; + description?: T; + id?: T; + }; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". diff --git a/apps/landing/src/payload.config.ts b/apps/landing/src/payload.config.ts index 48bc574..b63dcd5 100644 --- a/apps/landing/src/payload.config.ts +++ b/apps/landing/src/payload.config.ts @@ -5,6 +5,7 @@ import { buildConfig } from 'payload'; import sharp from 'sharp'; import { fileURLToPath } from 'url'; +import { FeaturesSection } from './collections/FeaturesSection'; import { HeroSection } from './collections/HeroSection'; import { Media } from './collections/Media'; import { Users } from './collections/Users'; @@ -26,7 +27,7 @@ export default buildConfig({ }, }, collections: [Users, Media], - globals: [HeroSection], + globals: [HeroSection, FeaturesSection], editor: lexicalEditor(), secret: process.env.CMS_SECRET || '', typescript: { diff --git a/apps/landing/src/repositories/get-globals-features-section.ts b/apps/landing/src/repositories/get-globals-features-section.ts new file mode 100644 index 0000000..d22574d --- /dev/null +++ b/apps/landing/src/repositories/get-globals-features-section.ts @@ -0,0 +1,7 @@ +import { payload } from '../lib/payload'; + +export async function getGlobalsFeaturesSection() { + return await payload.findGlobal({ + slug: 'features-section', + }); +}