OpChan/src/components/ui/author-display.tsx

104 lines
3.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { Badge } from '@/components/ui/badge';
import { Shield, Crown } from 'lucide-react';
import { UserVerificationStatus } from '@/lib/forum/types';
2025-08-18 13:52:47 +05:30
import { getEnsName } from '@wagmi/core';
import { config } from '@/lib/identity/wallets/appkit';
2025-08-18 14:07:01 +05:30
import { OrdinalAPI } from '@/lib/identity/ordinal';
interface AuthorDisplayProps {
address: string;
userVerificationStatus?: UserVerificationStatus;
className?: string;
showBadge?: boolean;
}
export function AuthorDisplay({
address,
userVerificationStatus,
className = "",
showBadge = true
}: AuthorDisplayProps) {
const userStatus = userVerificationStatus?.[address];
2025-08-18 13:52:47 +05:30
const [resolvedEns, setResolvedEns] = React.useState<string | undefined>(undefined);
2025-08-18 14:07:01 +05:30
const [resolvedOrdinal, setResolvedOrdinal] = React.useState<boolean | undefined>(undefined);
// Heuristics for address types
const isEthereumAddress = address.startsWith('0x') && address.length === 42;
const isBitcoinAddress = !isEthereumAddress; // simple heuristic for our context
2025-08-18 13:52:47 +05:30
// Lazily resolve ENS name for Ethereum addresses if not provided
React.useEffect(() => {
2025-08-18 14:07:01 +05:30
let cancelled = false;
2025-08-18 13:52:47 +05:30
if (!userStatus?.ensName && isEthereumAddress) {
getEnsName(config, { address: address as `0x${string}` })
2025-08-18 14:07:01 +05:30
.then((name) => { if (!cancelled) setResolvedEns(name || undefined); })
.catch(() => { if (!cancelled) setResolvedEns(undefined); });
} else {
setResolvedEns(userStatus?.ensName);
2025-08-18 13:52:47 +05:30
}
2025-08-18 14:07:01 +05:30
return () => { cancelled = true; };
2025-08-28 18:47:33 +05:30
2025-08-18 14:07:01 +05:30
}, [address, isEthereumAddress, userStatus?.ensName]);
// Lazily check Ordinal ownership for Bitcoin addresses if not provided
React.useEffect(() => {
let cancelled = false;
const run = async () => {
console.log({
isBitcoinAddress, userStatus
})
if (isBitcoinAddress) {
try {
const api = new OrdinalAPI();
const res = await api.getOperatorDetails(address);
if (!cancelled) setResolvedOrdinal(Boolean(res?.has_operators));
} catch {
if (!cancelled) setResolvedOrdinal(undefined);
}
} else {
setResolvedOrdinal(userStatus?.hasOrdinal);
}
};
run();
return () => { cancelled = true; };
2025-08-18 13:52:47 +05:30
// eslint-disable-next-line react-hooks/exhaustive-deps
2025-08-18 14:07:01 +05:30
}, [address, isBitcoinAddress, userStatus?.hasOrdinal]);
2025-08-18 13:52:47 +05:30
2025-08-18 14:07:01 +05:30
const hasENS = Boolean(userStatus?.hasENS) || Boolean(resolvedEns) || Boolean(userStatus?.ensName);
const hasOrdinal = Boolean(userStatus?.hasOrdinal) || Boolean(resolvedOrdinal);
2025-08-18 13:52:47 +05:30
// Only show a badge if the author has ENS or Ordinal ownership (not for basic verification)
const shouldShowBadge = showBadge && (hasENS || hasOrdinal);
const ensName = userStatus?.ensName || resolvedEns;
const displayName = ensName || `${address.slice(0, 6)}...${address.slice(-4)}`;
return (
<div className={`flex items-center gap-1.5 ${className}`}>
<span className="text-xs text-muted-foreground">
{displayName}
</span>
2025-08-18 13:52:47 +05:30
{shouldShowBadge && (
<Badge
variant="secondary"
className="text-xs px-1.5 py-0.5 h-auto bg-green-900/20 border-green-500/30 text-green-400"
>
{hasENS ? (
<>
<Crown className="w-3 h-3 mr-1" />
ENS
</>
) : (
<>
<Shield className="w-3 h-3 mr-1" />
2025-08-18 13:52:47 +05:30
Ordinal
</>
)}
</Badge>
)}
</div>
);
}