Files
loyalyweb/src/components/for-people/WhyLoyalySection.tsx

144 lines
7.0 KiB
TypeScript

'use client';
import React, { useEffect, useRef, useState } from 'react';
export default function WhyLoyalySection() {
const [active, setActive] = useState(false);
const [count, setCount] = useState(0);
const panelRef = useRef<HTMLDivElement>(null);
const rafRef = useRef<number>(0);
useEffect(() => {
const el = panelRef.current;
if (!el) return;
const obs = new MutationObserver(() => {
const isActive = el.hasAttribute('data-active');
setActive(isActive);
if (isActive) {
const start = performance.now();
const dur = 2000;
const tick = (now: number) => {
const t = Math.min((now - start) / dur, 1);
setCount(Math.round((1 - Math.pow(1 - t, 4)) * 21000000));
if (t < 1) rafRef.current = requestAnimationFrame(tick);
};
rafRef.current = requestAnimationFrame(tick);
}
});
obs.observe(el, { attributes: true, attributeFilter: ['data-active'] });
return () => { obs.disconnect(); cancelAnimationFrame(rafRef.current); };
}, []);
const bars = [
{ label: 'Online retail loyalty', pct: 78, color: '#171512' },
{ label: 'Offline retail loyalty', pct: 2, color: '#ef4444' },
{ label: 'Loyaly target', pct: 60, color: '#f4be28' },
];
return (
<section ref={panelRef} className="fp-panel fp-light" style={{ background: '#ffffff' }}>
{/* Faint grid */}
<div className="fp-deco" style={{
position: 'absolute', inset: 0, zIndex: 0,
backgroundImage: 'linear-gradient(rgba(23,21,18,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(23,21,18,0.03) 1px, transparent 1px)',
backgroundSize: '72px 72px',
}} />
<div className="fp-shell">
<div style={{ marginBottom: 'clamp(40px, 6vh, 64px)' }}>
<span className="fp-kicker fp-rise">The Gap · 01</span>
</div>
<div className="fp-split" style={{ gridTemplateColumns: '1fr 1fr' }}>
{/* Giant stat */}
<div>
{/* "0%" as two-color giant */}
<div style={{
display: 'flex', alignItems: 'flex-start', gap: 0,
opacity: active ? 1 : 0, transform: active ? 'translateY(0)' : 'translateY(50px)',
transition: 'opacity 0.95s cubic-bezier(0.16,1,0.3,1), transform 0.95s cubic-bezier(0.16,1,0.3,1)',
}}>
<span style={{ fontSize: 'clamp(120px, 18vw, 260px)', fontWeight: 900, fontFamily: 'Sora, sans-serif', color: '#f4be28', letterSpacing: '-0.06em', lineHeight: 0.85 }}>0</span>
<span style={{ fontSize: 'clamp(60px, 9vw, 130px)', fontWeight: 900, fontFamily: 'Sora, sans-serif', color: '#171512', letterSpacing: '-0.04em', lineHeight: 0.85, paddingTop: '0.12em' }}>%</span>
</div>
<div className="fp-rise" style={{ marginTop: 20, marginBottom: 32 }}>
<div style={{
display: 'inline-block', padding: '8px 16px', borderRadius: 10,
background: '#ef4444', color: '#fff',
fontSize: 12, fontWeight: 700, fontFamily: 'Sora, sans-serif', letterSpacing: '0.08em', textTransform: 'uppercase',
}}>Loyalty penetration in offline retail</div>
</div>
{/* Three metric chips */}
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
{[
{ val: '₹2.1L Cr', label: 'Offline retail market size', accent: '#171512' },
{ val: '<2%', label: 'Currently getting rewards', accent: '#ef4444' },
{ val: '10Cr+', label: 'Shoppers Loyaly can reach', accent: '#16a34a' },
].map((m, i) => (
<div key={i} className="fp-rise" style={{
display: 'flex', alignItems: 'center', gap: 16, padding: '14px 18px',
borderRadius: 14, background: '#f5f5f5', border: `1.5px solid ${m.accent}22`,
transitionDelay: `${0.1 + i * 0.08}s`,
}}>
<div style={{ fontSize: 20, fontWeight: 900, fontFamily: 'Sora, sans-serif', color: m.accent, letterSpacing: '-0.03em', flexShrink: 0, minWidth: 72 }}>{m.val}</div>
<div style={{ fontSize: 12, color: 'rgba(23,21,18,0.6)', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{m.label}</div>
</div>
))}
</div>
</div>
{/* Content */}
<div>
{/* Live counter badge */}
<div className="fp-rise" style={{
display: 'inline-flex', alignItems: 'center', gap: 10, marginBottom: 28,
background: '#fff7e0', border: '1.5px solid #f4be28', borderRadius: 100, padding: '10px 20px',
}}>
<span style={{ width: 8, height: 8, borderRadius: '50%', background: '#16a34a', display: 'block', flexShrink: 0, boxShadow: '0 0 0 3px rgba(22,163,74,0.2)', animation: 'fpPulse 1.5s ease-in-out infinite' }} />
<span style={{ fontSize: 13, fontWeight: 700, color: '#171512', fontFamily: 'Sora, sans-serif' }}>
<span style={{ color: '#f4be28' }}>{count.toLocaleString()}</span> txns today · unrewarded
</span>
</div>
<h2 style={{
fontSize: 'clamp(30px, 3.6vw, 50px)', fontWeight: 800, lineHeight: 1.08,
letterSpacing: '-0.04em', color: '#171512', margin: '0 0 20px', fontFamily: 'Sora, sans-serif',
}}>
<span className="fp-mask"><span>Millions shop offline.</span></span>
<span className="fp-mask"><span style={{ color: '#ef4444' }}>Nobody rewards them.</span></span>
</h2>
<p className="fp-rise" style={{
fontSize: 16, lineHeight: 1.8, color: '#4f463a', margin: '0 0 36px',
fontFamily: 'Sora, sans-serif', maxWidth: 440,
}}>
India&apos;s offline retail market is worth 2.1 lakh crore. Yet loyalty penetration sits at effectively zero. Loyaly exists to close that gap permanently.
</p>
{/* Data bars */}
{bars.map((b, i) => (
<div key={i} style={{ marginBottom: 16 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 7 }}>
<span style={{ fontSize: 13, fontWeight: 600, color: '#171512', fontFamily: 'Sora, sans-serif' }}>{b.label}</span>
<span style={{ fontSize: 14, fontWeight: 800, color: b.color, fontFamily: 'Sora, sans-serif' }}>{b.pct}%</span>
</div>
<div style={{ height: 8, background: 'rgba(23,21,18,0.07)', borderRadius: 100, overflow: 'hidden' }}>
<div style={{
height: '100%', borderRadius: 100, background: b.color,
width: active ? `${b.pct}%` : '0%',
transition: `width ${0.9 + i * 0.2}s cubic-bezier(0.22,1,0.36,1) ${0.4 + i * 0.15}s`,
}} />
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
}