SkateSpots/src/components/ProBadge.tsx
shakespeare.diy e48a5e6bc5 Add duration tiers + layered NIP-57 zap verification, extend featured/Pro to tours
- Add 4 duration tiers (7d/30d/90d/365d) with per-day price discrimination to usePlatformFee
- PlatformFeePayment: tier selector UI + attempt NIP-57 zap request (a/p tags), graceful fallback to plain LNURL invoice
- Add getZapProviderPubkey + getZapInvoiceFromLightningAddress helpers
- Add useFeaturedVerification hook (verified/claimed/none) querying kind 9735 zap receipts
- ProBadge: optional entityCoord to show green Verified state on detail pages
- Wire entityCoord through all 5 Become* Lab pages + CoachDetailPage
- Add featuredTour fee type; FeaturedUpgrade generalized for events + tours
- CreateTourPage: featured tag on publish + FeaturedUpgrade UI
- TourCard/TourDetailPage: render ProBadge; sort featured tours first
- Document tiers + zap-receipt verification scheme in NIP.md

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 16:18:15 +07:00

59 lines
2 KiB
TypeScript

import { Sparkles, BadgeCheck } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';
import { isFeaturedActive } from '@/lib/types';
import { useFeaturedVerification } from '@/hooks/useFeaturedVerification';
interface ProBadgeProps {
/** The `featuredUntil` unix-seconds timestamp from a parsed entity. */
featuredUntil?: number;
className?: string;
/** Compact = icon only (for dense card corners). */
compact?: boolean;
/**
* When set (an addressable `kind:pubkey:d` coordinate), the badge verifies the
* featured status against a NIP-57 zap receipt and shows a "Verified" state
* when found. Use on detail pages; omit in dense lists to avoid over-fetching.
*/
entityCoord?: string;
}
/**
* "Pro" badge shown on featured Lab profiles, events, and tours.
* Renders nothing if the entity isn't currently featured.
*/
export function ProBadge({ featuredUntil, className, compact = false, entityCoord }: ProBadgeProps) {
const { data: status } = useFeaturedVerification(
entityCoord,
entityCoord ? featuredUntil : undefined,
);
if (!isFeaturedActive(featuredUntil)) return null;
const verified = status === 'verified';
return (
<Badge
className={cn(
'gap-1 border-0 font-black uppercase tracking-wide shadow-sm',
verified
? 'bg-gradient-to-r from-emerald-400 to-green-500 text-black shadow-green-500/30'
: 'bg-gradient-to-r from-amber-400 to-orange-500 text-black shadow-orange-500/30',
compact ? 'px-1.5 py-0 text-[9px]' : 'text-[10px]',
className,
)}
title={
verified
? 'Verified Pro — payment confirmed on-chain via a Nostr zap receipt.'
: 'Pro listing — this profile supports SkateSpots and is featured.'
}
>
{verified ? (
<BadgeCheck className={compact ? 'h-2.5 w-2.5' : 'h-3 w-3'} />
) : (
<Sparkles className={compact ? 'h-2.5 w-2.5' : 'h-3 w-3'} />
)}
Pro
</Badge>
);
}