diff --git a/src/theme/conversion/components/cdcasestudies/components/index.tsx b/src/theme/conversion/components/cdcasestudies/components/index.tsx index e9b622b..4b2f488 100644 --- a/src/theme/conversion/components/cdcasestudies/components/index.tsx +++ b/src/theme/conversion/components/cdcasestudies/components/index.tsx @@ -4,6 +4,7 @@ import type { ViewComponentProps } from "@conversiondigital/headless-basics-data import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src"; import DemoVariant from "./variants/demoVariant"; import CdcasestudiesDefaultVariant from "./variants/cdcasestudiesDefaultVariant"; +import OurWorkVariant from "./variants/ourWorkVariant"; export const log = getLogger("conversion.components.cdcasestudies"); @@ -15,6 +16,8 @@ export default function CdcasestudiesUI(dynamicComponent: ViewComponentProps) { switch (variant) { case "xDemo": return ; + case "ourWork": + return ; default: return ; } diff --git a/src/theme/conversion/components/cdcasestudies/components/variants/ourWorkVariant.tsx b/src/theme/conversion/components/cdcasestudies/components/variants/ourWorkVariant.tsx new file mode 100644 index 0000000..b997026 --- /dev/null +++ b/src/theme/conversion/components/cdcasestudies/components/variants/ourWorkVariant.tsx @@ -0,0 +1,182 @@ +"use client" +import React, { useState, useMemo } from "react"; +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps"; +import { getCmsImage } from "@conversiondigital/headless-basics-data/src/cms/tools/multiCmsImageTools"; + +export default function OurWorkVariant(props: StandardComponentProps) { + console.log('DEBUG: OurWorkVariant props:', props); + + const { matchingData } = props; + console.log('DEBUG: matchingData:', matchingData); + + const title = matchingData?.title?.toUpperCase(); + const subtitle = matchingData?.subtitle; + const topics = matchingData?.topics || []; + const items = matchingData?.items || []; + const button = matchingData?.button || {}; + + console.log('DEBUG: Extracted data:'); + console.log('- title:', title); + console.log('- subtitle:', subtitle); + console.log('- topics:', topics); + console.log('- items:', items); + console.log('- button:', button); + + // State for active filter + const [activeFilter, setActiveFilter] = useState('all'); + + // Use topics from main schema + const availableTopics = topics; + + // Filter case studies based on active filter + const filteredItems = useMemo(() => { + console.log('DEBUG: Filtering - activeFilter:', activeFilter); + console.log('DEBUG: Filtering - items:', items); + + if (activeFilter === 'all') { + return items; + } + + const filtered = items.filter((item: any) => { + const itemTopics = item?.topics || []; + console.log('DEBUG: Item topics:', itemTopics, 'for item:', item?.title); + + const matches = itemTopics.some((topic: string) => { + const match = topic?.toLowerCase().trim() === activeFilter?.toLowerCase().trim(); + console.log('DEBUG: Comparing:', topic, 'with', activeFilter, 'match:', match); + return match; + }); + + console.log('DEBUG: Item matches filter:', matches); + return matches; + }); + + console.log('DEBUG: Filtered items:', filtered); + return filtered; + }, [items, activeFilter]); + + const handleFilterClick = (topic: string) => { + console.log('DEBUG: handleFilterClick called with topic:', topic); + setActiveFilter(topic); + console.log('DEBUG: activeFilter set to:', topic); + }; + + return ( +
+
+
+

+ {title} +

+
+

+ {subtitle} +

+
+
+ + {availableTopics && availableTopics.length > 0 && ( +
+
+ + {availableTopics.map((topic: string, index: number) => { + // Count items that match this topic (case-insensitive) + const matchingCount = items.filter((item: any) => + item?.topics?.some((itemTopic: string) => + itemTopic?.toLowerCase().trim() === topic?.toLowerCase().trim() + ) + ).length; + + return ( + + ); + })} +
+
+ )} + + {activeFilter !== 'all' && filteredItems.length === 0 && ( +
+

No case studies found for topic "{activeFilter}"

+ +
+ )} + +
+ {filteredItems.map((item: any, index: number) => { + const { hasImage, imageLocation } = getCmsImage(item); + const finalImage = hasImage ? imageLocation : item?.imageUrl; + + return ( + + + + {button?.text && button?.link && ( + + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/theme/conversion/components/cdcasestudies/sanity-query.ts b/src/theme/conversion/components/cdcasestudies/sanity-query.ts index c48d4ab..c0bd0df 100644 --- a/src/theme/conversion/components/cdcasestudies/sanity-query.ts +++ b/src/theme/conversion/components/cdcasestudies/sanity-query.ts @@ -14,10 +14,12 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str sortOrder title subtitle + topics items { title description link + topics image { asset { url @@ -33,10 +35,12 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + topics items { title description link + topics image { asset { url @@ -58,10 +62,12 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str sortOrder title subtitle + topics items { title description link + topics image { asset { url @@ -77,10 +83,12 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + topics items { title description link + topics image { asset { url diff --git a/src/theme/conversion/components/cdcasestudies/sanity-schema.ts b/src/theme/conversion/components/cdcasestudies/sanity-schema.ts index 9705f11..434894a 100644 --- a/src/theme/conversion/components/cdcasestudies/sanity-schema.ts +++ b/src/theme/conversion/components/cdcasestudies/sanity-schema.ts @@ -29,6 +29,16 @@ export const caseStudyItem = defineType({ name: 'link', title: 'Link', type: 'url' + }), + defineField({ + name: 'topics', + title: 'Topics', + type: 'array', + of: [{ type: 'string' }], + description: 'Topics/categories for this case study', + options: { + layout: 'tags' + } }) ] }) @@ -46,6 +56,7 @@ export default defineType({ options: { list: [ { title: 'Default', value: 'default' }, + { title: 'Our Work', value: 'ourWork' }, { title: 'Demo', value: 'xDemo' }, ], }, @@ -68,6 +79,16 @@ export default defineType({ type: 'string', description: 'Subtitle or tagline for the case studies section.' }), + defineField({ + name: 'topics', + title: 'Topics', + type: 'array', + of: [{ type: 'string' }], + description: 'Topics used for filtering case studies', + options: { + layout: 'tags' + } + }), defineField({ name: 'items', title: 'Case Studies', @@ -92,6 +113,27 @@ export default defineType({ title: 'Button URL', type: 'string', description: 'URL for the button link' + }), + defineField({ + name: 'showFilter', + title: 'Show Keyword Filter', + type: 'boolean', + description: 'Show the keyword filter section above the case studies', + initialValue: true + }), + defineField({ + name: 'filterTitle', + title: 'Filter Title', + type: 'string', + description: 'Title for the keyword filter section', + initialValue: 'Filter by Category' + }), + defineField({ + name: 'allKeyword', + title: 'All Keywords Text', + type: 'string', + description: 'Text for the "show all" filter option', + initialValue: 'All' }) ], preview: { diff --git a/src/theme/conversion/components/cdfooter/sanity-mapping.ts b/src/theme/conversion/components/cdfooter/sanity-mapping.ts index 64afa32..e58da61 100644 --- a/src/theme/conversion/components/cdfooter/sanity-mapping.ts +++ b/src/theme/conversion/components/cdfooter/sanity-mapping.ts @@ -9,11 +9,9 @@ export async function mapIdentifierData(pageAndComponentCombo: PageAndSingleComp ); const content = pageAndComponentCombo?.component?.data - const thisComponentsOrder = pageAndComponentCombo?.component?.sortOrder ?? 0; log.trace(`${logPrefix()} thisComponentsOrder: ${thisComponentsOrder}`); - const matchingData = extractComponentsFromSanityData(content, "cdfooter", log); return matchingData diff --git a/src/theme/conversion/components/herobanner/components/index.tsx b/src/theme/conversion/components/herobanner/components/index.tsx index bb1701a..0b06a86 100644 --- a/src/theme/conversion/components/herobanner/components/index.tsx +++ b/src/theme/conversion/components/herobanner/components/index.tsx @@ -4,9 +4,11 @@ import type { ViewComponentProps } from "@conversiondigital/headless-basics-data import { getLogger, logPrefix } from "@conversiondigital/headless-basics-data/src" import DemoVariant from "./variants/demoVariant" import DefaultVariant from "./variants/defaultVariant" +import CaseStudyVariant from "./variants/caseStudyVariant" import IntroductionVariant from "./variants/IntroductionVariant" import TitleOnlyVariant from "./variants/TitleOnlyVariant" + export const log = getLogger("default.components.heartcore.template.variants"); export default function TemplateUI(dynamicComponent: ViewComponentProps) { @@ -17,6 +19,8 @@ export default function TemplateUI(dynamicComponent: ViewComponentProps) { switch (variant) { case "xDemo": return ; + case "caseStudy": + return ; case "title-only": return ; case "introduction": diff --git a/src/theme/conversion/components/herobanner/components/variants/caseStudyVariant.tsx b/src/theme/conversion/components/herobanner/components/variants/caseStudyVariant.tsx new file mode 100644 index 0000000..236e933 --- /dev/null +++ b/src/theme/conversion/components/herobanner/components/variants/caseStudyVariant.tsx @@ -0,0 +1,49 @@ +import React from "react" +import { StandardComponentProps } from "@conversiondigital/headless-basics-components/src/interfaces/standardComponentProps" +import Link from "next/link" +import { buttonIcon as ButtonIcon } from "../../../../styles/icons/icons" + +export default function CaseStudyVariant(props: StandardComponentProps) { + const { matchingData } = props; + const imageUrl = matchingData?.image?.asset?.url + const altText = matchingData?.altText || matchingData?.image?.asset?.altText || "HeroBanner Image" + const description = matchingData?.description || "Case Study HeroBanner Description" + + const buttonLabel = matchingData?.button?.label + const buttonLink = matchingData?.button?.link + return ( +
+
+

+ {matchingData?.title || "Case Study HeroBanner Title"} +

+

+ {(matchingData?.subtitle || "Case Study HeroBanner Subtitle").toUpperCase()} +

+

+ {description} +

+ {buttonLabel && buttonLink && ( +
+ + {buttonLabel} + + +
+ )} +
+ {imageUrl && ( +
+ {altText} +
+ )} +
+ ) +} \ No newline at end of file diff --git a/src/theme/conversion/components/herobanner/sanity-query.ts b/src/theme/conversion/components/herobanner/sanity-query.ts index 61ab47b..2037971 100644 --- a/src/theme/conversion/components/herobanner/sanity-query.ts +++ b/src/theme/conversion/components/herobanner/sanity-query.ts @@ -14,6 +14,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + description category image { asset { @@ -32,6 +33,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _type title subtitle + description category image { asset { @@ -57,6 +59,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str selectableVariant title subtitle + description category image { asset { @@ -75,6 +78,7 @@ export function query(pageAndComponentCombo: PageAndSingleComponentDetails): str _type title subtitle + description category image { asset { diff --git a/src/theme/conversion/components/herobanner/sanity-schema.ts b/src/theme/conversion/components/herobanner/sanity-schema.ts index 76211b8..4bd3762 100644 --- a/src/theme/conversion/components/herobanner/sanity-schema.ts +++ b/src/theme/conversion/components/herobanner/sanity-schema.ts @@ -1,6 +1,38 @@ -import { defineField, defineType } from 'sanity' +import { defineField, defineType, defineArrayMember } from 'sanity' import { EyeOpenIcon } from '@sanity/icons' +// Define the case study item schema for hero banner as a top-level type +export const heroCaseStudyItem = defineType({ + name: 'heroCaseStudyItem', + title: 'Hero Case Study Item', + type: 'object', + fields: [ + defineField({ + name: 'title', + title: 'Title', + type: 'string' + }), + defineField({ + name: 'description', + title: 'Description', + type: 'text' + }), + defineField({ + name: 'image', + title: 'Image', + type: 'image', + options: { + hotspot: true + } + }), + defineField({ + name: 'link', + title: 'Link', + type: 'url' + }) + ] +}) + export default defineType({ name: 'herobanner', title: 'HeroBanner', @@ -16,6 +48,7 @@ export default defineType({ { title: 'Title Only', value: 'title-only' }, { title: 'Introduction', value: 'introduction' }, { title: 'Default', value: 'default' }, + { title: 'Case Study', value: 'caseStudy' }, { title: 'Demo', value: 'xDemo' }, ] } @@ -31,6 +64,10 @@ export default defineType({ type: 'string', }), defineField({ + name: 'description', + title: 'Description', + type: 'text', + description: 'Additional descriptive text for the hero banner (especially useful for Case Study variant)' name: 'category', title: 'Category', description: 'e.g: Services, About Us, etc.', @@ -54,6 +91,13 @@ export default defineType({ title: 'Button', type: 'heroButton' }), + defineField({ + name: 'items', + title: 'Case Studies', + type: 'array', + of: [{ type: 'heroCaseStudyItem' }], + description: 'Case studies to display in the hero banner (for Case Study variant)' + }), defineField({ name: 'sortOrder', title: 'Sort Order',