mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 06:34:24 +01:00
refactor: standardize @ prefix handling and improve npub/nprofile display
- Fix getNpubFallbackDisplay to return names without @ prefix - Update all call sites to consistently add @ when rendering mentions - Fix incomplete error handling in getNpubFallbackDisplay catch block - Add nprofile support to addLoadingClassToProfileLinks - Extract shared isProfileInCacheOrStore utility to eliminate duplicate loading state checks - Update ResolvedMention and NostrMentionLink to use shared utility This ensures consistent @ prefix handling across all profile display contexts and eliminates code duplication for profile loading state detection.
This commit is contained in:
@@ -4,7 +4,7 @@ import { useEventModel } from 'applesauce-react/hooks'
|
||||
import { Hooks } from 'applesauce-react'
|
||||
import { Models, Helpers } from 'applesauce-core'
|
||||
import { getProfileDisplayName } from '../utils/nostrUriResolver'
|
||||
import { loadCachedProfiles } from '../services/profileService'
|
||||
import { isProfileInCacheOrStore } from '../utils/profileLoadingUtils'
|
||||
|
||||
const { getPubkeyFromDecodeResult } = Helpers
|
||||
|
||||
@@ -43,14 +43,7 @@ const NostrMentionLink: React.FC<NostrMentionLinkProps> = ({
|
||||
// Check if profile is in cache or eventStore for loading detection
|
||||
const isInCacheOrStore = useMemo(() => {
|
||||
if (!pubkey) return false
|
||||
// Check cache
|
||||
const cached = loadCachedProfiles([pubkey])
|
||||
if (cached.has(pubkey)) {
|
||||
return true
|
||||
}
|
||||
// Check eventStore
|
||||
const eventStoreProfile = eventStore?.getEvent(pubkey + ':0')
|
||||
return !!eventStoreProfile
|
||||
return isProfileInCacheOrStore(pubkey, eventStore)
|
||||
}, [pubkey, eventStore])
|
||||
|
||||
// Show loading if profile doesn't exist and not in cache/store (for npub/nprofile)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Hooks } from 'applesauce-react'
|
||||
import { Models, Helpers } from 'applesauce-core'
|
||||
import { decode, npubEncode } from 'nostr-tools/nip19'
|
||||
import { getProfileDisplayName } from '../utils/nostrUriResolver'
|
||||
import { loadCachedProfiles } from '../services/profileService'
|
||||
import { isProfileInCacheOrStore } from '../utils/profileLoadingUtils'
|
||||
|
||||
const { getPubkeyFromDecodeResult } = Helpers
|
||||
|
||||
@@ -28,14 +28,7 @@ const ResolvedMention: React.FC<ResolvedMentionProps> = ({ encoded }) => {
|
||||
// Check if profile is in cache or eventStore
|
||||
const isInCacheOrStore = useMemo(() => {
|
||||
if (!pubkey) return false
|
||||
// Check cache
|
||||
const cached = loadCachedProfiles([pubkey])
|
||||
if (cached.has(pubkey)) {
|
||||
return true
|
||||
}
|
||||
// Check eventStore
|
||||
const eventStoreProfile = eventStore?.getEvent(pubkey + ':0')
|
||||
return !!eventStoreProfile
|
||||
return isProfileInCacheOrStore(pubkey, eventStore)
|
||||
}, [pubkey, eventStore])
|
||||
|
||||
// Show loading if profile doesn't exist and not in cache/store
|
||||
|
||||
@@ -60,13 +60,13 @@ export function useProfileLabels(
|
||||
if (cachedProfile) {
|
||||
const displayName = extractProfileDisplayName(cachedProfile)
|
||||
if (displayName) {
|
||||
// Only add @ prefix if we have a real name, otherwise use fallback format directly
|
||||
const label = displayName.startsWith('@') ? displayName : `@${displayName}`
|
||||
// Add @ prefix (extractProfileDisplayName returns name without @)
|
||||
const label = `@${displayName}`
|
||||
labels.set(pubkey, label)
|
||||
} else {
|
||||
// Use fallback npub display if profile has no name
|
||||
// Use fallback npub display if profile has no name (add @ prefix)
|
||||
const fallback = getNpubFallbackDisplay(pubkey)
|
||||
labels.set(pubkey, fallback)
|
||||
labels.set(pubkey, `@${fallback}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -224,13 +224,13 @@ export function useProfileLabels(
|
||||
// Extract display name using centralized utility
|
||||
const displayName = extractProfileDisplayName(eventStoreProfile as NostrEvent)
|
||||
if (displayName) {
|
||||
// Only add @ prefix if we have a real name, otherwise use fallback format directly
|
||||
const label = displayName.startsWith('@') ? displayName : `@${displayName}`
|
||||
// Add @ prefix (extractProfileDisplayName returns name without @)
|
||||
const label = `@${displayName}`
|
||||
labels.set(pubkey, label)
|
||||
} else {
|
||||
// Use fallback npub display if profile has no name
|
||||
// Use fallback npub display if profile has no name (add @ prefix)
|
||||
const fallback = getNpubFallbackDisplay(pubkey)
|
||||
labels.set(pubkey, fallback)
|
||||
labels.set(pubkey, `@${fallback}`)
|
||||
}
|
||||
loading.set(pubkey, false)
|
||||
} else {
|
||||
@@ -258,8 +258,9 @@ export function useProfileLabels(
|
||||
const pubkey = event.pubkey
|
||||
|
||||
// Determine the label for this profile using centralized utility
|
||||
// Add @ prefix (both extractProfileDisplayName and getNpubFallbackDisplay return names without @)
|
||||
const displayName = extractProfileDisplayName(event)
|
||||
const label = displayName ? (displayName.startsWith('@') ? displayName : `@${displayName}`) : getNpubFallbackDisplay(pubkey)
|
||||
const label = displayName ? `@${displayName}` : `@${getNpubFallbackDisplay(pubkey)}`
|
||||
|
||||
// Apply label immediately to prevent race condition with loading state
|
||||
// This ensures labels are available when isLoading becomes false
|
||||
|
||||
@@ -86,13 +86,15 @@ export function getNostrUriLabel(encoded: string): string {
|
||||
const decoded = decode(encoded)
|
||||
|
||||
switch (decoded.type) {
|
||||
case 'npub':
|
||||
// Remove "npub1" prefix (5 chars) and show next 7 chars
|
||||
return `@${encoded.slice(5, 12)}...`
|
||||
case 'npub': {
|
||||
// Use shared fallback display function and add @ for label
|
||||
const pubkey = decoded.data
|
||||
return `@${getNpubFallbackDisplay(pubkey)}`
|
||||
}
|
||||
case 'nprofile': {
|
||||
const npub = npubEncode(decoded.data.pubkey)
|
||||
// Remove "npub1" prefix (5 chars) and show next 7 chars
|
||||
return `@${npub.slice(5, 12)}...`
|
||||
// Use shared fallback display function and add @ for label
|
||||
const pubkey = decoded.data.pubkey
|
||||
return `@${getNpubFallbackDisplay(pubkey)}`
|
||||
}
|
||||
case 'note':
|
||||
return `note:${encoded.slice(5, 12)}...`
|
||||
@@ -119,18 +121,19 @@ export function getNostrUriLabel(encoded: string): string {
|
||||
|
||||
/**
|
||||
* Get a standardized fallback display name for a pubkey when profile has no name
|
||||
* Returns npub format: @abc1234...
|
||||
* Returns npub format: abc1234... (without @ prefix)
|
||||
* Components should add @ prefix when rendering mentions/links
|
||||
* @param pubkey The pubkey in hex format
|
||||
* @returns Formatted npub display string
|
||||
* @returns Formatted npub display string without @ prefix
|
||||
*/
|
||||
export function getNpubFallbackDisplay(pubkey: string): string {
|
||||
try {
|
||||
const npub = npubEncode(pubkey)
|
||||
// Remove "npub1" prefix (5 chars) and show next 7 chars
|
||||
return `@${npub.slice(5, 12)}...`
|
||||
return `${npub.slice(5, 12)}...`
|
||||
} catch {
|
||||
// Fallback to shortened pubkey if encoding fails
|
||||
return `@${pubkey.slice(0, 8)}...`
|
||||
return `${pubkey.slice(0, 8)}...`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,12 +383,17 @@ export function addLoadingClassToProfileLinks(
|
||||
// Find all <a> tags with href starting with /p/ (profile links)
|
||||
const result = html.replace(/<a\s+[^>]*?href="\/p\/([^"]+)"[^>]*?>/g, (match, npub: string) => {
|
||||
try {
|
||||
// Decode npub to get pubkey
|
||||
// Decode npub or nprofile to get pubkey
|
||||
const decoded: ReturnType<typeof decode> = decode(npub)
|
||||
switch (decoded.type) {
|
||||
case 'npub': {
|
||||
const pubkey = decoded.data
|
||||
|
||||
let pubkey: string | undefined
|
||||
if (decoded.type === 'npub') {
|
||||
pubkey = decoded.data
|
||||
} else if (decoded.type === 'nprofile') {
|
||||
pubkey = decoded.data.pubkey
|
||||
}
|
||||
|
||||
if (pubkey) {
|
||||
// Check if this profile is loading
|
||||
const isLoading = profileLoading.get(pubkey)
|
||||
|
||||
@@ -403,11 +411,6 @@ export function addLoadingClassToProfileLinks(
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
// Not an npub, ignore
|
||||
break
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore processing errors
|
||||
|
||||
27
src/utils/profileLoadingUtils.ts
Normal file
27
src/utils/profileLoadingUtils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { IEventStore } from 'applesauce-core'
|
||||
import { loadCachedProfiles } from '../services/profileService'
|
||||
|
||||
/**
|
||||
* Check if a profile exists in cache or eventStore
|
||||
* Used to determine if profile loading state should be shown
|
||||
* @param pubkey The pubkey in hex format
|
||||
* @param eventStore Optional eventStore instance
|
||||
* @returns true if profile exists in cache or eventStore, false otherwise
|
||||
*/
|
||||
export function isProfileInCacheOrStore(
|
||||
pubkey: string,
|
||||
eventStore?: IEventStore | null
|
||||
): boolean {
|
||||
if (!pubkey) return false
|
||||
|
||||
// Check cache first
|
||||
const cached = loadCachedProfiles([pubkey])
|
||||
if (cached.has(pubkey)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check eventStore
|
||||
const eventStoreProfile = eventStore?.getEvent(pubkey + ':0')
|
||||
return !!eventStoreProfile
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user