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.
 
 
 
 

114 lines
3.7 KiB

import { recipientHasAnyPaymentOptions } from '@/lib/merge-payment-methods'
import { getPaymentInfoFromEvent, getProfileFromEvent } from '@/lib/event-metadata'
import client, { replaceableEventService } from '@/services/client.service'
import { kinds, type Event } from 'nostr-tools'
import { useEffect, useMemo, useState } from 'react'
import type { TPaymentInfo } from '@/types'
import type { TProfile } from '@/types'
export type RecipientPaymentData = {
paymentInfo: TPaymentInfo | null
profile: TProfile | null
profileEvent: Event | null
/** Any payto / Lightning target on kind 0 or 10133. */
canReceiveTip: boolean
}
/** @deprecated Use {@link RecipientPaymentData} */
export type RecipientZapPaymentData = RecipientPaymentData
export function buildRecipientPaymentData(
paymentInfo: TPaymentInfo | null,
profile: TProfile | null,
profileEvent: Event | null
): RecipientPaymentData {
return {
paymentInfo,
profile,
profileEvent,
canReceiveTip: recipientHasAnyPaymentOptions(paymentInfo, profile, profileEvent)
}
}
/** @deprecated Use {@link buildRecipientPaymentData} */
export const buildRecipientZapPaymentData = buildRecipientPaymentData
export function mergeRecipientPaymentData(
partial: RecipientPaymentData | null | undefined,
fresh: RecipientPaymentData | null | undefined
): RecipientPaymentData {
if (!partial) {
return fresh ?? buildRecipientPaymentData(null, null, null)
}
if (!fresh) return partial
const profileEvent = fresh.profileEvent ?? partial.profileEvent
const profile = profileEvent
? (fresh.profile ?? partial.profile)
: (partial.profile ?? fresh.profile)
const paymentInfo = pickRicherPaymentInfo(partial.paymentInfo, fresh.paymentInfo)
return buildRecipientPaymentData(paymentInfo, profile ?? null, profileEvent)
}
/** @deprecated Use {@link mergeRecipientPaymentData} */
export const mergeRecipientZapPaymentData = mergeRecipientPaymentData
function pickRicherPaymentInfo(
a: TPaymentInfo | null | undefined,
b: TPaymentInfo | null | undefined
): TPaymentInfo | null {
const score = (p: TPaymentInfo | null | undefined) =>
p?.methods?.length ?? (p?.payto ? 1 : 0)
if (score(b) > score(a)) return b ?? null
if (score(a) > score(b)) return a ?? null
return b ?? a ?? null
}
export function useRecipientPaymentData(
recipientPubkey: string | undefined,
enabled: boolean
): RecipientPaymentData {
const [paymentInfo, setPaymentInfo] = useState<TPaymentInfo | null>(null)
const [profile, setProfile] = useState<TProfile | null>(null)
const [profileEvent, setProfileEvent] = useState<Event | null>(null)
useEffect(() => {
if (!enabled || !recipientPubkey) {
setPaymentInfo(null)
setProfile(null)
setProfileEvent(null)
return
}
let cancelled = false
void (async () => {
try {
const [paymentEvent, metaEvent] = await Promise.all([
client.fetchPaymentInfoEvent(recipientPubkey),
replaceableEventService.fetchReplaceableEvent(recipientPubkey, kinds.Metadata)
])
if (cancelled) return
setPaymentInfo(paymentEvent ? getPaymentInfoFromEvent(paymentEvent) : null)
setProfileEvent(metaEvent ?? null)
setProfile(metaEvent ? getProfileFromEvent(metaEvent) : null)
} catch {
if (!cancelled) {
setPaymentInfo(null)
setProfile(null)
setProfileEvent(null)
}
}
})()
return () => {
cancelled = true
}
}, [recipientPubkey, enabled])
return useMemo(
() => buildRecipientPaymentData(paymentInfo, profile, profileEvent),
[paymentInfo, profile, profileEvent]
)
}
/** @deprecated Use {@link useRecipientPaymentData} */
export const useRecipientZapPaymentData = useRecipientPaymentData