Custom amounts on LNURL

This commit is contained in:
Kieran 2023-01-07 23:01:32 +00:00
parent 037f39e386
commit 18b6f19894
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
5 changed files with 49 additions and 19 deletions

View File

@ -2,7 +2,7 @@
background-color: #222;
padding: 10px;
border-radius: 10px;
width: 50vw;
width: 500px;
text-align: center;
min-height: 10vh;
}

View File

@ -11,15 +11,23 @@ export default function LNURLTip(props) {
const amounts = [50, 100, 500, 1_000, 5_000, 10_000];
const [payService, setPayService] = useState("");
const [amount, setAmount] = useState(0);
const [customAmount, setCustomAmount] = useState(0);
const [invoice, setInvoice] = useState("");
const [comment, setComment] = useState("");
const [error, setError] = useState("")
const selectAmount = (a) => {
setError("");
setInvoice("");
setAmount(a);
};
async function fetchJson(url) {
let rsp = await fetch(url);
if (rsp.ok) {
let data = await rsp.json();
console.log(data);
setError("");
return data;
}
return null;
@ -48,6 +56,7 @@ export default function LNURLTip(props) {
setError(data.reason);
} else {
setInvoice(data.pr);
setError("");
}
} else {
setError("Failed to load invoice");
@ -57,6 +66,17 @@ export default function LNURLTip(props) {
}
};
function custom() {
let min = (payService?.minSendable ?? 0) / 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(e.target.value)} />
<div className="btn" onClick={() => selectAmount(customAmount)}>Confirm</div>
</div>
);
}
useEffect(() => {
if (payService && amount > 0) {
loadInvoice();
@ -83,8 +103,11 @@ export default function LNURLTip(props) {
const metadata = useMemo(() => {
if (payService) {
let meta = JSON.parse(payService.metadata);
let desc = meta.find(a => a[0] === "text/plain");
let image = meta.find(a => a[0] === "image/png;base64");
return {
description: meta.find(a => a[0] === "text/plain")[1]
description: desc ? desc[1] : null,
image: image ? image[1] : null
};
}
return null;
@ -95,17 +118,21 @@ export default function LNURLTip(props) {
<Modal onClose={() => onClose()}>
<div className="lnurl-tip" onClick={(e) => e.stopPropagation()}>
<h2> Send sats</h2>
<div className="f-ellipsis mb10">{service}</div>
<div className="f-ellipsis mb10">{metadata?.description}</div>
<div className="f-ellipsis mb10">{metadata?.description ?? service}</div>
<div className="flex">
{payService?.commentAllowed > 0 ?
<input type="text" placeholder="Comment" className="mb10 f-grow" maxLength={payService?.commentAllowed} onChange={(e) => setComment(e.target.value)} /> : null}
</div>
<div className="mb10">
{serviceAmounts.map(a => <span className={`pill ${amount === a ? "active" : ""}`} key={a} onClick={() => setAmount(a)}>
{serviceAmounts.map(a => <span className={`pill ${amount === a ? "active" : ""}`} key={a} onClick={() => selectAmount(a)}>
{a.toLocaleString()}
</span>)}
{payService ?
<span className={`pill ${amount === -1 ? "active" : ""}`} onClick={() => selectAmount(-1)}>
Custom
</span> : null}
</div>
{amount === -1 ? custom() : null}
{error ? <p className="error">{error}</p> : null}
<QrCode link={invoice} />
</div>

View File

@ -22,10 +22,10 @@ export default function Note(props) {
const reactions = props.reactions;
const deletion = props.deletion;
const emojiReactions = reactions?.filter(({ Content }) => Content && Content !== "+" && Content !== "-" && Content !== "❤️")
.reduce((acc, { Content }) => {
const amount = acc[Content] || 0
return {...acc, [Content]: amount + 1 }
}, {})
.reduce((acc, { Content }) => {
const amount = acc[Content] || 0
return { ...acc, [Content]: amount + 1 }
}, {})
const likes = reactions?.filter(({ Content }) => Content === "+" || Content === "❤️").length ?? 0
const dislikes = reactions?.filter(({ Content }) => Content === "-").length ?? 0
const publisher = useEventPublisher();
@ -47,7 +47,7 @@ export default function Note(props) {
};
function hasReacted(emoji) {
return reactions?.find(({ PubKey, Content }) => Content === emoji && PubKey === login)
return reactions?.find(({ PubKey, Content }) => Content === emoji && PubKey === login)
}
const transformBody = useCallback(() => {
@ -156,15 +156,15 @@ export default function Note(props) {
<FontAwesomeIcon icon={faReply} />
</span>
{Object.keys(emojiReactions).map((emoji) => {
return (
<span className="pill" onClick={() => react(emoji)}>
<span style={{ filter: hasReacted(emoji) ? 'none' : 'grayscale(1)' }}>
{emoji}
return (
<span className="pill" onClick={() => react(emoji)}>
<span style={{ filter: hasReacted(emoji) ? 'none' : 'grayscale(1)' }}>
{emoji}
</span>
&nbsp;
{emojiReactions[emoji]}
</span>
&nbsp;
{emojiReactions[emoji]}
</span>
)
)
})}
<span className="pill" onClick={() => like()}>
<FontAwesomeIcon color={liked ? "red" : "currentColor"} icon={faHeart} /> &nbsp;

View File

@ -32,6 +32,8 @@ export default function QrCode(props) {
elm.href = `lightning:${link}`;
elm.click();
}
} else {
qrRef.current.innerHTML = "";
}
}, [link]);

View File

@ -65,7 +65,7 @@ code {
border-radius: 25px;
}
input[type="text"], input[type="password"], textarea {
input[type="text"], input[type="password"], input[type="number"], textarea {
padding: 10px;
border-radius: 5px;
border: 0;
@ -120,6 +120,7 @@ span.pill {
span.pill.active {
background-color: #444;
font-weight: bold;
}
span.pill:hover {