'use client';
import React, { useEffect, useLayoutEffect, useRef } from 'react';
import Link from 'next/link';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
if (typeof window !== 'undefined') {
gsap.registerPlugin(ScrollTrigger);
}
const useIsomorphicLayoutEffect =
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
interface Product {
id: number;
href: string;
title: string;
subtitle: string;
description: string;
accent: string;
accentRgb: string;
tags: string[];
}
const PRODUCTS: Product[] = [
{
id: 1,
href: '/solutions/behavision',
title: 'Behavision',
subtitle: 'AI Powered Footfall Analytics',
description:
'AI powered footfall analytics and behavioral intelligence. Understand how customers move, dwell, and engage, turning raw foot traffic into rich, actionable insights.',
accent: '#f4be28',
accentRgb: '244, 190, 40',
tags: ['Footfall Tracking', 'Behavior Analysis'],
},
{
id: 2,
href: '/solutions/spendsense',
title: 'SpendSense',
subtitle: 'Customer Spending Intelligence',
description:
'Deep insights into customer spending patterns. Identify high-value segments, predict buying behaviour, and unlock incremental revenue hiding in plain sight.',
accent: '#10B981',
accentRgb: '16, 185, 129',
tags: ['Spending Trends', 'Revenue Analytics', 'Customer Value'],
},
{
id: 3,
href: '/solutions/dyscount',
title: 'Dyscount',
subtitle: 'Smart Discount Engine',
description:
'Smart discount engine that maximises conversions without killing margins. Deliver the right offer to the right customer at exactly the right moment.',
accent: '#EF4444',
accentRgb: '239, 68, 68',
tags: ['Smart Discounts', 'Offer Automation', 'Margin Protection'],
},
{
id: 4,
href: '/solutions/loyaly-app',
title: 'Identiq',
subtitle: 'Consumer Loyalty Platform',
description:
'Earn LYTs through daily logins and games, then redeem Lyts at real offline stores.',
accent: '#f4be28',
accentRgb: '244, 190, 40',
tags: ['Daily Lyts', 'Game Based Offers', 'Offline Redemption'],
},
];
function ProductIcon({ id, accent }: { id: number; accent: string }) {
if (id === 1) {
return (
);
}
if (id === 2) {
return (
);
}
if (id === 3) {
return (
);
}
return (
);
}
/* Real product-preview visual per product — a believable mini-UI, not generic decoration */
function ProductVisual({ product }: { product: Product }) {
const { id, accent, accentRgb } = product;
// 1 — Behavision: footfall heatmap + live counter
if (id === 1) {
const cells = Array.from({ length: 48 });
return (
Live footfall
2,847
{cells.map((_, i) => {
const intensity = Math.abs(Math.sin(i * 1.7) * Math.cos(i * 0.6));
const alpha = (0.08 + intensity * 0.7).toFixed(3);
return (
);
})}
{[['Peak', '6–8 PM'], ['Dwell', '14 min'], ['Zones', '12']].map(([k, v]) => (
))}
);
}
// 2 — SpendSense: spend trend chart
if (id === 2) {
const pts = [22, 30, 26, 42, 38, 54, 48, 66, 72];
const max = 80;
const w = 280, h = 120;
const path = pts.map((p, i) => `${(i / (pts.length - 1)) * w},${h - (p / max) * h}`).join(' ');
return (
Avg basket value
₹1,240
+18%
);
}
// 3 — Dyscount: smart offer + conversion uplift
if (id === 3) {
return (
{/* Live campaign badge, floating on the card edge */}
Live campaign
{/* Coupon-style offer card with perforated divider */}
Smart Offer
15% OFF
Targeted · high-intent shoppers
{/* Perforated tear-off edge */}
DYSCOUNT
{/* Mini stat grid */}
{[['Margin protected', '100%'], ['Waste', '0'], ['Redemptions', '1.2k']].map(([k, v]) => (
))}
);
}
// 4 — Loyaly App: rewards card
const REDEMPTIONS: [string, string, string][] = [
['Starbucks', '+120', '#1e6b52'],
['Nike Store', '+85', '#374151'],
];
return (
{/* Streak badge, floating on the card edge */}
🔥
6-day streak
{/* Member header */}
{/* LYTs balance card with progress to next tier */}
{/* Recent redemptions */}
Recently redeemed
{REDEMPTIONS.map(([s, p, dot], i) => (
))}
);
}
/* ── Gallery card (horizontal panel) ──────────────────────────────── */
function ProductCard({ product, index }: { product: Product; index: number }) {
return (
{/* ── Left content ── */}
0{product.id}
{product.subtitle}
{product.title}
{product.description}
{product.tags.map((tag) => (
{tag}
))}
{ (e.currentTarget as HTMLAnchorElement).style.transform = 'scale(1.04)'; }}
onMouseLeave={(e) => { (e.currentTarget as HTMLAnchorElement).style.transform = 'scale(1)'; }}
>
Explore {product.title}
{/* ── Right visual panel ── */}
);
}
interface ProductsSectionProps {
isLoaded?: boolean;
}
export default function ProductsSection({ isLoaded = false }: ProductsSectionProps) {
const sectionRef = useRef(null);
const trackRef = useRef(null);
const progressRef = useRef(null);
const counterRef = useRef(null);
useIsomorphicLayoutEffect(() => {
if (!isLoaded) return;
if (typeof window === 'undefined') return;
const section = sectionRef.current;
const track = trackRef.current;
if (!section || !track) return;
const mm = gsap.matchMedia();
// Desktop / tablet: pinned horizontal scroll
mm.add('(min-width: 901px)', () => {
const cards = gsap.utils.toArray('.products-card', track);
const distance = () => Math.max(0, track.scrollWidth - section.clientWidth);
const steps = Math.max(1, PRODUCTS.length - 1);
// Depth cue: the card nearest the viewport centre sits at full scale/
// opacity, neighbours ease back slightly — makes the ride feel guided
// rather than a flat strip sliding past, and the eased response
// absorbs small scrub jitter instead of showing it as a raw jump.
const updateDepth = () => {
const centerX = section.clientWidth / 2;
cards.forEach((card) => {
const trackX = Number(gsap.getProperty(track, 'x', 'px'));
const cardCenter = card.offsetLeft + card.offsetWidth / 2 + trackX;
const dist = Math.abs(cardCenter - centerX);
const norm = gsap.utils.clamp(0, 1, dist / (section.clientWidth * 0.62));
gsap.set(card, { scale: 1 - norm * 0.07, opacity: 1 - norm * 0.32 });
});
};
const tween = gsap.to(track, {
x: () => -distance(),
ease: 'none',
scrollTrigger: {
trigger: section,
start: 'top top',
end: () => `+=${distance()}`,
pin: true,
pinSpacing: true,
anticipatePin: 1,
scrub: 0.4,
invalidateOnRefresh: true,
refreshPriority: 5,
snap: {
snapTo: (value) => Math.round(value * steps) / steps,
duration: { min: 0.2, max: 0.5 },
ease: 'power2.inOut',
},
onUpdate: (self) => {
if (progressRef.current) progressRef.current.style.transform = `scaleX(${self.progress})`;
if (counterRef.current) {
const idx = Math.min(PRODUCTS.length, Math.max(1, Math.round(self.progress * steps) + 1));
counterRef.current.textContent = `0${idx}`;
}
updateDepth();
},
},
});
updateDepth();
ScrollTrigger.refresh();
return () => {
tween.scrollTrigger?.kill();
tween.kill();
gsap.set(track, { clearProps: 'transform' });
gsap.set(cards, { clearProps: 'scale,opacity' });
};
});
return () => mm.revert();
}, [isLoaded]);
return (
{/* ambient glow */}
{/* Heading (fixed within the pinned viewport) */}
Platform
Four agents.{' '}
One AI.
Powering every stage of the retail journey with intelligent AI solutions.
Unified into one platform
04
{/* Horizontal track */}
{PRODUCTS.map((product, index) => (
))}
{/* Progress bar + counter */}
);
}