import { useState } from 'react'; import { Link } from 'react-router-dom'; import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Skeleton } from '@/components/ui/skeleton'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { MapPin, Store, Bookmark, MoreVertical, Flag, ShieldCheck, Trash2 } from 'lucide-react'; import { useAuthor } from '@/hooks/useAuthor'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useVenuesWithPasses } from '@/hooks/useRiderCard'; import type { SpotCommunityMini } from '@/hooks/useBatchSpotCommunityScores'; import { genUserName } from '@/lib/genUserName'; import { ZapButton } from '@/components/ZapButton'; import { TrustBadge } from '@/components/TrustBadge'; import { OfficialBadge } from '@/components/OfficialBadge'; import { AddToCollectionDialog } from '@/components/AddToCollectionDialog'; import { ReportDialog } from '@/components/ReportDialog'; import { MuteMenuItem } from '@/components/MuteMenuItem'; import { DeleteEntityDialog } from '@/components/DeleteEntityDialog'; import { SpotStatusBadge } from '@/components/SpotStatusBadge'; import type { SkateSpot } from '@/lib/types'; import { ACCESS_TYPE_INFO, SHELTER_INFO, SKATE_SHOP_KIND } from '@/lib/types'; import { spotTypeLabel } from '@/lib/spotTypeLabel'; import { ACCESS_TYPE_KEYS, SHELTER_SHORT_KEYS } from '@/lib/labelKeys'; import type { AggregatedSpotStatus } from '@/hooks/useSpotStatus'; import { useTranslation } from '@/contexts/language'; import { isAdminPubkey } from '@/lib/admins'; import { cn } from '@/lib/utils'; interface SpotCardProps { spot: SkateSpot; /** Optional community status, passed in batched from the parent list/map. */ status?: AggregatedSpotStatus | null; /** Optional community confidence, passed in batched from the parent list/map. */ community?: SpotCommunityMini; } export function SpotCard({ spot, status, community }: SpotCardProps) { const { t } = useTranslation(); const author = useAuthor(spot.pubkey); const { user } = useCurrentUser(); const metadata = author.data?.metadata; const displayName = metadata?.name ?? genUserName(spot.pubkey); const [showCollectionDialog, setShowCollectionDialog] = useState(false); const [showReportDialog, setShowReportDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); // Determine if this is a shop or a spot const isShop = spot.types.includes('shop'); const isOwner = user?.pubkey === spot.pubkey; const isAdmin = isAdminPubkey(user?.pubkey); const canDelete = !!user && (isOwner || isAdmin); const route = isShop ? `/shop/${spot.pubkey}/${spot.identifier}` : `/spot/${spot.pubkey}/${spot.identifier}`; // Shops that actually issue access passes get a badge (one shared, cached query). const { data: passIndex } = useVenuesWithPasses(); const hasPasses = isShop && !!passIndex?.coords.has(`${SKATE_SHOP_KIND}:${spot.pubkey}:${spot.identifier}`); // Dim spots the community has reported as gone/demolished. const isGone = status?.status === 'gone'; return (
); } export function SpotCardSkeleton() { return (