"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { useReducedMotion } from "framer-motion"; // The eight beats of a merchant's life on Nearle. The visitor watches the whole // arc — join → digitize → sell → grow — play out once, then can replay/drive it. export type MerchantStageId = | "join" | "digitize" | "products" | "browse" | "orders" | "packed" | "rider" | "grows"; export type MerchantStep = { id: MerchantStageId; num: string; label: string; // short label for the progress rail icon: string; // Material Symbol for the rail node title: string; desc: string; }; export const MERCHANT_STEPS: MerchantStep[] = [ { id: "join", num: "01", label: "Join", icon: "handshake", title: "Merchant Joins Nearle", desc: "Your neighbourhood shop signs up in minutes — no tech skills needed.", }, { id: "digitize", num: "02", label: "Digitize", icon: "qr_code_2", title: "Store Digitized", desc: "A quick QR scan turns your shelves into a searchable digital storefront.", }, { id: "products", num: "03", label: "Products", icon: "inventory_2", title: "Products Added", desc: "AI reads a shelf photo and builds your live, shoppable catalogue.", }, { id: "browse", num: "04", label: "Browse", icon: "search", title: "Customers Browse", desc: "Nearby shoppers discover and search your store in natural language.", }, { id: "orders", num: "05", label: "Orders", icon: "receipt_long", title: "Orders Received", desc: "Orders land directly with you — an instant alert for every sale.", }, { id: "packed", num: "06", label: "Packed", icon: "package_2", title: "Products Packed", desc: "You pack the order yourself, staying at the centre of every sale.", }, { id: "rider", num: "07", label: "Delivery", icon: "two_wheeler", title: "Nearle Rider Delivers", desc: "A Nearle rider picks up and delivers to your customer’s door.", }, { id: "grows", num: "08", label: "Growth", icon: "trending_up", title: "Business Grows", desc: "Demand insights and repeat orders compound into steady local growth.", }, ]; const AUTOPLAY_MS = 3200; // each stage stays readable for ~3.2s export type MerchantJourney = { steps: MerchantStep[]; index: number; step: MerchantStep; started: boolean; autoplaying: boolean; atEnd: boolean; reduced: boolean; start: () => void; goTo: (i: number) => void; next: () => void; prev: () => void; replay: () => void; }; // Autoplays through the stages exactly once on scroll-into-view, then rests on // the final stage. Any manual input (rail node, arrow, swipe) cancels autoplay // and hands control to the visitor. Reduced motion → manual from the start. export function useMerchantJourney(): MerchantJourney { const reduced = useReducedMotion() ?? false; const [started, setStarted] = useState(false); const [index, setIndex] = useState(0); const [autoplaying, setAutoplaying] = useState(false); const last = MERCHANT_STEPS.length - 1; const timer = useRef | null>(null); const clear = useCallback(() => { if (timer.current) clearTimeout(timer.current); timer.current = null; }, []); useEffect(() => clear, [clear]); // Auto-advance one stage at a time; simply stop scheduling (don't loop) at the // end so the journey rests on the final stage. No synchronous setState here. useEffect(() => { if (!started || reduced || !autoplaying || index >= last) return; timer.current = setTimeout(() => setIndex((i) => Math.min(i + 1, last)), AUTOPLAY_MS); return clear; }, [started, reduced, autoplaying, index, last, clear]); const start = useCallback(() => { setStarted((was) => { if (!was && !reduced) setAutoplaying(true); return true; }); }, [reduced]); const goTo = useCallback( (i: number) => { clear(); setAutoplaying(false); setStarted(true); setIndex(Math.max(0, Math.min(i, last))); }, [clear, last] ); const next = useCallback(() => { clear(); setAutoplaying(false); setStarted(true); setIndex((i) => Math.min(i + 1, last)); }, [clear, last]); const prev = useCallback(() => { clear(); setAutoplaying(false); setStarted(true); setIndex((i) => Math.max(i - 1, 0)); }, [clear]); const replay = useCallback(() => { clear(); setIndex(0); setStarted(true); setAutoplaying(!reduced); }, [clear, reduced]); return { steps: MERCHANT_STEPS, index, step: MERCHANT_STEPS[index], started, autoplaying, atEnd: index >= last, reduced, start, goTo, next, prev, replay, }; }