You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
4.1 KiB
110 lines
4.1 KiB
import { buildAccountListRelayUrlsForMerge } from '@/lib/account-list-relay-urls' |
|
import { createFollowListDraftEvent } from '@/lib/draft-event' |
|
import { publishFollowListPreimageToHistory } from '@/lib/follow-list-history' |
|
import { |
|
dedupePTagsAppendPubkey, |
|
fetchLatestReplaceableListEvent, |
|
removePubkeyFromPTags |
|
} from '@/lib/replaceable-list-latest' |
|
import { getPubkeysFromPTags } from '@/lib/tag' |
|
import client from '@/services/client.service' |
|
import { kinds } from 'nostr-tools' |
|
import { useMemo, useCallback } from 'react' |
|
import { useTranslation } from 'react-i18next' |
|
import { useNostr } from './NostrProvider' |
|
import { useFavoriteRelays } from './FavoriteRelaysProvider' |
|
import { FollowListContext } from './follow-list-context' |
|
|
|
export function FollowListProvider({ children }: { children: React.ReactNode }) { |
|
const { t } = useTranslation() |
|
const { pubkey: accountPubkey, followListEvent, publish, updateFollowListEvent } = useNostr() |
|
const { favoriteRelays, blockedRelays } = useFavoriteRelays() |
|
const followings = useMemo( |
|
() => (followListEvent ? getPubkeysFromPTags(followListEvent.tags) : []), |
|
[followListEvent] |
|
) |
|
|
|
const buildMergeRelays = useCallback(async () => { |
|
if (!accountPubkey) return [] as string[] |
|
return buildAccountListRelayUrlsForMerge({ |
|
accountPubkey, |
|
favoriteRelays: favoriteRelays ?? [], |
|
blockedRelays |
|
}) |
|
}, [accountPubkey, favoriteRelays, blockedRelays]) |
|
|
|
const mergeLatestFollowTags = async (): Promise<{ tags: string[][]; content: string | undefined } | null> => { |
|
if (!accountPubkey) return null |
|
const relays = await buildMergeRelays() |
|
let latest = |
|
(await fetchLatestReplaceableListEvent(accountPubkey, kinds.Contacts, relays)) ?? null |
|
if (!latest) { |
|
latest = (await client.fetchFollowListEvent(accountPubkey)) ?? null |
|
} |
|
if (!latest) { |
|
const result = confirm(t('FollowListNotFoundConfirmation')) |
|
if (!result) return null |
|
} |
|
return { tags: latest?.tags ?? [], content: latest?.content } |
|
} |
|
|
|
const follow = async (pubkey: string) => { |
|
if (!accountPubkey) return |
|
const base = await mergeLatestFollowTags() |
|
if (base === null) return |
|
await publishFollowListPreimageToHistory(publish, base.tags, base.content) |
|
const mergedTags = dedupePTagsAppendPubkey(base.tags, pubkey) |
|
const newFollowListDraftEvent = createFollowListDraftEvent(mergedTags, base.content) |
|
const newFollowListEvent = await publish(newFollowListDraftEvent) |
|
await updateFollowListEvent(newFollowListEvent) |
|
} |
|
|
|
const followMany = async (pubkeys: string[]) => { |
|
if (!accountPubkey) return |
|
const unique = [...new Set(pubkeys.map((p) => p.trim().toLowerCase()).filter(Boolean))] |
|
if (unique.length === 0) return |
|
const base = await mergeLatestFollowTags() |
|
if (base === null) return |
|
await publishFollowListPreimageToHistory(publish, base.tags, base.content) |
|
let mergedTags = base.tags |
|
for (const pk of unique) { |
|
mergedTags = dedupePTagsAppendPubkey(mergedTags, pk) |
|
} |
|
const newFollowListDraftEvent = createFollowListDraftEvent(mergedTags, base.content) |
|
const newFollowListEvent = await publish(newFollowListDraftEvent) |
|
await updateFollowListEvent(newFollowListEvent) |
|
} |
|
|
|
const unfollow = async (pubkey: string) => { |
|
if (!accountPubkey) return |
|
|
|
const relays = await buildMergeRelays() |
|
let latest = |
|
(await fetchLatestReplaceableListEvent(accountPubkey, kinds.Contacts, relays)) ?? null |
|
if (!latest) { |
|
latest = (await client.fetchFollowListEvent(accountPubkey)) ?? null |
|
} |
|
if (!latest) return |
|
|
|
await publishFollowListPreimageToHistory(publish, latest.tags, latest.content) |
|
const newFollowListDraftEvent = createFollowListDraftEvent( |
|
removePubkeyFromPTags(latest.tags, pubkey), |
|
latest.content |
|
) |
|
const newFollowListEvent = await publish(newFollowListDraftEvent) |
|
await updateFollowListEvent(newFollowListEvent) |
|
} |
|
|
|
return ( |
|
<FollowListContext.Provider |
|
value={{ |
|
followings, |
|
follow, |
|
followMany, |
|
unfollow |
|
}} |
|
> |
|
{children} |
|
</FollowListContext.Provider> |
|
) |
|
}
|
|
|