add lightning payment mode setting

This commit is contained in:
hzrd149
2023-03-24 11:04:40 -05:00
parent a41c4d5041
commit 1f40f5643e
4 changed files with 88 additions and 15 deletions

View File

@@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Add lighting payment mode setting

View File

@@ -1,6 +1,7 @@
import { import {
Button, Button,
ButtonGroup, ButtonGroup,
DefaultIcon,
Flex, Flex,
IconButton, IconButton,
Input, Input,
@@ -33,6 +34,7 @@ import { useSigningContext } from "../providers/signing-provider";
import QrCodeSvg from "./qr-code-svg"; import QrCodeSvg from "./qr-code-svg";
import { CopyIconButton } from "./copy-icon-button"; import { CopyIconButton } from "./copy-icon-button";
import { useIsMobile } from "../hooks/use-is-mobile"; import { useIsMobile } from "../hooks/use-is-mobile";
import settings from "../services/settings";
type FormValues = { type FormValues = {
amount: number; amount: number;
@@ -59,7 +61,7 @@ export default function ZapModal({
const metadata = useUserMetadata(pubkey); const metadata = useUserMetadata(pubkey);
const { requestSignature } = useSigningContext(); const { requestSignature } = useSigningContext();
const toast = useToast(); const toast = useToast();
const [invoice, setInvoice] = useState<string>(); const [promptInvoice, setPromptInvoice] = useState<string>();
const { isOpen: showQr, onToggle: toggleQr } = useDisclosure(); const { isOpen: showQr, onToggle: toggleQr } = useDisclosure();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
@@ -118,7 +120,7 @@ export default function ZapModal({
const parsed = parsePaymentRequest(payRequest); const parsed = parsePaymentRequest(payRequest);
if (parsed.amount !== amountInMilisat) throw new Error("incorrect amount"); if (parsed.amount !== amountInMilisat) throw new Error("incorrect amount");
setInvoice(payRequest); payInvoice(payRequest);
} else throw new Error("Failed to get invoice"); } else throw new Error("Failed to get invoice");
} }
} else { } else {
@@ -131,7 +133,7 @@ export default function ZapModal({
const parsed = parsePaymentRequest(payRequest); const parsed = parsePaymentRequest(payRequest);
if (parsed.amount !== amountInMilisat) throw new Error("incorrect amount"); if (parsed.amount !== amountInMilisat) throw new Error("incorrect amount");
setInvoice(payRequest); payInvoice(payRequest);
} else throw new Error("Failed to get invoice"); } else throw new Error("Failed to get invoice");
} }
} else throw new Error("Failed to get LNURL metadata"); } else throw new Error("Failed to get LNURL metadata");
@@ -140,7 +142,7 @@ export default function ZapModal({
} }
}; };
const payWithWebLn = async () => { const payWithWebLn = async (invoice: string) => {
if (window.webln && invoice) { if (window.webln && invoice) {
if (!window.webln.enabled) await window.webln.enable(); if (!window.webln.enabled) await window.webln.enable();
await window.webln.sendPayment(invoice); await window.webln.sendPayment(invoice);
@@ -155,7 +157,7 @@ export default function ZapModal({
onClose(); onClose();
} }
}; };
const payWithApp = async () => { const payWithApp = async (invoice: string) => {
window.open("lightning:" + invoice); window.open("lightning:" + invoice);
const listener = () => { const listener = () => {
@@ -170,9 +172,24 @@ export default function ZapModal({
}, 1000 * 2); }, 1000 * 2);
}; };
const payInvoice = (invoice: string) => {
switch (settings.lightningPayMode.value) {
case "webln":
payWithWebLn(invoice);
break;
case "external":
payWithApp(invoice);
break;
default:
case "prompt":
setPromptInvoice(invoice);
break;
}
};
const handleClose = () => { const handleClose = () => {
// if there was an invoice and we a closing the modal. presume it was paid // if there was an invoice and we are closing the modal. presume it was paid
if (invoice && onPaid) { if (promptInvoice && onPaid) {
onPaid(); onPaid();
} }
onClose(); onClose();
@@ -183,11 +200,11 @@ export default function ZapModal({
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalBody padding="4"> <ModalBody padding="4">
{invoice ? ( {promptInvoice ? (
<Flex gap="4" direction="column"> <Flex gap="4" direction="column">
{showQr && <QrCodeSvg content={invoice} />} {showQr && <QrCodeSvg content={promptInvoice} />}
<Flex gap="2"> <Flex gap="2">
<Input value={invoice} readOnly /> <Input value={promptInvoice} readOnly />
<IconButton <IconButton
icon={<QrCodeIcon />} icon={<QrCodeIcon />}
aria-label="Show QrCode" aria-label="Show QrCode"
@@ -195,15 +212,21 @@ export default function ZapModal({
variant="solid" variant="solid"
size="md" size="md"
/> />
<CopyIconButton text={invoice} aria-label="Copy Invoice" variant="solid" size="md" /> <CopyIconButton text={promptInvoice} aria-label="Copy Invoice" variant="solid" size="md" />
</Flex> </Flex>
<Flex gap="2"> <Flex gap="2">
{window.webln && ( {window.webln && (
<Button onClick={payWithWebLn} flex={1} variant="solid" size="md"> <Button onClick={() => payWithWebLn(promptInvoice)} flex={1} variant="solid" size="md">
Pay with WebLN Pay with WebLN
</Button> </Button>
)} )}
<Button leftIcon={<ExternalLinkIcon />} onClick={payWithApp} flex={1} variant="solid" size="md"> <Button
leftIcon={<ExternalLinkIcon />}
onClick={() => payWithApp(promptInvoice)}
flex={1}
variant="solid"
size="md"
>
Open App Open App
</Button> </Button>
</Flex> </Flex>

View File

@@ -2,6 +2,12 @@ import { PersistentSubject } from "../classes/subject";
import db from "./db"; import db from "./db";
import { Account } from "./account"; import { Account } from "./account";
export enum LightningPayMode {
Prompt = "prompt",
Webln = "webln",
External = "external",
}
const settings = { const settings = {
blurImages: new PersistentSubject(true), blurImages: new PersistentSubject(true),
autoShowMedia: new PersistentSubject(true), autoShowMedia: new PersistentSubject(true),
@@ -9,6 +15,7 @@ const settings = {
showReactions: new PersistentSubject(true), showReactions: new PersistentSubject(true),
showSignatureVerification: new PersistentSubject(false), showSignatureVerification: new PersistentSubject(false),
accounts: new PersistentSubject<Account[]>([]), accounts: new PersistentSubject<Account[]>([]),
lightningPayMode: new PersistentSubject<LightningPayMode>(LightningPayMode.Prompt),
}; };
async function loadSettings() { async function loadSettings() {

View File

@@ -13,13 +13,14 @@ import {
AccordionIcon, AccordionIcon,
ButtonGroup, ButtonGroup,
FormHelperText, FormHelperText,
Select,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useState } from "react"; import { useState } from "react";
import settings from "../../services/settings"; import settings, { LightningPayMode } from "../../services/settings";
import { clearCacheData, deleteDatabase } from "../../services/db"; import { clearCacheData, deleteDatabase } from "../../services/db";
import accountService from "../../services/account"; import accountService from "../../services/account";
import useSubject from "../../hooks/use-subject"; import useSubject from "../../hooks/use-subject";
import { LogoutIcon } from "../../components/icons"; import { LightningIcon, LogoutIcon } from "../../components/icons";
export default function SettingsView() { export default function SettingsView() {
const blurImages = useSubject(settings.blurImages); const blurImages = useSubject(settings.blurImages);
@@ -27,6 +28,7 @@ export default function SettingsView() {
const proxyUserMedia = useSubject(settings.proxyUserMedia); const proxyUserMedia = useSubject(settings.proxyUserMedia);
const showReactions = useSubject(settings.showReactions); const showReactions = useSubject(settings.showReactions);
const showSignatureVerification = useSubject(settings.showSignatureVerification); const showSignatureVerification = useSubject(settings.showSignatureVerification);
const lightningPayMode = useSubject(settings.lightningPayMode);
const { colorMode, setColorMode } = useColorMode(); const { colorMode, setColorMode } = useColorMode();
@@ -178,6 +180,42 @@ export default function SettingsView() {
</AccordionPanel> </AccordionPanel>
</AccordionItem> </AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box as="span" flex="1" textAlign="left">
Lightning <LightningIcon color="yellow.400" />
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel>
<Flex direction="column" gap="4">
<FormControl>
<FormLabel htmlFor="lightning-payment-mode" mb="0">
Payment mode
</FormLabel>
<Select
id="lightning-payment-mode"
value={lightningPayMode}
onChange={(e) => settings.lightningPayMode.next(e.target.value as LightningPayMode)}
>
<option value="prompt">Prompt</option>
<option value="webln">WebLN</option>
<option value="external">External</option>
</Select>
<FormHelperText>
<span>Prompt: Ask every time</span>
<br />
<span>WebLN: Use browser extension</span>
<br />
<span>External: Open an external app using "lightning:" link</span>
</FormHelperText>
</FormControl>
</Flex>
</AccordionPanel>
</AccordionItem>
<AccordionItem> <AccordionItem>
<h2> <h2>
<AccordionButton> <AccordionButton>