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>
307 lines
12 KiB
TypeScript
307 lines
12 KiB
TypeScript
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>
|
||
);
|
||
}
|