~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).
93 lines
2.6 KiB
TypeScript
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>
|
|
);
|
|
}
|