diff --git a/src/components/platform/AnimatedDashboard.tsx b/src/components/platform/AnimatedDashboard.tsx new file mode 100644 index 0000000..7572119 --- /dev/null +++ b/src/components/platform/AnimatedDashboard.tsx @@ -0,0 +1,467 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { motion, AnimatePresence, useReducedMotion } from "framer-motion"; + +type ProductAsset = { + emoji: string; + name: string; + xStart: string; // Tailwind coordinate + yStart: string; // Tailwind coordinate + floatDelay: number; + floatDuration: number; +}; + +// Define products that float and participate in AI automation +const PRODUCT_ASSETS: ProductAsset[] = [ + { emoji: "🍎", name: "Apple", xStart: "left-[5%]", yStart: "top-[10%]", floatDelay: 0, floatDuration: 4 }, + { emoji: "🥛", name: "Milk", xStart: "right-[5%]", yStart: "top-[15%]", floatDelay: 0.5, floatDuration: 4.5 }, + { emoji: "🍞", name: "Bread", xStart: "left-[0%]", yStart: "top-[45%]", floatDelay: 0.8, floatDuration: 4.8 }, + { emoji: "🥬", name: "Spinach", xStart: "right-[2%]", yStart: "top-[50%]", floatDelay: 1.2, floatDuration: 5.2 }, + { emoji: "🏷️", name: "Price Tag", xStart: "left-[8%]", yStart: "bottom-[12%]", floatDelay: 1.5, floatDuration: 4.2 }, + { emoji: "📲", name: "QR Code", xStart: "right-[8%]", yStart: "bottom-[15%]", floatDelay: 2, floatDuration: 4.6 }, +]; + +export function AnimatedDashboard() { + const reduce = useReducedMotion(); + + // Animation states + const [animatingIndex, setAnimatingIndex] = useState(0); + const [stage, setStage] = useState<"idle" | "flying" | "scanning" | "updating" | "notifying">("idle"); + const [itemsCount, setItemsCount] = useState(142); + const [ordersCount, setOrdersCount] = useState(8); + + useEffect(() => { + if (reduce) return; + + const cycle = setInterval(() => { + // 1. Start Fly-in phase + setStage("flying"); + + // 2. Scan phase: Product reaches center, trigger laser scan + const scanTimer = setTimeout(() => { + setStage("scanning"); + }, 900); + + // 3. Update dashboard values (counter, green success pulse) + const updateTimer = setTimeout(() => { + setStage("updating"); + + // Update specific counters based on what product is processed + if (animatingIndex === 0) { + setItemsCount((c) => c + 1); + } else if (animatingIndex === 1) { + setOrdersCount((c) => c + 1); + } + }, 1400); + + // 4. Micro-notification appears + const notifyTimer = setTimeout(() => { + setStage("notifying"); + }, 1800); + + // 5. Clear notification, return to idle + const idleTimer = setTimeout(() => { + setStage("idle"); + setAnimatingIndex((prev) => (prev + 1) % 4); // Cycle through the first 4 products + }, 5200); + + return () => { + clearTimeout(scanTimer); + clearTimeout(updateTimer); + clearTimeout(notifyTimer); + clearTimeout(idleTimer); + }; + }, 8000); // Complete animation cycle every 8 seconds + + return () => clearInterval(cycle); + }, [animatingIndex, reduce]); + + // Floating variants for the idle products surrounding the dashboard + const floatVariant = (delay: number, duration: number) => ({ + animate: { + y: [0, -10, 0], + rotate: [-3, 3, -3], + scale: [1, 1.02, 1], + transition: { + duration, + repeat: Infinity, + ease: "easeInOut", + delay, + }, + }, + }); + + // Curved flight coordinates relative to the absolute dashboard layout + // Product index maps to original coordinates: + // index 0 (Apple): left-5%, top-10% (x: 5%, y: 10%) -> center (x: 50%, y: 45%) + const flightPaths = [ + { x: ["5%", "25%", "50%"], y: ["10%", "20%", "45%"] }, // Apple + { x: ["95%", "75%", "50%"], y: ["15%", "25%", "45%"] }, // Milk + { x: ["0%", "20%", "50%"], y: ["45%", "40%", "45%"] }, // Bread + { x: ["98%", "78%", "50%"], y: ["50%", "45%", "45%"] }, // Spinach + ]; + + return ( +