mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-22 15:19:47 +02:00
add lightning payment mode setting
This commit is contained in:
5
.changeset/yellow-trainers-sparkle.md
Normal file
5
.changeset/yellow-trainers-sparkle.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"nostrudel": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add lighting payment mode setting
|
@@ -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>
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user