'use client'; import React, { useEffect, useLayoutEffect, useRef, useState, useCallback } from 'react'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import { DEFAULT_EASE, DEFAULT_DURATION } from '@/utils/animation'; import AnimatedDarkBg from './AnimatedDarkBg'; if (typeof window !== 'undefined') { gsap.registerPlugin(ScrollTrigger); } const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect; interface CardProps { num: string; title: string; description: string; icon: React.ReactNode; cardRef: React.RefObject; orderClass: string; } function StageCard({ num, title, description, icon, cardRef, orderClass }: CardProps) { return (
{ (e.currentTarget as HTMLElement).style.transform = 'translateY(-8px)'; (e.currentTarget as HTMLElement).style.boxShadow = '0 32px 80px rgba(244, 190, 40,0.12), 0 0 0 1px rgba(244, 190, 40,0.25), inset 0 1px 0 rgba(255,255,255,0.08)'; (e.currentTarget as HTMLElement).style.borderColor = 'rgba(244, 190, 40,0.3)'; }} onMouseLeave={e => { (e.currentTarget as HTMLElement).style.transform = 'translateY(0)'; (e.currentTarget as HTMLElement).style.boxShadow = 'inset 0 1px 0 rgba(255,255,255,0.05)'; (e.currentTarget as HTMLElement).style.borderColor = 'rgba(255,255,255,0.08)'; }} > {/* Giant editorial number watermark */}
{num}
{/* Icon */}
{icon}
{/* Title */}

{title}

{/* Description */}

{description}

); } interface WhatWeDoProps { isLoaded?: boolean; } export default function WhatWeDo({ isLoaded = false }: WhatWeDoProps) { const containerRef = useRef(null); const gridContainerRef = useRef(null); const card1Ref = useRef(null); const card2Ref = useRef(null); const card3Ref = useRef(null); const card4Ref = useRef(null); const [points, setPoints] = useState({ p1: { x: 0, y: 0 }, p2: { x: 0, y: 0 }, p3: { x: 0, y: 0 }, p4: { x: 0, y: 0 } }); const [hasMeasured, setHasMeasured] = useState(false); const updatePoints = useCallback(() => { if (!gridContainerRef.current || !card1Ref.current || !card2Ref.current || !card3Ref.current || !card4Ref.current) return; const containerRect = gridContainerRef.current.getBoundingClientRect(); const r1 = card1Ref.current.getBoundingClientRect(); const r2 = card2Ref.current.getBoundingClientRect(); const r3 = card3Ref.current.getBoundingClientRect(); const r4 = card4Ref.current.getBoundingClientRect(); // Check that width is non-zero to verify the elements have rendered and have dimensions if (r1.width === 0 || r2.width === 0 || r3.width === 0 || r4.width === 0) return; setPoints({ p1: { x: r1.left - containerRect.left + r1.width / 2, y: r1.top - containerRect.top + r1.height / 2 }, p2: { x: r2.left - containerRect.left + r2.width / 2, y: r2.top - containerRect.top + r2.height / 2 }, p3: { x: r3.left - containerRect.left + r3.width / 2, y: r3.top - containerRect.top + r3.height / 2 }, p4: { x: r4.left - containerRect.left + r4.width / 2, y: r4.top - containerRect.top + r4.height / 2 } }); setHasMeasured(true); }, []); useEffect(() => { if (typeof window === 'undefined') return; // Use ResizeObserver for highly responsive layout tracking const observer = new ResizeObserver(() => { updatePoints(); }); if (gridContainerRef.current) observer.observe(gridContainerRef.current); if (card1Ref.current) observer.observe(card1Ref.current); if (card2Ref.current) observer.observe(card2Ref.current); if (card3Ref.current) observer.observe(card3Ref.current); if (card4Ref.current) observer.observe(card4Ref.current); // Initial calculation updatePoints(); // Secondary delay to ensure clean alignment post-font/css loading const timer = setTimeout(updatePoints, 200); window.addEventListener('resize', updatePoints); return () => { observer.disconnect(); window.removeEventListener('resize', updatePoints); clearTimeout(timer); }; }, [updatePoints]); // GSAP animations for stagger entrances on entering viewport useIsomorphicLayoutEffect(() => { if (!isLoaded) return; if (typeof window === 'undefined') return; const ctx = gsap.context(() => { // Header Animation gsap.fromTo( '.wwd-header-el', { opacity: 0, y: 40 }, { opacity: 1, y: 0, duration: DEFAULT_DURATION, stagger: 0.15, ease: DEFAULT_EASE, scrollTrigger: { trigger: '.wwd-header', start: 'top 85%', toggleActions: 'play none none reset' } } ); // Card Stagger Animation gsap.fromTo( '.wwd-card', { opacity: 0, y: 60 }, { opacity: 1, y: 0, duration: DEFAULT_DURATION, stagger: 0.15, ease: DEFAULT_EASE, onComplete: updatePoints, scrollTrigger: { trigger: '.wwd-grid-container', start: 'top 80%', toggleActions: 'play none none reset' } } ); }, containerRef); return () => ctx.revert(); }, [isLoaded, updatePoints]); return (
{/* Animated dark background (replaces video) */} {/* Header Container */}
{/* Pill Badge */}
What We Do
{/* Main Heading */}

Understand.
Engage. Convert.
Retain.

{/* Subtitle */}

Four stages. One platform. A smarter retail cycle that turns every walk-in into a loyal customer.

{/* Grid and Paths Container */}
{/* 2 x 2 Responsive Grid */}
{/* Card 1 — Understand */} } /> {/* Card 2 — Engage */} } /> {/* Card 4 — Retain (positioned bottom-left on desktop via order-3) */} } /> {/* Card 3 — Convert (positioned bottom-right on desktop via order-4) */} } />
{/* Center Area Ornament */} {hasMeasured && (
{/* Glowing container */}
{/* Pulsing outer aura */}
{/* Rotating ↻ Icon */}
)}
); }