SkateSpots/src/components/onboarding/RelayEducation.tsx
shakespeare.diy e29d35f1e4 fix: restore full skate-spots source tree from misplaced src/src/ copy
The entire skate-spots codebase was accidentally copied into src/src/ and
public/public/ instead of src/ and public/ directly. This left the real
src/ directory as blank MKStack template stubs, explaining why the landing
page showed the default template instead of SkateSpots.

Changes made:
- Copied all files from src/src/ up to src/ (App.tsx, AppRouter.tsx, main.tsx,
  all pages, components, hooks, contexts, lib, i18n, test)
- Copied all files from public/public/ up to public/ (images, manifest, etc.)
- Deleted src/src/ and public/public/ nested directories
- Removed HelloWorld.tsx template stub from pages/
- Retained the previously fixed index.css (Tailwind v3 directives)

Full skate-spots feature set is now active:
- All 30+ routes (map, events, spots, coaches, marketplace, wallet, etc.)
- NWCProvider, LanguageProvider, PWAInstallPrompt, AmberCallbackHandler
- Skate community relays (goskatespots.nostr1.com, wotr.relatr.xyz, etc.)
- Outfit Variable font, Amber pre-check in main.tsx
- All hooks (useSkateSpots, useCoaches, useZaps, etc.)
- i18n support (en/es)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-15 22:18:28 +07:00

307 lines
12 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { cn } from '@/lib/utils';
import {
Globe,
Lock,
Unlock,
Key,
ChevronRight,
ChevronLeft,
CheckCircle2,
AlertTriangle,
Store,
Users,
Shield,
} from 'lucide-react';
interface RelayEducationProps {
onComplete: () => void;
onSkip?: () => void;
}
export function RelayEducation({ onComplete, onSkip }: RelayEducationProps) {
const [currentStep, setCurrentStep] = useState(1);
const totalSteps = 3;
const nextStep = () => {
if (currentStep < totalSteps) {
setCurrentStep(currentStep + 1);
} else {
onComplete();
}
};
const prevStep = () => {
if (currentStep > 1) {
setCurrentStep(currentStep - 1);
}
};
return (
<Card className="w-full max-w-lg mx-auto border-2 border-purple-500/30 bg-gradient-to-br from-purple-500/5 to-blue-500/5">
<CardContent className="p-6">
{/* Progress */}
<div className="mb-6">
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-bold text-gray-400 uppercase tracking-wide">
Understanding Nostr
</span>
<span className="text-xs text-gray-500">
Step {currentStep} of {totalSteps}
</span>
</div>
<Progress value={(currentStep / totalSteps) * 100} className="h-1.5" />
</div>
{/* Step 1: Relay Concept */}
{currentStep === 1 && (
<div className="space-y-6">
<div className="text-center">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-purple-500/20 mb-4">
<Globe className="h-8 w-8 text-purple-500" />
</div>
<h2 className="text-xl font-black uppercase mb-2">Understanding Relays</h2>
<p className="text-gray-400 text-sm">
Think of relays like skate shops that share news about spots
</p>
</div>
{/* Visual Diagram */}
<div className="flex items-center justify-center gap-2 py-4">
<div className="flex flex-col items-center gap-1">
<div className="w-12 h-12 rounded-lg bg-red-500/20 flex items-center justify-center">
<span className="text-2xl">🛹</span>
</div>
<span className="text-xs text-gray-500">You</span>
</div>
<ChevronRight className="h-5 w-5 text-gray-600" />
<div className="flex flex-col items-center gap-1">
<div className="flex gap-1">
<div className="w-10 h-10 rounded-lg bg-purple-500/20 flex items-center justify-center">
<Store className="h-5 w-5 text-purple-500" />
</div>
<div className="w-10 h-10 rounded-lg bg-purple-500/20 flex items-center justify-center">
<Store className="h-5 w-5 text-purple-500" />
</div>
</div>
<span className="text-xs text-gray-500">Relays</span>
</div>
<ChevronRight className="h-5 w-5 text-gray-600" />
<div className="flex flex-col items-center gap-1">
<div className="w-12 h-12 rounded-lg bg-green-500/20 flex items-center justify-center">
<Users className="h-6 w-6 text-green-500" />
</div>
<span className="text-xs text-gray-500">Skaters</span>
</div>
</div>
<div className="space-y-3 text-sm">
<div className="flex items-start gap-3 p-3 rounded-lg bg-green-500/10 border border-green-500/20">
<CheckCircle2 className="h-5 w-5 text-green-500 flex-shrink-0 mt-0.5" />
<div>
<span className="font-bold text-green-400">No company owns your account</span>
<p className="text-gray-400 text-xs mt-0.5">Your identity lives on multiple relay servers</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 rounded-lg bg-green-500/10 border border-green-500/20">
<CheckCircle2 className="h-5 w-5 text-green-500 flex-shrink-0 mt-0.5" />
<div>
<span className="font-bold text-green-400">Your posts can't be deleted by others</span>
<p className="text-gray-400 text-xs mt-0.5">Data is distributed across the network</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 rounded-lg bg-amber-500/10 border border-amber-500/20">
<AlertTriangle className="h-5 w-5 text-amber-500 flex-shrink-0 mt-0.5" />
<div>
<span className="font-bold text-amber-400">Relay operators can see public posts</span>
<p className="text-gray-400 text-xs mt-0.5">Think of it like posting on a bulletin board</p>
</div>
</div>
</div>
</div>
)}
{/* Step 2: Public vs Private */}
{currentStep === 2 && (
<div className="space-y-6">
<div className="text-center">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-blue-500/20 mb-4">
<Shield className="h-8 w-8 text-blue-500" />
</div>
<h2 className="text-xl font-black uppercase mb-2">Public vs Private</h2>
<p className="text-gray-400 text-sm">
Know what's visible and what's encrypted
</p>
</div>
<div className="grid gap-4">
{/* Public */}
<div className="p-4 rounded-lg bg-red-500/10 border border-red-500/20">
<div className="flex items-center gap-2 mb-3">
<Unlock className="h-5 w-5 text-red-400" />
<span className="font-bold text-red-400 uppercase text-sm">Public (Anyone Can See)</span>
</div>
<div className="space-y-2 text-sm text-gray-300">
<div className="flex items-center gap-2">
<span className="text-red-400">•</span>
<span>Spots you add to the map</span>
</div>
<div className="flex items-center gap-2">
<span className="text-red-400">•</span>
<span>Reviews and comments</span>
</div>
<div className="flex items-center gap-2">
<span className="text-red-400">•</span>
<span>Your profile info (name, picture)</span>
</div>
<div className="flex items-center gap-2">
<span className="text-red-400">•</span>
<span>Who you follow</span>
</div>
</div>
</div>
{/* Private */}
<div className="p-4 rounded-lg bg-green-500/10 border border-green-500/20">
<div className="flex items-center gap-2 mb-3">
<Lock className="h-5 w-5 text-green-400" />
<span className="font-bold text-green-400 uppercase text-sm">Private (Encrypted)</span>
</div>
<div className="space-y-2 text-sm text-gray-300">
<div className="flex items-center gap-2">
<span className="text-green-400">•</span>
<span>Direct messages</span>
</div>
<div className="flex items-center gap-2">
<span className="text-green-400">•</span>
<span>Wallet communications</span>
</div>
</div>
</div>
</div>
<div className="p-3 rounded-lg bg-gray-800/50 border border-gray-700">
<p className="text-xs text-gray-400 text-center">
<span className="text-amber-400 font-bold">Note:</span> Posts may be stored permanently on relays.
Think before you post - just like real life!
</p>
</div>
</div>
)}
{/* Step 3: Key Backup */}
{currentStep === 3 && (
<div className="space-y-6">
<div className="text-center">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-amber-500/20 mb-4">
<Key className="h-8 w-8 text-amber-500" />
</div>
<h2 className="text-xl font-black uppercase mb-2">Your Keys = Your Account</h2>
<p className="text-gray-400 text-sm">
This is the most important thing to understand
</p>
</div>
<div className="space-y-4">
<div className="p-4 rounded-lg bg-amber-500/10 border border-amber-500/30">
<h3 className="font-bold text-amber-400 mb-2 flex items-center gap-2">
<Key className="h-4 w-4" />
Your Secret Key (nsec)
</h3>
<p className="text-sm text-gray-300 mb-3">
Think of it like your skateboard - never lend it to anyone.
It proves you own your account.
</p>
<div className="space-y-2 text-sm">
<div className="flex items-start gap-2 text-red-400">
<span className="font-bold">⚠️</span>
<span>If lost, your account can't be recovered</span>
</div>
<div className="flex items-start gap-2 text-red-400">
<span className="font-bold">⚠️</span>
<span>No "forgot password" - nobody can reset it</span>
</div>
<div className="flex items-start gap-2 text-green-400">
<span className="font-bold">✓</span>
<span>Back it up and store it safely</span>
</div>
</div>
</div>
<div className="p-4 rounded-lg bg-purple-500/10 border border-purple-500/30">
<h3 className="font-bold text-purple-400 mb-2 flex items-center gap-2">
<Globe className="h-4 w-4" />
Your Public Key (npub)
</h3>
<p className="text-sm text-gray-300">
This is like your username - share it freely so others can find you!
</p>
</div>
</div>
<div className="p-3 rounded-lg bg-green-500/10 border border-green-500/20 text-center">
<p className="text-sm text-green-400 font-bold">
🔐 You're in control - no company can lock you out!
</p>
</div>
</div>
)}
{/* Navigation */}
<div className="flex items-center justify-between mt-6 pt-4 border-t border-gray-800">
<div>
{currentStep > 1 ? (
<Button
variant="ghost"
onClick={prevStep}
className="gap-1"
>
<ChevronLeft className="h-4 w-4" />
Back
</Button>
) : onSkip ? (
<Button
variant="ghost"
onClick={onSkip}
className="text-gray-500"
>
Skip
</Button>
) : (
<div />
)}
</div>
<Button
onClick={nextStep}
className={cn(
"gap-1",
currentStep === totalSteps
? "bg-green-500 hover:bg-green-600"
: "bg-purple-500 hover:bg-purple-600"
)}
>
{currentStep === totalSteps ? (
<>
Got It!
<CheckCircle2 className="h-4 w-4" />
</>
) : (
<>
Next
<ChevronRight className="h-4 w-4" />
</>
)}
</Button>
</div>
</CardContent>
</Card>
);
}