refactor
This commit is contained in:
parent
c52b56871c
commit
241ead7a03
66
packages/app/src/Element/CashuNuts.tsx
Normal file
66
packages/app/src/Element/CashuNuts.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { getDecodedToken } from "@cashu/cashu-ts";
|
||||
import { useMemo } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import useLogin from "Hooks/useLogin";
|
||||
import { useUserProfile } from "Hooks/useUserProfile";
|
||||
|
||||
export default function CashuNuts({ token }: { token: string }) {
|
||||
const login = useLogin();
|
||||
const profile = useUserProfile(login.publicKey);
|
||||
|
||||
async function copyToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
|
||||
e.stopPropagation();
|
||||
await navigator.clipboard.writeText(token);
|
||||
}
|
||||
async function redeemToken(e: React.MouseEvent<HTMLButtonElement>, token: string) {
|
||||
e.stopPropagation();
|
||||
const lnurl = profile?.lud16 ?? "";
|
||||
const url = `https://redeem.cashu.me?token=${encodeURIComponent(token)}&lightning=${encodeURIComponent(lnurl)}`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
const cashu = useMemo(() => {
|
||||
try {
|
||||
if (!token.startsWith("cashuA") || token.length < 10) {
|
||||
return;
|
||||
}
|
||||
return getDecodedToken(token);
|
||||
} catch {
|
||||
// ignored
|
||||
}
|
||||
}, [token]);
|
||||
|
||||
if (!cashu) return <>{token}</>;
|
||||
|
||||
return (
|
||||
<div className="note-invoice">
|
||||
<div className="flex f-between">
|
||||
<div>
|
||||
<h4>
|
||||
<FormattedMessage defaultMessage="Cashu token" />
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Amount: {amount} sats"
|
||||
values={{
|
||||
amount: cashu.token[0].proofs.reduce((acc, v) => acc + v.amount, 0),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<small className="xs">
|
||||
<FormattedMessage defaultMessage="Mint: {url}" values={{ url: cashu.token[0].mint }} />
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={e => copyToken(e, token)} className="mr5">
|
||||
<FormattedMessage defaultMessage="Copy" description="Button: Copy Cashu token" />
|
||||
</button>
|
||||
<button onClick={e => redeemToken(e, token)}>
|
||||
<FormattedMessage defaultMessage="Redeem" description="Button: Redeem Cashu token" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -6,15 +6,13 @@ import { visit, SKIP } from "unist-util-visit";
|
||||
import * as unist from "unist";
|
||||
import { HexKey, NostrPrefix } from "@snort/nostr";
|
||||
|
||||
import { getDecodedToken } from "@cashu/cashu-ts";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { MentionRegex, InvoiceRegex, HashtagRegex, CashuRegex } from "Const";
|
||||
import { eventLink, hexToBech32, splitByUrl, unwrap } from "Util";
|
||||
import { eventLink, hexToBech32, splitByUrl, unwrap, validateNostrLink } from "Util";
|
||||
import Invoice from "Element/Invoice";
|
||||
import Hashtag from "Element/Hashtag";
|
||||
import Mention from "Element/Mention";
|
||||
import HyperText from "Element/HyperText";
|
||||
import CashuNuts from "Element/CashuNuts";
|
||||
|
||||
export type Fragment = string | React.ReactNode;
|
||||
|
||||
@ -72,46 +70,11 @@ export default function Text({ content, tags, creator, disableMedia, depth }: Te
|
||||
}
|
||||
|
||||
function extractCashuTokens(fragments: Fragment[]) {
|
||||
async function copyToken(token: string) {
|
||||
await navigator.clipboard.writeText(token);
|
||||
}
|
||||
async function redeemToken(token: string) {
|
||||
const url = `https://redeem.cashu.me?token=${encodeURIComponent(token)}&lightning=${encodeURIComponent(
|
||||
"callebtc@ln.tips"
|
||||
)}`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
return fragments
|
||||
.map(f => {
|
||||
if (typeof f === "string" && f.includes("cashuA")) {
|
||||
return f.split(CashuRegex).map(a => {
|
||||
if (!a.startsWith("cashuA") || a.length < 10) {
|
||||
return a;
|
||||
}
|
||||
const cashu = getDecodedToken(a);
|
||||
if (cashu && cashu.token[0].proofs) {
|
||||
return (
|
||||
<div className="note-invoice" style={{ paddingRight: "0px" }}>
|
||||
<div className="flex f-between">
|
||||
<div>
|
||||
<h4>Cashu token</h4>
|
||||
<p>Amount: {cashu.token[0].proofs.reduce((acc, v) => (acc += v.amount), 0)} sats</p>
|
||||
<p style={{ fontSize: "0.6em" }}>Mint: {cashu.token[0].mint}</p>
|
||||
</div>
|
||||
<div>
|
||||
<button style={{ margin: "5px" }} type="button" onClick={() => copyToken(a)}>
|
||||
<FormattedMessage defaultMessage="Copy" description="Button: Copy Cashu token" />
|
||||
</button>
|
||||
<button type="button" onClick={() => redeemToken(a)}>
|
||||
<FormattedMessage defaultMessage="Redeem" description="Button: Redeem Cashu token" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return a;
|
||||
return <CashuNuts token={a} />;
|
||||
});
|
||||
}
|
||||
return f;
|
||||
|
@ -220,7 +220,7 @@ export default function LoginPage() {
|
||||
/>
|
||||
</div>
|
||||
{error.length > 0 ? <b className="error">{error}</b> : null}
|
||||
<p className="login-note">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Only the secret key can be used to publish (sign events), everything else logs you in read-only mode."
|
||||
description="Explanation for public key only login is read-only"
|
||||
|
@ -422,6 +422,10 @@ body.scroll-lock {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
small.xs {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user