diff --git a/package-lock.json b/package-lock.json index 16ad1fa4..33cb4d32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "jumble-imwald", - "version": "21.3.0", + "version": "21.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jumble-imwald", - "version": "21.3.0", + "version": "21.3.1", "license": "MIT", "dependencies": { "@asciidoctor/core": "^3.0.4", diff --git a/package.json b/package.json index 91ba492e..2aa6a821 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jumble-imwald", - "version": "21.3.0", + "version": "21.3.1", "description": "A user-friendly Nostr client focused on relay feed browsing and relay discovery, forked from Jumble", "private": true, "type": "module", diff --git a/src/pages/secondary/BookmarkListPage/index.tsx b/src/pages/secondary/BookmarkListPage/index.tsx index f5b56d89..14fa0726 100644 --- a/src/pages/secondary/BookmarkListPage/index.tsx +++ b/src/pages/secondary/BookmarkListPage/index.tsx @@ -29,6 +29,7 @@ import { fetchLatestReplaceableListEvent } from '@/lib/replaceable-list-latest' import { normalizeUrl } from '@/lib/url' import { PROFILE_FETCH_RELAY_URLS } from '@/constants' import { queryService } from '@/services/client.service' +import dayjs from 'dayjs' import { Code, Eraser, MoreVertical } from 'lucide-react' import { kinds } from 'nostr-tools' import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react' @@ -108,6 +109,9 @@ const BookmarkListPage = forwardRef( if (!pubkey || cleaning) return setCleaning(true) try { + if (dayjs().unix() === bookmarkListEvent?.created_at) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ accountPubkey: pubkey, favoriteRelays: favoriteRelays ?? [], @@ -124,7 +128,7 @@ const BookmarkListPage = forwardRef( setCleaning(false) setCleanConfirmOpen(false) } - }, [pubkey, cleaning, favoriteRelays, blockedRelays, publish, updateBookmarkListEvent, refreshFromRelays, t]) + }, [pubkey, cleaning, bookmarkListEvent?.created_at, favoriteRelays, blockedRelays, publish, updateBookmarkListEvent, refreshFromRelays, t]) if (!profile || !pubkey) { return diff --git a/src/pages/secondary/FollowingListPage/index.tsx b/src/pages/secondary/FollowingListPage/index.tsx index 89bb4eb9..40eec860 100644 --- a/src/pages/secondary/FollowingListPage/index.tsx +++ b/src/pages/secondary/FollowingListPage/index.tsx @@ -26,6 +26,7 @@ import { FOLLOWS_HISTORY_RELAY_URLS } from '@/constants' import { createFollowListDraftEvent } from '@/lib/draft-event' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useNostr } from '@/providers/NostrProvider' +import dayjs from 'dayjs' import { Code, Eraser, MoreVertical } from 'lucide-react' import { forwardRef, useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -70,6 +71,9 @@ const FollowingListPage = forwardRef(({ id, index, hideTitlebar = false }: { id? if (!accountPubkey || !isOwnList || cleaning) return setCleaning(true) try { + if (dayjs().unix() === followListEvent?.created_at) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ accountPubkey, favoriteRelays: favoriteRelays ?? [], diff --git a/src/pages/secondary/InterestListPage/index.tsx b/src/pages/secondary/InterestListPage/index.tsx index 18dae3e9..962370e4 100644 --- a/src/pages/secondary/InterestListPage/index.tsx +++ b/src/pages/secondary/InterestListPage/index.tsx @@ -31,6 +31,7 @@ import { useInterestList } from '@/providers/InterestListProvider' import { useNostr } from '@/providers/NostrProvider' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import client from '@/services/client.service' +import dayjs from 'dayjs' import { Code, Eraser, MoreVertical, Trash2 } from 'lucide-react' import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -109,6 +110,9 @@ const InterestListPage = forwardRef( if (!pubkey || cleaning) return setCleaning(true) try { + if (dayjs().unix() === interestListEvent?.created_at) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ accountPubkey: pubkey, favoriteRelays: favoriteRelays ?? [], @@ -124,7 +128,7 @@ const InterestListPage = forwardRef( setCleaning(false) setCleanConfirmOpen(false) } - }, [pubkey, cleaning, favoriteRelays, blockedRelays, publish, updateInterestListEvent, t]) + }, [pubkey, cleaning, interestListEvent?.created_at, favoriteRelays, blockedRelays, publish, updateInterestListEvent, t]) if (!profile || !pubkey) { return diff --git a/src/pages/secondary/MuteListPage/index.tsx b/src/pages/secondary/MuteListPage/index.tsx index c8b23f59..efec6daa 100644 --- a/src/pages/secondary/MuteListPage/index.tsx +++ b/src/pages/secondary/MuteListPage/index.tsx @@ -32,6 +32,7 @@ import indexedDb from '@/services/indexed-db.service' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useNostr } from '@/providers/NostrProvider' import { Code, Eraser, Lock, MoreVertical, Unlock } from 'lucide-react' +import dayjs from 'dayjs' import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' @@ -45,7 +46,7 @@ const MuteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb const { getMutePubkeys } = useMuteList() const [jsonOpen, setJsonOpen] = useState(false) const [jsonPayload, setJsonPayload] = useState(null) - const mutePubkeys = useMemo(() => getMutePubkeys(), [pubkey]) + const mutePubkeys = useMemo(() => getMutePubkeys(), [getMutePubkeys]) const [visibleMutePubkeys, setVisibleMutePubkeys] = useState([]) const [listRefreshKey, setListRefreshKey] = useState(0) const [cleanConfirmOpen, setCleanConfirmOpen] = useState(false) @@ -119,6 +120,9 @@ const MuteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb if (!pubkey || cleaning) return setCleaning(true) try { + if (dayjs().unix() === muteListEvent?.created_at) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ accountPubkey: pubkey, favoriteRelays: favoriteRelays ?? [], diff --git a/src/pages/secondary/PinListPage/index.tsx b/src/pages/secondary/PinListPage/index.tsx index 45dcef4c..c235149c 100644 --- a/src/pages/secondary/PinListPage/index.tsx +++ b/src/pages/secondary/PinListPage/index.tsx @@ -26,6 +26,7 @@ import { fetchNewestPinListForPubkey } from '@/lib/replaceable-list-latest' import { useNostr } from '@/providers/NostrProvider' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import indexedDb from '@/services/indexed-db.service' +import dayjs from 'dayjs' import { Code, Eraser, MoreVertical } from 'lucide-react' import type { Event } from 'nostr-tools' import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react' @@ -112,6 +113,9 @@ const PinListPage = forwardRef( if (!pubkey || cleaning) return setCleaning(true) try { + if (dayjs().unix() === pinListEvent?.created_at) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ accountPubkey: pubkey, favoriteRelays: favoriteRelays ?? [], @@ -132,7 +136,7 @@ const PinListPage = forwardRef( setCleaning(false) setCleanConfirmOpen(false) } - }, [pubkey, cleaning, favoriteRelays, blockedRelays, publish, t]) + }, [pubkey, cleaning, pinListEvent?.created_at, favoriteRelays, blockedRelays, publish, t]) if (!profile || !pubkey) { return diff --git a/src/providers/MuteListProvider.tsx b/src/providers/MuteListProvider.tsx index 502a6a20..13295498 100644 --- a/src/providers/MuteListProvider.tsx +++ b/src/providers/MuteListProvider.tsx @@ -138,9 +138,9 @@ export function MuteListProvider({ children }: { children: ReactNode }) { updateMuteTags() }, [muteListEvent, isAccountSessionHydrating, account?.signerType, account?.pubkey]) - const getMutePubkeys = () => { + const getMutePubkeys = useCallback(() => { return Array.from(mutePubkeySet) - } + }, [mutePubkeySet]) const getMuteType = useCallback( (pubkey: string): 'public' | 'private' | null => { diff --git a/src/providers/NostrProvider/index.tsx b/src/providers/NostrProvider/index.tsx index c5ebc54f..a39f6174 100644 --- a/src/providers/NostrProvider/index.tsx +++ b/src/providers/NostrProvider/index.tsx @@ -1353,11 +1353,10 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { } const updateFollowListEvent = async (followListEvent: Event) => { - const newFollowListEvent = await indexedDb.putReplaceableEvent(followListEvent) - if (newFollowListEvent.id !== followListEvent.id) return - - setFollowListEvent(newFollowListEvent) - await client.updateFollowListCache(newFollowListEvent) + const stored = await indexedDb.putReplaceableEvent(followListEvent) + /** Always sync follow list state/cache to the IndexedDB winner. */ + setFollowListEvent(stored) + await client.updateFollowListCache(stored) } const updateMuteListEvent = async (muteListEvent: Event, privateTags: string[][]) => { @@ -1373,17 +1372,15 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { } const updateBookmarkListEvent = async (bookmarkListEvent: Event) => { - const newBookmarkListEvent = await indexedDb.putReplaceableEvent(bookmarkListEvent) - if (newBookmarkListEvent.id !== bookmarkListEvent.id) return - - setBookmarkListEvent(newBookmarkListEvent) + const stored = await indexedDb.putReplaceableEvent(bookmarkListEvent) + /** Keep bookmark UI aligned with replaceable winner from storage. */ + setBookmarkListEvent(stored) } const updateInterestListEvent = async (interestListEvent: Event) => { - const newInterestListEvent = await indexedDb.putReplaceableEvent(interestListEvent) - if (newInterestListEvent.id !== interestListEvent.id) return - - setInterestListEvent(newInterestListEvent) + const stored = await indexedDb.putReplaceableEvent(interestListEvent) + /** Keep interests UI aligned with replaceable winner from storage. */ + setInterestListEvent(stored) } const updateFavoriteRelaysEvent = async (favoriteRelaysEvent: Event) => {