import { useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Skeleton } from '@/components/ui/skeleton'; import { useFollowing, useFollowers, useFollowActions } from '@/hooks/useFollowing'; import { useAuthor } from '@/hooks/useAuthor'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { genUserName } from '@/lib/genUserName'; import { Users, UserPlus, UserMinus, Loader2, AlertCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; function FollowingUserCard({ pubkey, onUnfollow }: { pubkey: string; onUnfollow: (pubkey: string) => void }) { const author = useAuthor(pubkey); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(pubkey); const [isUnfollowing, setIsUnfollowing] = useState(false); const handleUnfollow = async () => { setIsUnfollowing(true); await onUnfollow(pubkey); setIsUnfollowing(false); }; return (
{displayName.slice(0, 2).toUpperCase()}
{displayName}
{metadata?.nip05 && (
{metadata.nip05}
)} {!metadata?.nip05 && (
{pubkey.slice(0, 8)}...{pubkey.slice(-8)}
)}
); } function FollowerUserCard({ pubkey }: { pubkey: string }) { const author = useAuthor(pubkey); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(pubkey); return (
{displayName.slice(0, 2).toUpperCase()}
{displayName}
{metadata?.nip05 && (
{metadata.nip05}
)} {!metadata?.nip05 && (
{pubkey.slice(0, 8)}...{pubkey.slice(-8)}
)}
); } export function FollowListManager() { const { user } = useCurrentUser(); const { data: following = [], isLoading: followingLoading } = useFollowing(); const { data: followers = [], isLoading: followersLoading } = useFollowers(); const { unfollow, followByIdentifier, isFollowing, isUnfollowing } = useFollowActions(); const [followInput, setFollowInput] = useState(''); const handleFollow = async (e: React.FormEvent) => { e.preventDefault(); if (!followInput.trim()) return; await followByIdentifier(followInput.trim()); setFollowInput(''); }; if (!user) { return null; } return ( Your Nostr Network Manage who you follow. Following users helps build your Web of Trust and determines which spots show trust badges. Following ({following.length}) Followers ({followers.length}) {/* Add Follow Input */}
setFollowInput(e.target.value)} className="flex-1" disabled={isFollowing} />

💡 Paste a Nostr pubkey (npub1...), NIP-05 address (user@domain.com), or hex pubkey

{/* Following List */} {followingLoading ? (
{Array.from({ length: 3 }).map((_, i) => (
))}
) : following.length > 0 ? (
{following.map((pubkey) => ( ))}
) : (

You're not following anyone yet

Follow skaters to see their spots with ✅ VERIFIED badges

)} {/* Trust Info */} {following.length > 0 && (

✅ Trust Badges Active: Spots created by people you follow will now show VERIFIED badges. Spots by their friends will show TRUSTED badges.

)}
{followersLoading ? (
{Array.from({ length: 3 }).map((_, i) => (
))}
) : followers.length > 0 ? (
{followers.map((pubkey) => ( ))}
) : (

No followers yet

Share your Nostr profile to gain followers!

)}
{/* Info Card */} 💡 How Following Affects Trust Badges

✅ VERIFIED (Green): Spots created by people you directly follow

🟡 TRUSTED (Yellow): Spots created by people your friends follow (2 hops)

⚪ Unverified: Spots by users with no connection to your network

💡 Tip: Follow active skateboarders to see more verified spots and build your trust network!

); }