From 656aee204958cb713f3f0dad8dbe507f0f7e63a1 Mon Sep 17 00:00:00 2001 From: Kieran Date: Mon, 2 Jan 2023 13:40:42 +0000 Subject: [PATCH] Show invoices --- package.json | 2 +- src/element/Invoice.css | 5 + src/element/Invoice.js | 27 ++++++ src/element/Note.js | 99 +++++++++++++------- src/pages/NewUserPage.js | 1 + src/state/Login.js | 1 + yarn.lock | 196 ++++++++------------------------------- 7 files changed, 140 insertions(+), 191 deletions(-) create mode 100644 src/element/Invoice.css create mode 100644 src/element/Invoice.js diff --git a/package.json b/package.json index aaf56f6a..0df6806b 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@noble/secp256k1": "^1.7.0", "@reduxjs/toolkit": "^1.9.1", "bech32": "^2.0.0", - "invoices": "^2.2.2", + "light-bolt11-decoder": "^2.1.0", "moment": "^2.29.4", "qr-code-styling": "^1.6.0-rc.1", "react": "^18.2.0", diff --git a/src/element/Invoice.css b/src/element/Invoice.css new file mode 100644 index 00000000..e5a7cbc5 --- /dev/null +++ b/src/element/Invoice.css @@ -0,0 +1,5 @@ +.invoice { + border-radius: 10px; + border: 1px solid #444; + padding: 10px; +} \ No newline at end of file diff --git a/src/element/Invoice.js b/src/element/Invoice.js new file mode 100644 index 00000000..ecee7766 --- /dev/null +++ b/src/element/Invoice.js @@ -0,0 +1,27 @@ +import "./Invoice.css"; +import { decode as invoiceDecode } from "light-bolt11-decoder"; +import { useMemo } from "react"; +import { useNavigate } from "react-router-dom"; + +export default function Invoice(props) { + const invoice = props.invoice; + const navigate = useNavigate(); + + const info = useMemo(() => { + let parsed = invoiceDecode(invoice); + + let amount = parseInt(parsed.sections.find(a => a.name === "amount")?.value); + return { + amount: !isNaN(amount) ? (amount / 1000) : null + } + }, [invoice]); + + return ( +
+
+ ⚡️ Invoice for {info?.amount?.toLocaleString()} sats +
+
window.open(`lightning:${invoice}`)}>Pay
+
+ ) +} \ No newline at end of file diff --git a/src/element/Note.js b/src/element/Note.js index d984e9b8..decb4fa0 100644 --- a/src/element/Note.js +++ b/src/element/Note.js @@ -1,5 +1,5 @@ import "./Note.css"; -import { useState } from "react"; +import { useCallback, useState } from "react"; import { useSelector } from "react-redux"; import moment from "moment"; import { Link, useNavigate } from "react-router-dom"; @@ -10,10 +10,12 @@ import Event from "../nostr/Event"; import ProfileImage from "./ProfileImage"; import useEventPublisher from "../feed/EventPublisher"; import { NoteCreator } from "./NoteCreator"; +import Invoice from "./Invoice"; const UrlRegex = /((?:http|ftp|https):\/\/(?:[\w+?\.\w+])+(?:[a-zA-Z0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?)/i; const FileExtensionRegex = /\.([\w]+)$/i; const MentionRegex = /(#\[\d+\])/gi; +const InvoiceRegex = /(lnbc\w+)/i; export default function Note(props) { const navigate = useNavigate(); @@ -33,6 +35,14 @@ export default function Note(props) { ...opt }; + const transformBody = useCallback(() => { + let body = ev?.Content ?? ""; + + let fragments = extractLinks([body]); + fragments = extractMentions(fragments); + return extractInvoices(fragments); + }, [data, dataEvent]); + function goToEvent(e, id) { if (!window.location.pathname.startsWith("/e/")) { e.stopPropagation(); @@ -55,36 +65,25 @@ export default function Note(props) { ) } - function transformBody() { - let body = ev.Content; - let urlBody = body.split(UrlRegex); - - return urlBody.map(a => { - if (a.startsWith("http")) { - let url = new URL(a); - let ext = url.pathname.toLowerCase().match(FileExtensionRegex); - if (ext) { - switch (ext[1]) { - case "gif": - case "jpg": - case "jpeg": - case "png": - case "bmp": - case "webp": { - return ; - } - case "mp4": - case "mkv": - case "avi": - case "m4v": { - return