From 86dcb39379f8857f15188b19e015fb8c8bfb3e94 Mon Sep 17 00:00:00 2001 From: bbkenny Date: Sun, 7 Jun 2026 17:47:40 +0100 Subject: [PATCH] feat: add 4-slide onboarding modal for first-time visitors --- frontend/app/page.tsx | 3 + frontend/components/OnboardingModal.tsx | 134 ++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 frontend/components/OnboardingModal.tsx diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index 8a035fe..4f30c1b 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -17,6 +17,8 @@ interface EscrowItem { status: "Locked" | "Executed" | "Refunded"; } +import OnboardingModal from "@/components/OnboardingModal"; + export default function Home() { const { address, connect } = useWallet(); const { createEscrow, isPending: isCreating } = useCreateEscrow(); @@ -123,6 +125,7 @@ export default function Home() { return (
+
diff --git a/frontend/components/OnboardingModal.tsx b/frontend/components/OnboardingModal.tsx new file mode 100644 index 0000000..fae44bc --- /dev/null +++ b/frontend/components/OnboardingModal.tsx @@ -0,0 +1,134 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { Zap, ShieldCheck, Clock, CheckCircle2, X } from "lucide-react"; + +const slides = [ + { + id: 1, + title: "Welcome to EpochSend", + description: "The next generation of intent-based conditional payments built securely on the Stellar network.", + icon: , + }, + { + id: 2, + title: "Time-Locked Escrows", + description: "Easily lock digital assets on-chain. Funds are automatically released to the recipient only when the exact timestamp is reached.", + icon: , + }, + { + id: 3, + title: "Trusted Arbiters", + description: "Need human intervention? Assign a trusted third-party arbiter to manually release or refund payments when conditions are met.", + icon: , + }, + { + id: 4, + title: "Fully Decentralized", + description: "Powered entirely by Soroban smart contracts. No middlemen, no hidden fees, and complete transparency.", + icon: , + }, +]; + +export default function OnboardingModal() { + const [isOpen, setIsOpen] = useState(false); + const [currentSlide, setCurrentSlide] = useState(0); + + useEffect(() => { + // Check local storage to see if user has seen onboarding + const hasSeenOnboarding = localStorage.getItem("hasSeenEpochSendOnboarding"); + if (!hasSeenOnboarding) { + setIsOpen(true); + } + }, []); + + const handleClose = () => { + localStorage.setItem("hasSeenEpochSendOnboarding", "true"); + setIsOpen(false); + }; + + const nextSlide = () => { + if (currentSlide < slides.length - 1) { + setCurrentSlide(currentSlide + 1); + } else { + handleClose(); + } + }; + + if (!isOpen) return null; + + return ( + + {isOpen && ( +
+ + {/* Background Glow */} +
+ + {/* Close Button */} + + + {/* Slide Content */} + + +
+ {slides[currentSlide].icon} +
+ +
+

+ {slides[currentSlide].title} +

+

+ {slides[currentSlide].description} +

+
+
+
+ + {/* Navigation & Progress */} +
+ {/* Dots */} +
+ {slides.map((_, index) => ( +
+ ))} +
+ + {/* Action Button */} + +
+ +
+ )} + + ); +}