From 2c58bb43263feba8524b8b07bcd1cd2b570a116a Mon Sep 17 00:00:00 2001 From: 0xMosas Date: Thu, 26 Feb 2026 18:18:52 +0100 Subject: [PATCH 1/2] feat(components): add onboarding modal for first-time users Four-step walkthrough covering: platform introduction, how tipping works, Stacks address format, and activity tracking features. State persisted in localStorage to show only on first visit. --- frontend/src/components/Onboarding.jsx | 101 +++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 frontend/src/components/Onboarding.jsx diff --git a/frontend/src/components/Onboarding.jsx b/frontend/src/components/Onboarding.jsx new file mode 100644 index 00000000..f5cfd1c1 --- /dev/null +++ b/frontend/src/components/Onboarding.jsx @@ -0,0 +1,101 @@ +import { useState, useEffect } from 'react'; + +const STORAGE_KEY = 'tipstream_onboarding_completed'; + +const steps = [ + { + title: 'Welcome to TipStream', + description: 'TipStream lets you send STX tips to creators and supporters on the Stacks blockchain, secured by Bitcoin.', + icon: '👋', + }, + { + title: 'How Tipping Works', + description: 'Enter a Stacks address, choose an amount, and add an optional message. A small 0.5% platform fee is deducted automatically. The rest goes directly to the recipient.', + icon: '⚡', + }, + { + title: 'Stacks Addresses', + description: 'Stacks addresses start with "SP" on mainnet or "ST" on testnet. You can find someone\'s address on their profile or from the Stacks explorer.', + icon: '🔗', + }, + { + title: 'Track Your Activity', + description: 'View your tip history, check the leaderboard, and manage your profile. All transactions are recorded on-chain for full transparency.', + icon: '📊', + }, +]; + +export default function Onboarding({ onComplete }) { + const [currentStep, setCurrentStep] = useState(0); + const [visible, setVisible] = useState(false); + + useEffect(() => { + const completed = localStorage.getItem(STORAGE_KEY); + if (!completed) { + setVisible(true); + } + }, []); + + const handleNext = () => { + if (currentStep < steps.length - 1) { + setCurrentStep(currentStep + 1); + } else { + handleComplete(); + } + }; + + const handleSkip = () => { + handleComplete(); + }; + + const handleComplete = () => { + localStorage.setItem(STORAGE_KEY, 'true'); + setVisible(false); + if (onComplete) onComplete(); + }; + + if (!visible) return null; + + const step = steps[currentStep]; + const isLast = currentStep === steps.length - 1; + + return ( +
+
+
+ {step.icon} +

{step.title}

+

{step.description}

+
+ +
+ {steps.map((_, i) => ( +
+ ))} +
+ +
+ {!isLast && ( + + )} + +
+
+
+ ); +} From 7fde1c10902e9dfcff2cebd2519b755f41e42940 Mon Sep 17 00:00:00 2001 From: 0xMosas Date: Thu, 26 Feb 2026 18:19:12 +0100 Subject: [PATCH 2/2] feat(App): integrate onboarding flow after wallet connection Show the onboarding modal when an authenticated user has not completed the tutorial. Modal renders above the main navigation and content area, dismissing permanently on completion or skip. --- frontend/src/App.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 73047d12..5e2897a2 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -4,6 +4,7 @@ import { userSession, authenticate, disconnect } from './utils/stacks'; import Header from './components/Header'; import SendTip from './components/SendTip'; import OfflineBanner from './components/OfflineBanner'; +import Onboarding from './components/Onboarding'; import { AnimatedHero } from './components/ui/animated-hero'; import { ToastContainer, useToast } from './components/ui/toast'; @@ -66,6 +67,7 @@ function App() {
{userData ? (
+