diff --git a/src/components/InboxViewer.tsx b/src/components/InboxViewer.tsx index 0e18834..e818a38 100644 --- a/src/components/InboxViewer.tsx +++ b/src/components/InboxViewer.tsx @@ -73,12 +73,20 @@ function useIsMobile() { return isMobile; } +/** + * Format relay URL for display + */ +function formatRelayForDisplay(url: string): string { + return url.replace(/^wss?:\/\//, "").replace(/\/$/, ""); +} + /** * Conversation info for display */ interface ConversationInfo { id: string; partnerPubkey: string; + inboxRelays?: string[]; lastMessage?: { content: string; timestamp: number; @@ -101,12 +109,12 @@ const ConversationListItem = memo(function ConversationListItem({ return (
- +
)}
+ {/* Inbox relays */} + {conversation.inboxRelays && conversation.inboxRelays.length > 0 && ( +
+ {conversation.inboxRelays.map(formatRelayForDisplay).join(", ")} +
+ )} {conversation.lastMessage && (
{conversation.lastMessage.isOwn && ( @@ -209,7 +223,7 @@ export function InboxViewer() { // State const [selectedPartner, setSelectedPartner] = useState(null); const [sidebarOpen, setSidebarOpen] = useState(false); - const [sidebarWidth, setSidebarWidth] = useState(300); + const [sidebarWidth, setSidebarWidth] = useState(280); const [isResizing, setIsResizing] = useState(false); const [isDecrypting, setIsDecrypting] = useState(false); @@ -225,15 +239,55 @@ export function InboxViewer() { [adapter, activePubkey], ); + // Track inbox relays for each partner + const [partnerRelays, setPartnerRelays] = useState>( + new Map(), + ); + + // Fetch inbox relays for conversation partners + useEffect(() => { + if (!conversations) return; + + const fetchRelays = async () => { + const newRelays = new Map(); + + for (const conv of conversations) { + const partner = conv.participants.find( + (p) => p.pubkey !== activePubkey, + ); + if (!partner) continue; + + // Skip if already fetched + if (partnerRelays.has(partner.pubkey)) { + newRelays.set(partner.pubkey, partnerRelays.get(partner.pubkey)!); + continue; + } + + try { + const relays = await adapter.getInboxRelays(partner.pubkey); + newRelays.set(partner.pubkey, relays); + } catch { + newRelays.set(partner.pubkey, []); + } + } + + setPartnerRelays(newRelays); + }; + + fetchRelays(); + }, [conversations, activePubkey, adapter, partnerRelays]); + // Convert to display format const conversationList = useMemo(() => { if (!conversations || !activePubkey) return []; return conversations.map((conv): ConversationInfo => { const partner = conv.participants.find((p) => p.pubkey !== activePubkey); + const partnerPubkey = partner?.pubkey || ""; return { id: conv.id, - partnerPubkey: partner?.pubkey || "", + partnerPubkey, + inboxRelays: partnerRelays.get(partnerPubkey), lastMessage: conv.lastMessage ? { content: conv.lastMessage.content, @@ -243,7 +297,7 @@ export function InboxViewer() { : undefined, }; }); - }, [conversations, activePubkey]); + }, [conversations, activePubkey, partnerRelays]); // Handle conversation selection const handleSelect = useCallback( @@ -405,7 +459,7 @@ export function InboxViewer() { return (
- + Messages diff --git a/src/lib/chat/adapters/nip-17-adapter.ts b/src/lib/chat/adapters/nip-17-adapter.ts index cd6e7e0..f4aaed1 100644 --- a/src/lib/chat/adapters/nip-17-adapter.ts +++ b/src/lib/chat/adapters/nip-17-adapter.ts @@ -496,7 +496,7 @@ export class Nip17Adapter extends ChatProtocolAdapter { this.cleanup(conversationId); // Get user's private inbox relays (kind 10050) - const inboxRelays = await this.getInboxRelays(pubkey); + const inboxRelays = await this.fetchInboxRelays(pubkey); if (inboxRelays.length === 0) { console.warn( "[NIP-17] No inbox relays found. Configure kind 10050 to receive DMs.", @@ -547,10 +547,28 @@ export class Nip17Adapter extends ChatProtocolAdapter { this.subscriptions.set(conversationId, subscription); } + /** Cache for inbox relays */ + private inboxRelayCache = new Map(); + /** - * Get private inbox relays for a user (kind 10050) + * Get inbox relays for a user (public API for UI display) + * Returns cached value or fetches from network */ - private async getInboxRelays(pubkey: string): Promise { + async getInboxRelays(pubkey: string): Promise { + const cached = this.inboxRelayCache.get(pubkey); + if (cached) return cached; + + const relays = await this.fetchInboxRelays(pubkey); + if (relays.length > 0) { + this.inboxRelayCache.set(pubkey, relays); + } + return relays; + } + + /** + * Fetch private inbox relays for a user (kind 10050) + */ + private async fetchInboxRelays(pubkey: string): Promise { // Try to fetch from EventStore first const existing = await firstValueFrom( eventStore.replaceable(DM_RELAY_LIST_KIND, pubkey, ""),