mirror of
https://github.com/dergigi/boris.git
synced 2025-12-18 15:14:20 +01:00
fix: resolve Rules of Hooks violation by using eventStore instead of useEventModel in map
This commit is contained in:
@@ -24,7 +24,7 @@ export const useMarkdownToHTML = (
|
|||||||
console.log('[useMarkdownToHTML] Hook called, markdown length:', markdown?.length || 0, 'hasRelayPool:', !!relayPool)
|
console.log('[useMarkdownToHTML] Hook called, markdown length:', markdown?.length || 0, 'hasRelayPool:', !!relayPool)
|
||||||
|
|
||||||
// Resolve profile labels progressively as profiles load
|
// Resolve profile labels progressively as profiles load
|
||||||
const profileLabels = useProfileLabels(markdown || '')
|
const profileLabels = useProfileLabels(markdown || '', relayPool)
|
||||||
console.log('[useMarkdownToHTML] Profile labels size:', profileLabels.size)
|
console.log('[useMarkdownToHTML] Profile labels size:', profileLabels.size)
|
||||||
|
|
||||||
// Fetch article titles
|
// Fetch article titles
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo, useState, useEffect } from 'react'
|
||||||
import { useEventModel } from 'applesauce-react/hooks'
|
import { Hooks } from 'applesauce-react'
|
||||||
import { Models, Helpers } from 'applesauce-core'
|
import { Helpers, IEventStore } from 'applesauce-core'
|
||||||
import { getContentPointers } from 'applesauce-factory/helpers'
|
import { getContentPointers } from 'applesauce-factory/helpers'
|
||||||
|
import { RelayPool } from 'applesauce-relay'
|
||||||
|
import { fetchProfiles } from '../services/profileService'
|
||||||
|
|
||||||
const { getPubkeyFromDecodeResult, encodeDecodeResult } = Helpers
|
const { getPubkeyFromDecodeResult, encodeDecodeResult } = Helpers
|
||||||
|
|
||||||
@@ -9,7 +11,9 @@ const { getPubkeyFromDecodeResult, encodeDecodeResult } = Helpers
|
|||||||
* Hook to resolve profile labels from content containing npub/nprofile identifiers
|
* Hook to resolve profile labels from content containing npub/nprofile identifiers
|
||||||
* Returns a Map of encoded identifier -> display name that updates progressively as profiles load
|
* Returns a Map of encoded identifier -> display name that updates progressively as profiles load
|
||||||
*/
|
*/
|
||||||
export function useProfileLabels(content: string): Map<string, string> {
|
export function useProfileLabels(content: string, relayPool?: RelayPool | null): Map<string, string> {
|
||||||
|
const eventStore = Hooks.useEventStore()
|
||||||
|
|
||||||
// Extract profile pointers (npub and nprofile) using applesauce helpers
|
// Extract profile pointers (npub and nprofile) using applesauce helpers
|
||||||
const profileData = useMemo(() => {
|
const profileData = useMemo(() => {
|
||||||
console.log('[useProfileLabels] Processing content, length:', content?.length || 0)
|
console.log('[useProfileLabels] Processing content, length:', content?.length || 0)
|
||||||
@@ -18,19 +22,18 @@ export function useProfileLabels(content: string): Map<string, string> {
|
|||||||
console.log('[useProfileLabels] Found pointers:', pointers.length, 'types:', pointers.map(p => p.type))
|
console.log('[useProfileLabels] Found pointers:', pointers.length, 'types:', pointers.map(p => p.type))
|
||||||
const filtered = pointers.filter(p => p.type === 'npub' || p.type === 'nprofile')
|
const filtered = pointers.filter(p => p.type === 'npub' || p.type === 'nprofile')
|
||||||
console.log('[useProfileLabels] Profile pointers:', filtered.length)
|
console.log('[useProfileLabels] Profile pointers:', filtered.length)
|
||||||
const result = filtered
|
const result: Array<{ pubkey: string; encoded: string }> = []
|
||||||
.map(pointer => {
|
filtered.forEach(pointer => {
|
||||||
try {
|
try {
|
||||||
return {
|
const pubkey = getPubkeyFromDecodeResult(pointer)
|
||||||
pubkey: getPubkeyFromDecodeResult(pointer),
|
const encoded = encodeDecodeResult(pointer)
|
||||||
encoded: encodeDecodeResult(pointer)
|
if (pubkey && encoded) {
|
||||||
}
|
result.push({ pubkey, encoded: encoded as string })
|
||||||
} catch (err) {
|
|
||||||
console.error('[useProfileLabels] Error processing pointer:', err, pointer)
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
})
|
} catch (err) {
|
||||||
.filter((p): p is { pubkey: string; encoded: string } => p !== null && !!p.pubkey)
|
console.error('[useProfileLabels] Error processing pointer:', err, pointer)
|
||||||
|
}
|
||||||
|
})
|
||||||
console.log('[useProfileLabels] Profile data after filtering:', result.length)
|
console.log('[useProfileLabels] Profile data after filtering:', result.length)
|
||||||
return result
|
return result
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -39,27 +42,76 @@ export function useProfileLabels(content: string): Map<string, string> {
|
|||||||
}
|
}
|
||||||
}, [content])
|
}, [content])
|
||||||
|
|
||||||
// Fetch profiles for all found pubkeys (progressive loading)
|
const [profileLabels, setProfileLabels] = useState<Map<string, string>>(new Map())
|
||||||
const profiles = profileData.map(({ pubkey }) =>
|
|
||||||
useEventModel(Models.ProfileModel, pubkey ? [pubkey] : null)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Build profile labels map that updates reactively as profiles load
|
// Build initial labels from eventStore, then fetch missing profiles
|
||||||
return useMemo(() => {
|
useEffect(() => {
|
||||||
|
console.log('[useProfileLabels] Building labels, profileData:', profileData.length, 'hasEventStore:', !!eventStore)
|
||||||
|
|
||||||
|
// First, get profiles from eventStore synchronously
|
||||||
const labels = new Map<string, string>()
|
const labels = new Map<string, string>()
|
||||||
console.log('[useProfileLabels] Building labels map, profileData:', profileData.length, 'profiles:', profiles.length)
|
const pubkeysToFetch: string[] = []
|
||||||
profileData.forEach(({ encoded }, index) => {
|
|
||||||
const profile = profiles[index]
|
profileData.forEach(({ encoded, pubkey }) => {
|
||||||
if (profile) {
|
if (eventStore) {
|
||||||
const displayName = profile.name || profile.display_name || profile.nip05
|
const profileEvent = eventStore.getEvent(pubkey + ':0')
|
||||||
if (displayName) {
|
if (profileEvent) {
|
||||||
labels.set(encoded, `@${displayName}`)
|
try {
|
||||||
console.log('[useProfileLabels] Set label:', encoded, '->', displayName)
|
const profileData = JSON.parse(profileEvent.content || '{}') as { name?: string; display_name?: string; nip05?: string }
|
||||||
|
const displayName = profileData.display_name || profileData.name || profileData.nip05
|
||||||
|
if (displayName) {
|
||||||
|
labels.set(encoded, `@${displayName}`)
|
||||||
|
console.log('[useProfileLabels] Found in eventStore:', encoded, '->', displayName)
|
||||||
|
} else {
|
||||||
|
pubkeysToFetch.push(pubkey)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
pubkeysToFetch.push(pubkey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pubkeysToFetch.push(pubkey)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pubkeysToFetch.push(pubkey)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log('[useProfileLabels] Final labels map size:', labels.size)
|
|
||||||
return labels
|
// Update labels with what we found in eventStore
|
||||||
}, [profileData, profiles])
|
setProfileLabels(new Map(labels))
|
||||||
|
|
||||||
|
// Fetch missing profiles asynchronously
|
||||||
|
if (pubkeysToFetch.length > 0 && relayPool && eventStore) {
|
||||||
|
console.log('[useProfileLabels] Fetching', pubkeysToFetch.length, 'missing profiles')
|
||||||
|
fetchProfiles(relayPool, eventStore as unknown as IEventStore, pubkeysToFetch)
|
||||||
|
.then(profiles => {
|
||||||
|
// Rebuild labels map with fetched profiles
|
||||||
|
const updatedLabels = new Map(labels)
|
||||||
|
profileData.forEach(({ encoded, pubkey }) => {
|
||||||
|
if (!updatedLabels.has(encoded)) {
|
||||||
|
const profileEvent = profiles.find(p => p.pubkey === pubkey)
|
||||||
|
if (profileEvent) {
|
||||||
|
try {
|
||||||
|
const profileData = JSON.parse(profileEvent.content || '{}') as { name?: string; display_name?: string; nip05?: string }
|
||||||
|
const displayName = profileData.display_name || profileData.name || profileData.nip05
|
||||||
|
if (displayName) {
|
||||||
|
updatedLabels.set(encoded, `@${displayName}`)
|
||||||
|
console.log('[useProfileLabels] Fetched profile:', encoded, '->', displayName)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore parse errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setProfileLabels(updatedLabels)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('[useProfileLabels] Error fetching profiles:', err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [profileData, eventStore, relayPool])
|
||||||
|
|
||||||
|
console.log('[useProfileLabels] Final labels map size:', profileLabels.size)
|
||||||
|
return profileLabels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,17 @@ export function extractNostrUris(text: string): string[] {
|
|||||||
try {
|
try {
|
||||||
const pointers = getContentPointers(text)
|
const pointers = getContentPointers(text)
|
||||||
console.log('[nostrUriResolver] Found pointers:', pointers.length)
|
console.log('[nostrUriResolver] Found pointers:', pointers.length)
|
||||||
const result = pointers.map(pointer => {
|
const result: string[] = []
|
||||||
|
pointers.forEach(pointer => {
|
||||||
try {
|
try {
|
||||||
return encodeDecodeResult(pointer)
|
const encoded = encodeDecodeResult(pointer)
|
||||||
|
if (encoded) {
|
||||||
|
result.push(encoded)
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[nostrUriResolver] Error encoding pointer:', err, pointer)
|
console.error('[nostrUriResolver] Error encoding pointer:', err, pointer)
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}).filter((v): v is string => v !== null)
|
})
|
||||||
console.log('[nostrUriResolver] Extracted URIs:', result.length)
|
console.log('[nostrUriResolver] Extracted URIs:', result.length)
|
||||||
return result
|
return result
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user