"use client"; import React, { useEffect, useRef, useState } from "react"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; if (typeof window !== "undefined") { gsap.registerPlugin(ScrollTrigger); } const PILLS: { value: string; label: string }[] = [ { value: "100%", label: "Electric Fleet" }, { value: "Live", label: "Route Sync" }, { value: "Real-time", label: "Battery Monitoring" }, ]; const MINI_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [ { value: 94, suffix: "K+", label: "Routes Optimised" }, { value: 23, suffix: "%", label: "Avg Battery Saved" }, { value: 1.4, decimals: 1, suffix: "x", label: "Charging Stops Saved" }, ]; const FEATURES: { icon: string; title: string; desc: string }[] = [ { icon: "โšก", title: "Battery-Aware Routing", desc: "Battery level, health, and degradation are first-class inputs to route optimization โ€” not afterthoughts.", }, { icon: "๐Ÿ”Œ", title: "Charging Integration", desc: "Seamlessly integrate charging stops without compromising delivery windows or SLA commitments.", }, { icon: "โ›ฐ", title: "Energy-Optimized Paths", desc: "Factor in elevation, speed limits, payload weight, and live weather for maximum range efficiency.", }, { icon: "๐Ÿ›ก", title: "Predictable Operations", desc: "EVs become predictable assets, not operational risks. Full visibility from depot to doorstep.", }, ]; const BOTTOM_STATS: { value: number; decimals?: number; suffix: string; label: string }[] = [ { value: 120, suffix: "K+", label: "Deliveries Completed" }, { value: 98, suffix: "%", label: "On-Time Rate" }, { value: 31, suffix: "%", label: "Range Efficiency Gain" }, { value: 340, suffix: "ms", label: "Avg Route Calc Time" }, ]; /** Count-up that fires once when scrolled ~20% into view (ease-out cubic). */ function CountUp({ value, decimals = 0, suffix = "", duration = 1700, className, }: { value: number; decimals?: number; suffix?: string; duration?: number; className?: string; }) { const [n, setN] = useState(0); const ref = useRef(null); const done = useRef(false); useEffect(() => { const el = ref.current; if (!el) return; const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; if (reduced) { requestAnimationFrame(() => setN(value)); return; } const io = new IntersectionObserver( (entries) => { for (const e of entries) { if (e.isIntersecting && !done.current) { done.current = true; const start = performance.now(); const ease = (t: number) => 1 - Math.pow(1 - t, 3); const tick = (now: number) => { const p = Math.min(1, (now - start) / duration); setN(value * ease(p)); if (p < 1) requestAnimationFrame(tick); else setN(value); }; requestAnimationFrame(tick); io.disconnect(); } } }, { threshold: 0.2 } ); io.observe(el); return () => io.disconnect(); }, [value, duration]); return ( } className={className}> {n.toFixed(decimals)} {suffix} ); } export default function EVSection() { const bannerRef = useRef(null); useEffect(() => { // Banner Scroll-Triggered Parallax (Replicating background_image_parallax from theme.js exactly) const banner = bannerRef.current; if (!banner) return; const parallaxTrigger = ScrollTrigger.create({ trigger: banner, start: "top bottom", end: "bottom top", scrub: true, onUpdate: () => { if (window.innerWidth >= 1021) { const scrollTop = window.scrollY; const rect = banner.getBoundingClientRect(); const offsetTop = rect.top + scrollTop; const from_top = scrollTop - offsetTop; const yOffset = 0.3 * from_top; gsap.set(banner, { backgroundPosition: `center ${yOffset}px` }); } else { gsap.set(banner, { backgroundPosition: "" }); } }, }); return () => parallaxTrigger?.kill(); }, []); return ( <>