import { useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { ShieldCheck, Users } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { useAuthor } from '@/hooks/useAuthor'; import { useBatchTrustScores } from '@/hooks/useBatchTrustScores'; import { genUserName } from '@/lib/genUserName'; import { cn } from '@/lib/utils'; const TRUSTED_THRESHOLD = 60; function AttendeeRow({ pubkey, trusted }: { pubkey: string; trusted: boolean }) { const author = useAuthor(pubkey); const name = author.data?.metadata?.name ?? genUserName(pubkey); const pic = author.data?.metadata?.picture; const npub = (() => { try { return nip19.npubEncode(pubkey); } catch { return null; } })(); const inner = (
{name.slice(0, 2).toUpperCase()} {name} {trusted && ( Trusted )}
); if (!npub) return inner; return {inner}; } /** * Full attendee list for a host: tabbed Going / Interested, each row showing a * face + name, plus a "trust signal" summarizing how many of the Going crowd * are people the viewer follows or trusted mappers (skate events live or die on * whether real locals show up). */ export function AttendeeList({ going, tentative, className, }: { going: string[]; tentative: string[]; className?: string; }) { const [tab, setTab] = useState<'going' | 'tentative'>('going'); const allPubkeys = useMemo(() => [...new Set([...going, ...tentative])], [going, tentative]); const { data: trustScores } = useBatchTrustScores(allPubkeys); const trustedGoing = useMemo( () => going.filter((pk) => (trustScores?.get(pk) ?? 0) >= TRUSTED_THRESHOLD).length, [going, trustScores], ); if (going.length === 0 && tentative.length === 0) { return (

No RSVPs yet — be the first to say you're going.

); } const list = tab === 'going' ? going : tentative; return (
{/* Trust signal */} {going.length > 0 && (

{going.length} going {trustedGoing > 0 && ( <> {' · '} {trustedGoing} you trust )}

)} {/* Tabs */}
{/* List */} {list.length > 0 ? (
{list.map((pk) => ( = TRUSTED_THRESHOLD} /> ))}
) : (

{tab === 'going' ? 'Nobody has confirmed yet.' : 'Nobody marked interested yet.'}

)}
); }