Browse Source

fixed note pinning

imwald
Silberengel 5 months ago
parent
commit
993c634b32
  1. 82
      src/components/NoteOptions/useMenuActions.tsx
  2. 104
      src/components/Profile/ProfileFeed.tsx

82
src/components/NoteOptions/useMenuActions.tsx

@ -7,6 +7,7 @@ import { useCurrentRelays } from '@/providers/CurrentRelaysProvider' @@ -7,6 +7,7 @@ import { useCurrentRelays } from '@/providers/CurrentRelaysProvider'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { useMuteList } from '@/providers/MuteListProvider'
import { useNostr } from '@/providers/NostrProvider'
import { BIG_RELAY_URLS, FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants'
import client from '@/services/client.service'
import { Bell, BellOff, Code, Copy, Link, SatelliteDish, Trash2, TriangleAlert, Pin } from 'lucide-react'
import { Event } from 'nostr-tools'
@ -71,7 +72,35 @@ export function useMenuActions({ @@ -71,7 +72,35 @@ export function useMenuActions({
return
}
try {
const pinListEvent = await client.fetchPinListEvent(pubkey)
// Build comprehensive relay list for pin status check
const allRelays = [
...(currentBrowsingRelayUrls || []),
...(favoriteRelays || []),
...BIG_RELAY_URLS,
...FAST_READ_RELAY_URLS,
...FAST_WRITE_RELAY_URLS
]
const normalizedRelays = allRelays
.map(url => normalizeUrl(url))
.filter((url): url is string => !!url)
const comprehensiveRelays = Array.from(new Set(normalizedRelays))
// Try to fetch pin list event from comprehensive relay list first
let pinListEvent = null
try {
const pinListEvents = await client.fetchEvents(comprehensiveRelays, {
authors: [pubkey],
kinds: [10001], // Pin list kind
limit: 1
})
pinListEvent = pinListEvents[0] || null
} catch (error) {
console.warn('[PinStatus] Error fetching pin list from comprehensive relays, falling back to default method:', error)
pinListEvent = await client.fetchPinListEvent(pubkey)
}
if (pinListEvent) {
const isEventPinned = pinListEvent.tags.some(tag => tag[0] === 'e' && tag[1] === event.id)
setIsPinned(isEventPinned)
@ -81,14 +110,42 @@ export function useMenuActions({ @@ -81,14 +110,42 @@ export function useMenuActions({
}
}
checkIfPinned()
}, [pubkey, event.id])
}, [pubkey, event.id, currentBrowsingRelayUrls, favoriteRelays])
const handlePinNote = async () => {
if (!pubkey) return
try {
// Fetch existing pin list
let pinListEvent = await client.fetchPinListEvent(pubkey)
// Build comprehensive relay list for pin list fetching
const allRelays = [
...(currentBrowsingRelayUrls || []),
...(favoriteRelays || []),
...BIG_RELAY_URLS,
...FAST_READ_RELAY_URLS,
...FAST_WRITE_RELAY_URLS
]
const normalizedRelays = allRelays
.map(url => normalizeUrl(url))
.filter((url): url is string => !!url)
const comprehensiveRelays = Array.from(new Set(normalizedRelays))
// Try to fetch pin list event from comprehensive relay list first
let pinListEvent = null
try {
const pinListEvents = await client.fetchEvents(comprehensiveRelays, {
authors: [pubkey],
kinds: [10001], // Pin list kind
limit: 1
})
pinListEvent = pinListEvents[0] || null
} catch (error) {
console.warn('[PinNote] Error fetching pin list from comprehensive relays, falling back to default method:', error)
pinListEvent = await client.fetchPinListEvent(pubkey)
}
console.log('[PinNote] Current pin list event:', pinListEvent)
// Get existing event IDs, excluding the one we're toggling
const existingEventIds = (pinListEvent?.tags || [])
@ -96,6 +153,10 @@ export function useMenuActions({ @@ -96,6 +153,10 @@ export function useMenuActions({
.map(tag => tag[1])
.filter(id => id !== event.id)
console.log('[PinNote] Existing event IDs (excluding current):', existingEventIds)
console.log('[PinNote] Current event ID:', event.id)
console.log('[PinNote] Is currently pinned:', isPinned)
let newTags: string[][]
let successMessage: string
@ -103,18 +164,24 @@ export function useMenuActions({ @@ -103,18 +164,24 @@ export function useMenuActions({
// Unpin: just keep the existing tags without this event
newTags = existingEventIds.map(id => ['e', id])
successMessage = t('Note unpinned')
console.log('[PinNote] Unpinning - new tags:', newTags)
} else {
// Pin: add this event to the existing list
newTags = [...existingEventIds.map(id => ['e', id]), ['e', event.id]]
successMessage = t('Note pinned')
console.log('[PinNote] Pinning - new tags:', newTags)
}
// Create and publish the new pin list event
console.log('[PinNote] Publishing new pin list event with', newTags.length, 'tags')
console.log('[PinNote] Publishing to comprehensive relays:', comprehensiveRelays)
await publish({
kind: 10001,
tags: newTags,
content: '',
created_at: Math.floor(Date.now() / 1000)
}, {
specifiedRelayUrls: comprehensiveRelays
})
// Update local state - the publish will update the cache automatically
@ -337,7 +404,8 @@ export function useMenuActions({ @@ -337,7 +404,8 @@ export function useMenuActions({
}
}
if (pubkey && event.pubkey === pubkey) {
// Pin functionality available for any note (not just own notes)
if (pubkey) {
actions.push({
icon: Pin,
label: isPinned ? t('Unpin note') : t('Pin note'),
@ -346,6 +414,10 @@ export function useMenuActions({ @@ -346,6 +414,10 @@ export function useMenuActions({
},
separator: true
})
}
// Delete functionality only available for own notes
if (pubkey && event.pubkey === pubkey) {
actions.push({
icon: Trash2,
label: t('Try deleting this note'),

104
src/components/Profile/ProfileFeed.tsx

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
import KindFilter from '@/components/KindFilter'
import NoteList, { TNoteListRef } from '@/components/NoteList'
import Tabs from '@/components/Tabs'
import { BIG_RELAY_URLS } from '@/constants'
import { BIG_RELAY_URLS, FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants'
import { isTouchDevice } from '@/lib/utils'
import { useKindFilter } from '@/providers/KindFilterProvider'
import { useNostr } from '@/providers/NostrProvider'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { normalizeUrl } from '@/lib/url'
import client from '@/services/client.service'
import storage from '@/services/local-storage.service'
import { TFeedSubRequest, TNoteListMode } from '@/types'
@ -21,6 +23,7 @@ export default function ProfileFeed({ @@ -21,6 +23,7 @@ export default function ProfileFeed({
topSpace?: number
}) {
const { pubkey: myPubkey } = useNostr()
const { favoriteRelays } = useFavoriteRelays()
const { showKinds } = useKindFilter()
const [temporaryShowKinds, setTemporaryShowKinds] = useState(showKinds)
const [listMode, setListMode] = useState<TNoteListMode>(() => storage.getNoteListMode())
@ -47,7 +50,24 @@ export default function ProfileFeed({ @@ -47,7 +50,24 @@ export default function ProfileFeed({
const init = async () => {
// Privacy: Only use user's own relays + defaults, never connect to other users' relays
const myRelayList = myPubkey ? await client.fetchRelayList(myPubkey) : { write: [], read: [] }
const userRelays = [...myRelayList.read, ...BIG_RELAY_URLS]
// Build comprehensive relay list: user's inboxes + user's favorite relays + big relays + fast read relays + fast write relays
const allRelays = [
...(myRelayList.read || []), // User's inboxes (kind 10002)
...(myRelayList.write || []), // User's outboxes (kind 10002)
...(favoriteRelays || []), // User's favorite relays (kind 10012)
...BIG_RELAY_URLS, // Big relays
...FAST_READ_RELAY_URLS, // Fast read relays
...FAST_WRITE_RELAY_URLS // Fast write relays
]
// Normalize and deduplicate relay URLs
const normalizedRelays = allRelays
.map(url => normalizeUrl(url))
.filter((url): url is string => !!url)
const userRelays = Array.from(new Set(normalizedRelays))
console.log('[ProfileFeed] Using', userRelays.length, 'relays for profile feed:', userRelays)
if (listMode === 'you') {
if (!myPubkey) {
@ -57,14 +77,14 @@ export default function ProfileFeed({ @@ -57,14 +77,14 @@ export default function ProfileFeed({
setSubRequests([
{
urls: userRelays.slice(0, 5),
urls: userRelays,
filter: {
authors: [myPubkey],
'#p': [pubkey]
}
},
{
urls: userRelays.slice(0, 5),
urls: userRelays,
filter: {
authors: [pubkey],
'#p': [myPubkey]
@ -76,7 +96,7 @@ export default function ProfileFeed({ @@ -76,7 +96,7 @@ export default function ProfileFeed({
setSubRequests([
{
urls: userRelays.slice(0, 8),
urls: userRelays,
filter: {
authors: [pubkey]
}
@ -84,14 +104,47 @@ export default function ProfileFeed({ @@ -84,14 +104,47 @@ export default function ProfileFeed({
])
}
init()
}, [pubkey, listMode, myPubkey])
}, [pubkey, listMode, myPubkey, favoriteRelays])
// Fetch pinned notes
useEffect(() => {
const fetchPinnedNotes = async () => {
setLoadingPinned(true)
try {
const pinListEvent = await client.fetchPinListEvent(pubkey)
// Build comprehensive relay list for fetching pin list event
const myRelayList = myPubkey ? await client.fetchRelayList(myPubkey) : { write: [], read: [] }
const allRelaysForPinList = [
...(myRelayList.read || []), // User's inboxes (kind 10002)
...(myRelayList.write || []), // User's outboxes (kind 10002)
...(favoriteRelays || []), // User's favorite relays (kind 10012)
...BIG_RELAY_URLS, // Big relays
...FAST_READ_RELAY_URLS, // Fast read relays
...FAST_WRITE_RELAY_URLS // Fast write relays
]
const normalizedRelaysForPinList = allRelaysForPinList
.map(url => normalizeUrl(url))
.filter((url): url is string => !!url)
const comprehensiveRelaysForPinList = Array.from(new Set(normalizedRelaysForPinList))
console.log('[ProfileFeed] Using', comprehensiveRelaysForPinList.length, 'relays for pin list event:', comprehensiveRelaysForPinList)
console.log('[ProfileFeed] Relay breakdown - inboxes:', myRelayList.read?.length || 0, 'outboxes:', myRelayList.write?.length || 0, 'favorites:', favoriteRelays?.length || 0, 'big:', BIG_RELAY_URLS.length, 'fast_read:', FAST_READ_RELAY_URLS.length, 'fast_write:', FAST_WRITE_RELAY_URLS.length)
// Try to fetch pin list event from comprehensive relay list first
let pinListEvent = null
try {
const pinListEvents = await client.fetchEvents(comprehensiveRelaysForPinList, {
authors: [pubkey],
kinds: [10001], // Pin list kind
limit: 1
})
pinListEvent = pinListEvents[0] || null
} catch (error) {
console.warn('[ProfileFeed] Error fetching pin list from comprehensive relays, falling back to default method:', error)
pinListEvent = await client.fetchPinListEvent(pubkey)
}
console.log('[ProfileFeed] Pin list event:', pinListEvent)
if (pinListEvent && pinListEvent.tags.length > 0) {
// Extract event IDs from pin list
const eventIds = pinListEvent.tags
@ -99,12 +152,45 @@ export default function ProfileFeed({ @@ -99,12 +152,45 @@ export default function ProfileFeed({
.map(tag => tag[1])
.reverse() // Reverse to show newest first
console.log('[ProfileFeed] Found', eventIds.length, 'pinned event IDs:', eventIds)
// Use the same comprehensive relay list we built for the pin list event
console.log('[ProfileFeed] Using', comprehensiveRelaysForPinList.length, 'relays for pinned notes:', comprehensiveRelaysForPinList)
// Fetch the actual events
const events = await client.fetchEvents(
[...BIG_RELAY_URLS],
comprehensiveRelaysForPinList,
{ ids: eventIds }
)
console.log('[ProfileFeed] Fetched', events.length, 'pinned events out of', eventIds.length, 'requested')
console.log('[ProfileFeed] Fetched events:', events.map(e => ({ id: e.id, content: e.content.substring(0, 50) + '...' })))
// Debug: Check which event IDs were not found
const foundEventIds = events.map(e => e.id)
const missingEventIds = eventIds.filter(id => !foundEventIds.includes(id))
if (missingEventIds.length > 0) {
console.log('[ProfileFeed] Missing event IDs that could not be fetched:', missingEventIds)
// Try to fetch missing events individually to see if any specific relay has them
for (const missingId of missingEventIds) {
try {
console.log('[ProfileFeed] Attempting to fetch missing event:', missingId)
const missingEvents = await client.fetchEvents(comprehensiveRelaysForPinList, {
ids: [missingId],
limit: 1
})
if (missingEvents.length > 0) {
console.log('[ProfileFeed] Successfully fetched missing event:', missingId, missingEvents[0].content.substring(0, 50) + '...')
} else {
console.log('[ProfileFeed] Missing event not found on any relay:', missingId)
}
} catch (error) {
console.error('[ProfileFeed] Error fetching missing event:', missingId, error)
}
}
}
// Sort by created_at desc (newest first)
const sortedEvents = events.sort((a, b) => b.created_at - a.created_at)
setPinnedEvents(sortedEvents)
@ -120,7 +206,7 @@ export default function ProfileFeed({ @@ -120,7 +206,7 @@ export default function ProfileFeed({
}
fetchPinnedNotes()
}, [pubkey])
}, [pubkey, myPubkey, favoriteRelays])
const handleListModeChange = (mode: TNoteListMode) => {
setListMode(mode)

Loading…
Cancel
Save