Show invoices

This commit is contained in:
2023-01-02 13:40:42 +00:00
parent 6b19183524
commit 656aee2049
7 changed files with 140 additions and 191 deletions

5
src/element/Invoice.css Normal file
View File

@ -0,0 +1,5 @@
.invoice {
border-radius: 10px;
border: 1px solid #444;
padding: 10px;
}

27
src/element/Invoice.js Normal file
View File

@ -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 (
<div className="invoice flex">
<div className="f-grow">
Invoice for {info?.amount?.toLocaleString()} sats
</div>
<div className="btn" onClick={() => window.open(`lightning:${invoice}`)}>Pay</div>
</div>
)
}

View File

@ -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 <img key={url} src={url} />;
}
case "mp4":
case "mkv":
case "avi":
case "m4v": {
return <video key={url} src={url} controls />
}
function extractInvoices(fragments) {
return fragments.map(f => {
if (typeof f === "string") {
return f.split(InvoiceRegex).map(i => {
if (i.toLowerCase().startsWith("lnbc")) {
return <Invoice key={i} invoice={i}/>
} else {
return i;
}
} else {
return <a href={url}>{url.toString()}</a>
}
} else {
let mentions = a.split(MentionRegex).map((match) => {
});
}
return f;
}).flat();
}
function extractMentions(fragments) {
return fragments.map(f => {
if (typeof f === "string") {
return f.split(MentionRegex).map((match) => {
let matchTag = match.match(/#\[(\d+)\]/);
if (matchTag && matchTag.length === 2) {
let idx = parseInt(matchTag[1]);
@ -106,10 +105,44 @@ export default function Note(props) {
return match;
}
});
return mentions;
}
return a;
});
return f;
}).flat();
}
function extractLinks(fragments) {
return fragments.map(f => {
if (typeof f === "string") {
return f.split(UrlRegex).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 <img key={url} src={url} />;
}
case "mp4":
case "mkv":
case "avi":
case "m4v": {
return <video key={url} src={url} controls />
}
}
} else {
return <a href={url}>{url.toString()}</a>
}
}
return a;
});
}
return f;
}).flat();
}
async function like() {

View File

@ -18,6 +18,7 @@ const RecommendedFollows = [
"3F770D65D3A764A9C5CB503AE123E62EC7598AD035D836E2A810F3877A745B24", // DerekRoss
"472F440F29EF996E92A186B8D320FF180C855903882E59D50DE1B8BD5669301E", // MartyBent
"1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", // yegorpetrov
"04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9", // ODELL
];
export default function NewUserPage(props) {

View File

@ -124,6 +124,7 @@ const LoginSlice = createSlice({
state.publicKey = null;
state.follows = [];
state.notifications = [];
state.loggedOut = true;
},
markNotificationsRead: (state) => {
state.readNotifications = new Date().getTime();