Zap modal (#209)
This commit is contained in:
@ -20,8 +20,8 @@ export default function AsyncButton(props: any) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...props} className={`btn ${props.className}${loading ? " disabled" : ""}`} onClick={(e) => handle(e)}>
|
||||
{props.children}
|
||||
</div>
|
||||
<button type="button" disabled={loading} {...props} onClick={(e) => handle(e)}>
|
||||
{props.children}
|
||||
</button>
|
||||
)
|
||||
}
|
@ -4,7 +4,7 @@ import { useState } from "react";
|
||||
import { decode as invoiceDecode } from "light-bolt11-decoder";
|
||||
import { useMemo } from "react";
|
||||
import NoteTime from "Element/NoteTime";
|
||||
import LNURLTip from "Element/LNURLTip";
|
||||
import SendSats from "Element/SendSats";
|
||||
import ZapCircle from "Icons/ZapCircle";
|
||||
import useWebln from "Hooks/useWebln";
|
||||
|
||||
@ -49,7 +49,7 @@ export default function Invoice(props: InvoiceProps) {
|
||||
<>
|
||||
<h4>Lightning Invoice</h4>
|
||||
<ZapCircle className="zap-circle" />
|
||||
<LNURLTip invoice={invoice} show={showInvoice} onClose={() => setShowInvoice(false)} />
|
||||
<SendSats title="Pay Invoice" invoice={invoice} show={showInvoice} onClose={() => setShowInvoice(false)} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
.lnurl-tip {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .btn {
|
||||
background-color: inherit;
|
||||
width: 210px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.lnurl-tip .btn:hover {
|
||||
background-color: var(--gray);
|
||||
}
|
||||
|
||||
.sat-amount {
|
||||
display: inline-block;
|
||||
background-color: var(--gray-secondary);
|
||||
color: var(--font-color);
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
user-select: none;
|
||||
margin: 2px 5px;
|
||||
}
|
||||
|
||||
.sat-amount:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sat-amount.active {
|
||||
font-weight: bold;
|
||||
color: var(--note-bg);
|
||||
background-color: var(--font-color);
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions .copy-action {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions .pay-actions {
|
||||
margin: 10px auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
@ -11,7 +11,7 @@ import {
|
||||
CheckRegisterResponse
|
||||
} from "Nip05/ServiceProvider";
|
||||
import AsyncButton from "Element/AsyncButton";
|
||||
import LNURLTip from "Element/LNURLTip";
|
||||
import SendSats from "Element/SendSats";
|
||||
import Copy from "Element/Copy";
|
||||
import { useUserProfile }from "Feed/ProfileFeed";
|
||||
import useEventPublisher from "Feed/EventPublisher";
|
||||
@ -176,7 +176,7 @@ export default function Nip5Service(props: Nip05ServiceProps) {
|
||||
{availabilityResponse?.available === false && !registerStatus && <div className="flex">
|
||||
<b className="error">Not available: {mapError(availabilityResponse.why!, availabilityResponse.reasonTag || null)}</b>
|
||||
</div>}
|
||||
<LNURLTip
|
||||
<SendSats
|
||||
invoice={registerResponse?.invoice}
|
||||
show={showInvoice}
|
||||
onClose={() => setShowInvoice(false)}
|
||||
|
@ -12,6 +12,7 @@
|
||||
}
|
||||
|
||||
.note-creator textarea {
|
||||
border: none;
|
||||
outline: none;
|
||||
resize: none;
|
||||
background-color: var(--note-bg);
|
||||
|
@ -13,7 +13,7 @@ import { formatShort } from "Number";
|
||||
import useEventPublisher from "Feed/EventPublisher";
|
||||
import { getReactions, hexToBech32, normalizeReaction, Reaction } from "Util";
|
||||
import { NoteCreator } from "Element/NoteCreator";
|
||||
import LNURLTip from "Element/LNURLTip";
|
||||
import SendSats from "Element/SendSats";
|
||||
import { parseZap, ZapsSummary } from "Element/Zap";
|
||||
import { useUserProfile } from "Feed/ProfileFeed";
|
||||
import { default as NEvent } from "Nostr/Event";
|
||||
@ -268,7 +268,14 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
show={reply}
|
||||
setShow={setReply}
|
||||
/>
|
||||
<LNURLTip svc={author?.lud16 || author?.lud06} onClose={() => setTip(false)} show={tip} author={author?.pubkey} note={ev.Id} />
|
||||
<SendSats
|
||||
svc={author?.lud16 || author?.lud06}
|
||||
onClose={() => setTip(false)}
|
||||
show={tip}
|
||||
author={author?.pubkey}
|
||||
target={author?.display_name || author?.name}
|
||||
note={ev.Id}
|
||||
/>
|
||||
</div>
|
||||
<div className="zaps-container">
|
||||
<ZapsSummary zaps={zaps} />
|
||||
|
176
src/Element/SendSats.css
Normal file
176
src/Element/SendSats.css
Normal file
@ -0,0 +1,176 @@
|
||||
.lnurl-modal .modal-body {
|
||||
padding: 0;
|
||||
max-width: 470px;
|
||||
}
|
||||
|
||||
.lnurl-modal .lnurl-tip .pfp .avatar {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.lnurl-tip {
|
||||
padding: 24px 32px;
|
||||
background-color: #1B1B1B;
|
||||
border-radius: 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.lnurl-tip {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.light .lnurl-tip {
|
||||
background-color: var(--note-bg);
|
||||
}
|
||||
|
||||
.lnurl-tip h3 {
|
||||
color: var(--font-secondary-color);
|
||||
font-size: 11px;
|
||||
letter-spacing: .11em;
|
||||
font-weight: 600;
|
||||
line-height: 13px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.lnurl-tip .close {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 16px;
|
||||
color: var(--font-secondary-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.lnurl-tip .close:hover {
|
||||
color: var(--font-tertiary-color);
|
||||
}
|
||||
|
||||
.lnurl-tip .lnurl-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.lnurl-tip .lnurl-header h2 {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
}
|
||||
|
||||
.lnurl-tip .btn {
|
||||
background-color: inherit;
|
||||
width: 210px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.lnurl-tip .btn:hover {
|
||||
}
|
||||
|
||||
.amounts {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.amounts::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sat-amount {
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
background-color: #2A2A2A;
|
||||
color: var(--font-color);
|
||||
padding: 12px 16px;
|
||||
border-radius: 100px;
|
||||
user-select: none;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.light .sat-amount {
|
||||
background-color: var(--gray);
|
||||
}
|
||||
|
||||
.sat-amount:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.sat-amount:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sat-amount.active {
|
||||
font-weight: bold;
|
||||
color: var(--note-bg);
|
||||
background-color: var(--font-color);
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions .copy-action {
|
||||
margin: 10px auto;
|
||||
}
|
||||
|
||||
.lnurl-tip .invoice .actions .wallet-action {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.lnurl-tip .zap-action {
|
||||
margin-top: 16px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.lnurl-tip .zap-action svg {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.lnurl-tip .zap-action-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.lnurl-tip .custom-amount {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.lnurl-tip .custom-amount button {
|
||||
padding: 12px 18px;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.lnurl-tip canvas {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.lnurl-tip .success-action .paid {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.lnurl-tip .success-action a {
|
||||
color: var(--highlight);
|
||||
font-size: 19px;
|
||||
}
|
@ -1,12 +1,19 @@
|
||||
import "./LNURLTip.css";
|
||||
import "./SendSats.css";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { formatShort } from "Number";
|
||||
import { bech32ToText } from "Util";
|
||||
import { HexKey } from "Nostr";
|
||||
import Check from "Icons/Check";
|
||||
import Zap from "Icons/Zap";
|
||||
import Close from "Icons/Close";
|
||||
import useEventPublisher from "Feed/EventPublisher";
|
||||
import ProfileImage from "Element/ProfileImage";
|
||||
import Modal from "Element/Modal";
|
||||
import QrCode from "Element/QrCode";
|
||||
import Copy from "Element/Copy";
|
||||
import useWebln from "Hooks/useWebln";
|
||||
import useHorizontalScroll from "Hooks/useHorizontalScroll";
|
||||
|
||||
interface LNURLService {
|
||||
nostrPubkey?: HexKey
|
||||
@ -34,6 +41,7 @@ export interface LNURLTipProps {
|
||||
invoice?: string, // shortcut to invoice qr tab
|
||||
title?: string,
|
||||
notice?: string
|
||||
target?: string
|
||||
note?: HexKey
|
||||
author?: HexKey
|
||||
}
|
||||
@ -42,10 +50,19 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
const onClose = props.onClose || (() => { });
|
||||
const service = props.svc;
|
||||
const show = props.show || false;
|
||||
const { note, author } = props
|
||||
const amounts = [50, 100, 500, 1_000, 5_000, 10_000, 50_000];
|
||||
const { note, author, target } = props
|
||||
const amounts = [500, 1_000, 5_000, 10_000, 20_000, 50_000, 100_000, 1_000_000];
|
||||
const emojis: Record<number, string> = {
|
||||
1_000: "👍",
|
||||
5_000: "💜",
|
||||
10_000: "😍",
|
||||
20_000: "🤩",
|
||||
50_000: "🔥",
|
||||
100_000: "🚀",
|
||||
1_000_000: "🤯",
|
||||
}
|
||||
const [payService, setPayService] = useState<LNURLService>();
|
||||
const [amount, setAmount] = useState<number>();
|
||||
const [amount, setAmount] = useState<number>(500);
|
||||
const [customAmount, setCustomAmount] = useState<number>();
|
||||
const [invoice, setInvoice] = useState<LNURLInvoice>();
|
||||
const [comment, setComment] = useState<string>();
|
||||
@ -53,6 +70,7 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
const [success, setSuccess] = useState<LNURLSuccessAction>();
|
||||
const webln = useWebln(show);
|
||||
const publisher = useEventPublisher();
|
||||
const horizontalScroll = useHorizontalScroll();
|
||||
|
||||
useEffect(() => {
|
||||
if (show && !props.invoice) {
|
||||
@ -63,7 +81,7 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
setPayService(undefined);
|
||||
setError(undefined);
|
||||
setInvoice(props.invoice ? { pr: props.invoice } : undefined);
|
||||
setAmount(undefined);
|
||||
setAmount(500);
|
||||
setComment(undefined);
|
||||
setSuccess(undefined);
|
||||
}
|
||||
@ -155,12 +173,27 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
};
|
||||
|
||||
function custom() {
|
||||
let min = (payService?.minSendable ?? 0) / 1000;
|
||||
let min = (payService?.minSendable ?? 1000) / 1000;
|
||||
let max = (payService?.maxSendable ?? 21_000_000_000) / 1000;
|
||||
return (
|
||||
<div className="flex mb10">
|
||||
<input type="number" min={min} max={max} className="f-grow mr10" value={customAmount} onChange={(e) => setCustomAmount(parseInt(e.target.value))} />
|
||||
<div className="btn" onClick={() => selectAmount(customAmount!)}>Confirm</div>
|
||||
<div className="custom-amount flex">
|
||||
<input
|
||||
type="number"
|
||||
min={min}
|
||||
max={max}
|
||||
className="f-grow mr10"
|
||||
placeholder="Custom"
|
||||
value={customAmount}
|
||||
onChange={(e) => setCustomAmount(parseInt(e.target.value))}
|
||||
/>
|
||||
<button
|
||||
className="secondary"
|
||||
type="button"
|
||||
disabled={!Boolean(customAmount)}
|
||||
onClick={() => selectAmount(customAmount!)}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -182,22 +215,36 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
if (invoice) return null;
|
||||
return (
|
||||
<>
|
||||
<div className="f-ellipsis mb10">{metadata?.description ?? service}</div>
|
||||
<h3>Zap amount in sats</h3>
|
||||
<div className="amounts" ref={horizontalScroll}>
|
||||
{serviceAmounts.map(a =>
|
||||
<span className={`sat-amount ${amount === a ? "active" : ""}`} key={a} onClick={() => selectAmount(a)}>
|
||||
{emojis[a] && <>{emojis[a]} </> }
|
||||
{formatShort(a)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{payService && custom()}
|
||||
<div className="flex">
|
||||
{(payService?.commentAllowed ?? 0) > 0 ?
|
||||
<input type="text" placeholder="Comment" className="mb10 f-grow" maxLength={payService?.commentAllowed} onChange={(e) => setComment(e.target.value)} /> : null}
|
||||
{(payService?.commentAllowed ?? 0) > 0 &&
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Comment"
|
||||
className="f-grow"
|
||||
maxLength={payService?.commentAllowed}
|
||||
onChange={(e) => setComment(e.target.value)}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className="mb10">
|
||||
{serviceAmounts.map(a => <span className={`sat-amount ${amount === a ? "active" : ""}`} key={a} onClick={() => selectAmount(a)}>
|
||||
{a.toLocaleString()}
|
||||
</span>)}
|
||||
{payService ?
|
||||
<span className={`sat-amount ${amount === -1 ? "active" : ""}`} onClick={() => selectAmount(-1)}>
|
||||
Custom
|
||||
</span> : null}
|
||||
</div>
|
||||
{amount === -1 ? custom() : null}
|
||||
{(amount ?? 0) > 0 && <button type="button" className="mb10" onClick={() => loadInvoice()}>Get Invoice</button>}
|
||||
{(amount ?? 0) > 0 && (
|
||||
<button type="button" className="zap-action" onClick={() => loadInvoice()}>
|
||||
<div className="zap-action-container">
|
||||
<Zap /> Zap
|
||||
{target && ` ${target} `}
|
||||
{formatShort(amount)} sats
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -208,22 +255,20 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="invoice">
|
||||
{props.notice && <b className="error">{props.notice}</b>}
|
||||
<QrCode data={pr} link={`lightning:${pr}`} />
|
||||
<div className="actions">
|
||||
{pr && (
|
||||
<>
|
||||
<div className="copy-action">
|
||||
<Copy text={pr} maxSize={26} />
|
||||
</div>
|
||||
<div className="pay-actions">
|
||||
<button type="button" onClick={() => window.open(`lightning:${pr}`)}>
|
||||
Open Wallet
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{props.notice && <b className="error">{props.notice}</b>}
|
||||
<QrCode data={pr} link={`lightning:${pr}`} />
|
||||
<div className="actions">
|
||||
{pr && (
|
||||
<>
|
||||
<div className="copy-action">
|
||||
<Copy text={pr} maxSize={26} />
|
||||
</div>
|
||||
<button className="wallet-action" type="button" onClick={() => window.open(`lightning:${pr}`)}>
|
||||
Open Wallet
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
@ -232,24 +277,46 @@ export default function LNURLTip(props: LNURLTipProps) {
|
||||
function successAction() {
|
||||
if (!success) return null;
|
||||
return (
|
||||
<>
|
||||
<p>{success?.description ?? "Paid!"}</p>
|
||||
{success.url ? <a href={success.url} rel="noreferrer" target="_blank">{success.url}</a> : null}
|
||||
</>
|
||||
<div className="success-action">
|
||||
<p className="paid">
|
||||
<Check className="success mr10" />
|
||||
{success?.description ?? "Paid!"}
|
||||
</p>
|
||||
{success.url &&
|
||||
<p>
|
||||
<a
|
||||
href={success.url}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{success.url}
|
||||
</a>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const defaultTitle = payService?.nostrPubkey ? "⚡️ Send Zap!" : "⚡️ Send sats";
|
||||
const defaultTitle = payService?.nostrPubkey ? "Send zap" : "Send sats";
|
||||
const title = target ? `${defaultTitle} to ${target}` : defaultTitle
|
||||
if (!show) return null;
|
||||
return (
|
||||
<Modal onClose={onClose}>
|
||||
<div className="lnurl-tip" onClick={(e) => e.stopPropagation()}>
|
||||
<h2>{props.title || defaultTitle}</h2>
|
||||
{invoiceForm()}
|
||||
{error ? <p className="error">{error}</p> : null}
|
||||
{payInvoice()}
|
||||
{successAction()}
|
||||
</div>
|
||||
<Modal className="lnurl-modal" onClose={onClose}>
|
||||
<div className="lnurl-tip" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="close" onClick={onClose}>
|
||||
<Close />
|
||||
</div>
|
||||
<div className="lnurl-header">
|
||||
{author && <ProfileImage pubkey={author} showUsername={false} />}
|
||||
<h2>
|
||||
{props.title || title}
|
||||
</h2>
|
||||
</div>
|
||||
{invoiceForm()}
|
||||
{error && <p className="error">{error}</p>}
|
||||
{payInvoice()}
|
||||
{successAction()}
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
overflow-x: scroll;
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
@ -12,7 +13,8 @@
|
||||
}
|
||||
|
||||
.tab {
|
||||
border: 1px solid var(--gray-secondary);
|
||||
color: var(--font-tertiary-color);
|
||||
border: 1px solid var(--font-tertiary-color);
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
@ -21,7 +23,6 @@
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
color: #A3A3A3;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-left: 52px;
|
||||
margin-left: 56px;
|
||||
}
|
||||
|
||||
.note.thread-root .zaps-summary {
|
||||
@ -70,8 +70,8 @@
|
||||
}
|
||||
|
||||
.top-zap .avatar {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.top-zap .nip05 {
|
||||
|
@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useState } from "react";
|
||||
import { useUserProfile } from "Feed/ProfileFeed";
|
||||
import { HexKey } from "Nostr";
|
||||
import LNURLTip from "Element/LNURLTip";
|
||||
import SendSats from "Element/SendSats";
|
||||
|
||||
|
||||
const ZapButton = ({ pubkey, svc }: { pubkey?: HexKey, svc?: string }) => {
|
||||
@ -19,7 +19,7 @@ const ZapButton = ({ pubkey, svc }: { pubkey?: HexKey, svc?: string }) => {
|
||||
<div className="zap-button" onClick={(e) => setZap(true)}>
|
||||
<FontAwesomeIcon icon={faBolt} />
|
||||
</div>
|
||||
<LNURLTip svc={service} show={zap} onClose={() => setZap(false)} author={pubkey} />
|
||||
<SendSats target={profile?.display_name || profile?.name} svc={service} show={zap} onClose={() => setZap(false)} author={pubkey} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user