OpChan/packages/react/src/v1/hooks/useUserDisplay.ts

123 lines
3.6 KiB
TypeScript
Raw Normal View History

2025-09-24 13:45:00 +05:30
import React from 'react';
import { useClient } from '../context/ClientContext';
2025-09-18 22:04:40 +05:30
import { EDisplayPreference, EVerificationStatus } from '@opchan/core';
2025-09-18 17:02:11 +05:30
export interface UserDisplayInfo {
displayName: string;
callSign: string | null;
ensName: string | null;
ordinalDetails: string | null;
verificationLevel: EVerificationStatus;
displayPreference: EDisplayPreference | null;
isLoading: boolean;
error: string | null;
}
2025-09-18 22:04:40 +05:30
/**
* User display hook with caching and reactive updates
2025-09-24 13:45:00 +05:30
* Takes an address and resolves display details for it
2025-09-18 22:04:40 +05:30
*/
2025-09-18 17:02:11 +05:30
export function useUserDisplay(address: string): UserDisplayInfo {
2025-09-18 22:04:40 +05:30
const client = useClient();
2025-09-24 13:45:00 +05:30
const [displayInfo, setDisplayInfo] = React.useState<UserDisplayInfo>({
2025-09-18 17:02:11 +05:30
displayName: `${address.slice(0, 6)}...${address.slice(-4)}`,
callSign: null,
ensName: null,
ordinalDetails: null,
verificationLevel: EVerificationStatus.WALLET_UNCONNECTED,
displayPreference: null,
isLoading: true,
error: null,
});
2025-09-24 13:45:00 +05:30
const getDisplayName = React.useCallback((addr: string) => {
return client.userIdentityService.getDisplayName(addr);
}, [client]);
// Initial load and refresh listener
React.useEffect(() => {
if (!address) return;
2025-09-22 17:49:02 +05:30
let cancelled = false;
2025-09-24 13:45:00 +05:30
const loadUserDisplay = async () => {
2025-09-18 22:04:40 +05:30
try {
const identity = await client.userIdentityService.getUserIdentity(address);
2025-09-24 13:45:00 +05:30
2025-09-22 17:49:02 +05:30
if (cancelled) return;
2025-09-24 13:45:00 +05:30
2025-09-18 22:04:40 +05:30
if (identity) {
setDisplayInfo({
2025-09-22 17:49:02 +05:30
displayName: getDisplayName(address),
2025-09-18 22:04:40 +05:30
callSign: identity.callSign || null,
ensName: identity.ensName || null,
2025-09-24 13:45:00 +05:30
ordinalDetails: identity.ordinalDetails?.ordinalDetails || null,
2025-09-18 22:04:40 +05:30
verificationLevel: identity.verificationStatus,
displayPreference: identity.displayPreference || null,
isLoading: false,
error: null,
});
} else {
2025-09-22 17:49:02 +05:30
setDisplayInfo(prev => ({
...prev,
displayName: getDisplayName(address),
2025-09-18 22:04:40 +05:30
isLoading: false,
error: null,
2025-09-22 17:49:02 +05:30
}));
2025-09-18 22:04:40 +05:30
}
2025-09-18 17:02:11 +05:30
} catch (error) {
2025-09-24 13:45:00 +05:30
if (cancelled) return;
2025-09-22 17:49:02 +05:30
setDisplayInfo(prev => ({
...prev,
2025-09-18 17:02:11 +05:30
isLoading: false,
error: error instanceof Error ? error.message : 'Unknown error',
2025-09-22 17:49:02 +05:30
}));
2025-09-18 17:02:11 +05:30
}
};
2025-09-24 13:45:00 +05:30
loadUserDisplay();
// Subscribe to identity service refresh events
const unsubscribe = client.userIdentityService.addRefreshListener(async (changedAddress) => {
if (changedAddress !== address || cancelled) return;
try {
const identity = await client.userIdentityService.getUserIdentity(address);
if (!identity || cancelled) return;
setDisplayInfo(prev => ({
...prev,
displayName: getDisplayName(address),
callSign: identity.callSign || null,
ensName: identity.ensName || null,
ordinalDetails: identity.ordinalDetails?.ordinalDetails || null,
verificationLevel: identity.verificationStatus,
displayPreference: identity.displayPreference || null,
isLoading: false,
error: null,
}));
} catch (error) {
if (cancelled) return;
setDisplayInfo(prev => ({
...prev,
isLoading: false,
error: error instanceof Error ? error.message : 'Unknown error',
}));
}
2025-09-23 17:35:25 +05:30
});
2025-09-24 13:45:00 +05:30
return () => {
cancelled = true;
try {
unsubscribe();
} catch {
// Ignore unsubscribe errors
}
};
2025-09-23 17:35:25 +05:30
}, [address, client, getDisplayName]);
2025-09-18 17:02:11 +05:30
return displayInfo;
2025-09-24 13:45:00 +05:30
}