import { nip19 } from 'nostr-tools'; import { useParams, Link } from 'react-router-dom'; import { Layout } from '@/components/Layout'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { Badge } from '@/components/ui/badge'; import { Skeleton } from '@/components/ui/skeleton'; import { ZapButton } from '@/components/ZapButton'; import { useAuthor } from '@/hooks/useAuthor'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useUserSkateSpots } from '@/hooks/useSkateSpots'; import { useUserShops } from '@/hooks/useShops'; import { SpotCard, SpotCardSkeleton } from '@/components/SpotCard'; import { genUserName } from '@/lib/genUserName'; import NotFound from './NotFound'; import { MapPin, Store, MessageCircle, Globe, Zap, Calendar, ExternalLink, ArrowLeft, Copy, Check, } from 'lucide-react'; import { useState } from 'react'; import { UserStatusIndicator } from '@/components/UserStatusIndicator'; function ProfilePage({ pubkey }: { pubkey: string }) { const author = useAuthor(pubkey); const { user } = useCurrentUser(); const { data: spots, isLoading: spotsLoading } = useUserSkateSpots(pubkey); const { data: shops, isLoading: shopsLoading } = useUserShops(pubkey); const [copied, setCopied] = useState(false); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(pubkey); const avatar = metadata?.picture; const banner = metadata?.banner; const about = metadata?.about; const website = metadata?.website; const nip05 = metadata?.nip05; const lud16 = metadata?.lud16; const npub = nip19.npubEncode(pubkey); const isOwnProfile = user?.pubkey === pubkey; const handleCopyNpub = () => { navigator.clipboard.writeText(npub); setCopied(true); setTimeout(() => setCopied(false), 2000); }; // Create a mock event for zapping const profileEvent = author.data?.event; if (author.isLoading) { return ( ); } return ( {/* Back Button */} Back to Leaderboard {/* Banner */} {banner && ( )} {/* Profile Header */} {displayName.slice(0, 2).toUpperCase()} {/* User Status Indicator */} {displayName} {nip05 && ( {nip05} )} {/* Actions */} {!isOwnProfile && user && ( Message )} {profileEvent && !isOwnProfile && ( )} {/* Profile Info */} {/* Main Content */} {/* About */} {about && ( {about} )} {/* Spots by this user */} Spots Added {spots && spots.length > 0 && ( {spots.length} )} {spotsLoading ? ( {Array.from({ length: 2 }).map((_, i) => ( ))} ) : spots && spots.length > 0 ? ( {spots.slice(0, 4).map((spot) => ( ))} ) : ( No spots added yet )} {/* Shops by this user */} Shops Added {shops && shops.length > 0 && ( {shops.length} )} {shopsLoading ? ( {Array.from({ length: 2 }).map((_, i) => ( ))} ) : shops && shops.length > 0 ? ( {shops.slice(0, 4).map((shop) => ( {shop.name} {shop.location && ( {shop.location} )} ))} ) : ( No shops added yet )} {/* Sidebar */} {/* Quick Info Card */} Info {website && ( {website.replace(/^https?:\/\//, '')} )} {lud16 && ( {lud16} )} {/* Npub Copy */} {copied ? ( ) : ( )} {copied ? 'Copied!' : `${npub.slice(0, 12)}...${npub.slice(-8)}`} {/* Stats Card */} Contributions {spots?.length || 0} Spots {shops?.length || 0} Shops {/* Tip Card */} {!isOwnProfile && profileEvent && ( Support this mapper Send a zap to thank them for their contributions )} ); } export function NIP19Page() { const { nip19: identifier } = useParams<{ nip19: string }>(); if (!identifier) { return ; } let decoded; try { decoded = nip19.decode(identifier); } catch { return ; } const { type, data } = decoded; switch (type) { case 'npub': return ; case 'nprofile': return ; case 'note': // AI agent should implement note view here return ; case 'nevent': // AI agent should implement event view here return ; case 'naddr': // AI agent should implement addressable event view here return ; default: return ; } }
{nip05}
{about}
No spots added yet
{shop.location}
No shops added yet
{spots?.length || 0}
Spots
{shops?.length || 0}
Shops
Send a zap to thank them for their contributions