diff --git a/packages/app/src/Element/AsyncButton.tsx b/packages/app/src/Element/AsyncButton.tsx index 808b6557..c4118afa 100644 --- a/packages/app/src/Element/AsyncButton.tsx +++ b/packages/app/src/Element/AsyncButton.tsx @@ -12,6 +12,7 @@ export default function AsyncButton(props: AsyncButtonProps) { const [loading, setLoading] = useState(false); async function handle(e: React.MouseEvent) { + e.stopPropagation(); if (loading || props.disabled) return; setLoading(true); try { diff --git a/packages/app/src/Element/FollowListBase.tsx b/packages/app/src/Element/FollowListBase.tsx index 122f6c4d..63de99a7 100644 --- a/packages/app/src/Element/FollowListBase.tsx +++ b/packages/app/src/Element/FollowListBase.tsx @@ -10,12 +10,21 @@ import messages from "./messages"; export interface FollowListBaseProps { pubkeys: HexKey[]; - title?: ReactNode | string; + title?: ReactNode; showFollowAll?: boolean; showAbout?: boolean; className?: string; + actions?: ReactNode; } -export default function FollowListBase({ pubkeys, title, showFollowAll, showAbout, className }: FollowListBaseProps) { + +export default function FollowListBase({ + pubkeys, + title, + showFollowAll, + showAbout, + className, + actions, +}: FollowListBaseProps) { const publisher = useEventPublisher(); const { follows, relays } = useLogin(); @@ -31,6 +40,7 @@ export default function FollowListBase({ pubkeys, title, showFollowAll, showAbou {(showFollowAll ?? true) && (
{title}
+ {actions} diff --git a/packages/app/src/Element/PubkeyList.tsx b/packages/app/src/Element/PubkeyList.tsx index df415ab2..6c43fe0f 100644 --- a/packages/app/src/Element/PubkeyList.tsx +++ b/packages/app/src/Element/PubkeyList.tsx @@ -1,8 +1,84 @@ import { RawEvent } from "@snort/nostr"; -import { dedupe } from "Util"; -import FollowListBase from "./FollowListBase"; +import { FormattedMessage, FormattedNumber } from "react-intl"; + +import { dedupe, hexToBech32, unixNow } from "Util"; +import FollowListBase from "Element/FollowListBase"; +import AsyncButton from "Element/AsyncButton"; +import { useWallet } from "Wallet"; +import { Toastore } from "Toaster"; +import { getDisplayName } from "Element/ProfileImage"; +import { UserCache } from "Cache"; +import useLogin from "Hooks/useLogin"; +import { LNURL } from "LNURL"; +import useEventPublisher from "Feed/EventPublisher"; +import { WalletInvoiceState } from "Wallet"; export default function PubkeyList({ ev, className }: { ev: RawEvent; className?: string }) { + const wallet = useWallet(); + const login = useLogin(); + const publisher = useEventPublisher(); const ids = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1])); - return ; + + async function zapAll() { + for (const pk of ids) { + try { + const profile = await UserCache.get(pk); + const amtSend = login.preferences.defaultZapAmount; + const lnurl = profile?.lud16 || profile?.lud06; + if (lnurl) { + const svc = new LNURL(lnurl); + await svc.load(); + + const zap = await publisher?.zap( + amtSend * 1000, + pk, + Object.keys(login.relays.item), + undefined, + `Zap from ${hexToBech32("note", ev.id)}` + ); + const invoice = await svc.getInvoice(amtSend, undefined, zap); + if (invoice.pr) { + const rsp = await wallet.wallet?.payInvoice(invoice.pr); + if (rsp?.state === WalletInvoiceState.Paid) { + Toastore.push({ + element: ( + + ), + icon: "zap", + }); + } + } + } + } catch (e) { + console.debug("Failed to zap", pk, e); + } + } + } + + return ( + a[0] === "d")?.[1]} + actions={ + <> + zapAll()}> + , + }} + /> + + + } + /> + ); } diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json index 298c44a9..f5c25c03 100644 --- a/packages/app/src/lang.json +++ b/packages/app/src/lang.json @@ -225,6 +225,9 @@ "defaultMessage": "Parent", "description": "Link to parent note in thread" }, + "AGNz71": { + "defaultMessage": "Zap All {n} sats" + }, "ASRK0S": { "defaultMessage": "This author has been muted" }, @@ -428,6 +431,9 @@ "IUZC+0": { "defaultMessage": "This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you." }, + "Ig9/a1": { + "defaultMessage": "Sent {n} sats to {name}" + }, "Iwm6o2": { "defaultMessage": "NIP-05 Shop" }, @@ -1232,6 +1238,9 @@ "defaultMessage": "Unlock", "description": "Unlock wallet" }, + "xaj9Ba": { + "defaultMessage": "Provider" + }, "xbVgIm": { "defaultMessage": "Automatically load media" }, diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json index ad813929..c27813f9 100644 --- a/packages/app/src/translations/en.json +++ b/packages/app/src/translations/en.json @@ -73,6 +73,7 @@ "9pMqYs": "Nostr Address", "9wO4wJ": "Lightning Invoice", "ADmfQT": "Parent", + "AGNz71": "Zap All {n} sats", "ASRK0S": "This author has been muted", "Adk34V": "Setup your Profile", "Ai8VHU": "Unlimited note retention on Snort relay", @@ -140,6 +141,7 @@ "IEwZvs": "Are you sure you want to unpin this note?", "INSqIz": "Twitter username...", "IUZC+0": "This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you.", + "Ig9/a1": "Sent {n} sats to {name}", "Iwm6o2": "NIP-05 Shop", "Ix8l+B": "Trending Notes", "J+dIsA": "Subscriptions", @@ -402,6 +404,7 @@ "xJ9n2N": "Your public key", "xKflGN": "{username}''s Follows on Nostr", "xQtL3v": "Unlock", + "xaj9Ba": "Provider", "xbVgIm": "Automatically load media", "xhQMeQ": "Expires", "xmcVZ0": "Search", @@ -415,4 +418,4 @@ "zjJZBd": "You're ready!", "zonsdq": "Failed to load LNURL service", "zvCDao": "Automatically show latest notes" -} +} \ No newline at end of file