SkateSpots/src/components/CrewNip05Badge.tsx
SkateSpots 0b796440f1 feat(i18n): Spanish batch 2 — nav/chrome, events/shops/tours, crews/DMs, settings/auth, wallet/stash/newsletter/stats
~3,470 new keys (5,770 total, EN=ES), ~115 more files wired.
- nav + chromeUi: header, More menu, burger menu, footer, map toolbar widgets
  (sort/trust/weather), spot-type label helper.
- placesUi: events, shops, tours, food. socialUi: crews, DMs, notifications,
  collectives, crew chat/coordinator. settingsUi: settings, auth/signup,
  onboarding, profile edit, legal. walletUi: wallet/Cashu, stash, mints,
  app shop, newsletter, community stats, leaderboards, profile.
- Fixed 738 usages where an agent dropped the socialUi. prefix (caught by check:i18n).
2026-10-02 10:11:06 +07:00

93 lines
2.6 KiB
TypeScript

import { BadgeCheck, Loader2, AlertTriangle } from 'lucide-react';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { useCrewNip05 } from '@/hooks/useCrewNip05';
import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
interface CrewNip05BadgeProps {
nip05?: string;
founderPubkey?: string;
className?: string;
}
/**
* Verified-handle badge for a crew's optional NIP-05.
*
* - `verified`: green check + the handle. The domain confirms the founder key.
* - `mismatch`: red warning — the domain points the handle at a different key.
* - `unreachable`: muted handle (shown but unverified) while the domain is down.
* - `none`: renders nothing.
*/
export function CrewNip05Badge({ nip05, founderPubkey, className }: CrewNip05BadgeProps) {
const { t } = useTranslation();
const { data, isLoading } = useCrewNip05(nip05, founderPubkey);
if (!nip05) return null;
const status = data?.status ?? (isLoading ? 'loading' : 'unreachable');
const handle = nip05.trim().toLowerCase();
if (status === 'mismatch') {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span
className={cn(
'inline-flex items-center gap-1 rounded-full bg-red-500/15 px-2 py-0.5 text-xs font-bold text-red-400',
className,
)}
>
<AlertTriangle className="h-3 w-3" /> {handle}
</span>
</TooltipTrigger>
<TooltipContent>
{t('socialUi.nip05.mismatch')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
if (status === 'verified') {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span
className={cn(
'inline-flex items-center gap-1 rounded-full bg-teal-500/15 px-2 py-0.5 text-xs font-bold text-teal-300',
className,
)}
>
<BadgeCheck className="h-3 w-3" /> {handle}
</span>
</TooltipTrigger>
<TooltipContent>
{t('socialUi.nip05.verified')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
// loading / unreachable — show the handle, muted.
return (
<span
className={cn(
'inline-flex items-center gap-1 rounded-full bg-white/5 px-2 py-0.5 text-xs font-medium text-gray-400',
className,
)}
>
{status === 'loading' ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : null}
{handle}
</span>
);
}