lnurl-pay.me/src/App.svelte
2021-07-17 13:44:07 +03:00

234 lines
6.1 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
export let name;
import { Styles,
Container,
Row,
Col,
Card, CardBody, CardHeader, CardTitle,
Button,
Tooltip,
Icon,
InputGroup,
Nav, NavItem, NavLink,
Modal, ModalHeader, ModalBody, ModalFooter,
} from 'sveltestrap';
import SiteHead from './SiteHead.svelte';
import SiteCard from './SiteCard.svelte';
import SiteDeck from './SiteDeck.svelte';
import InputMask from './InputMask.svelte';
import payways from './payways.js';
import QR from './QR.svelte';
import CTC from './CTC.svelte';
import Tipped from './Tipped.svelte';
import { bech32 } from 'bech32'
import UTF8 from 'utf-8'
import PayFlow from './PayFlow.svelte';
let payway = payways[0];
setTimeout(()=>{
payway = payways[0];
accounts[inputId]=null;
},0);
let inputId;
let amountMask;
let realAmount;
$: inputId = payway.iid||payway.id;
$: amountMask = {
mask: Number, scale:2,
min: payway.min, max:payway.max,
radix:".",mapToRadix:[","],
padFractionalZeros: true,
normalizeZeros: true}
$: realAmount = amounts[payway.id] && (
Math.max(Math.min(amounts[payway.id], payway.max),payway.min))
function genAutoMemo(payway,account,amount) {
if (!account)
return "...automatic";
if (amount)
amount = parseFloat(amount)
let sum = amount?
amount.toFixed(amount===Math.round(amount)?0:2)
+ " " + payway.currency.toLowerCase() : "some sats";
return sum + " to " + payway.id + " " + account;
}
let autoMemo;
$: autoMemo = genAutoMemo(payway,
accountComplete && accounts[inputId],
realAmount)
function lnurlEncode(url) {
return bech32.encode("LNURL",
bech32.toWords(UTF8.setBytesFromString(url)),2048)
}
function toHexString(byteArray) {
return Array.from(byteArray, function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('')
}
function genLNURL(payway,account,amount,memo) {
let params = new URLSearchParams();
params.set("mtg","pay");
params.set("p",payway.id);
params.set("acc",toHexString(UTF8.setBytesFromString(account)))
params.set("v","1")
if (amount) {
params.set(payway.currency.toLowerCase(),amount)
}
if (memo) {
params.set("m",toHexString(UTF8.setBytesFromString(memo)))
}
return lnurlEncode("https://lnurl-pay.me/pay?"+params.toString()).toUpperCase()
}
let accounts = {};
let amounts = {};
let memo;
let lnurl;
$: lnurl = accountComplete ?
genLNURL(payway, accounts[inputId], realAmount, memo) : "";
const curr = {
"UAH":"₴",
"RUB":"₽",
"USD":"$",
"KZT":"₸",
}
let accountComplete = false;
const canShare = !!navigator.share;
let getInvoiceFor;
</script>
<SiteHead/>
<SiteDeck>
<SiteCard>
<p class="form-text">Fill in everything to get your lnurl-pay link</p>
<label class="form-label mb-3">Payment direction
<select class="form-select" autofocus bind:value="{payway}">
{#each payways as payway}
<option value="{payway}">{payway.name}</option>
{/each}
</select>
</label>
{#key payway}
<label class="form-label mb-3">{payway.acc}
<InputMask
unmask
bind:value={accounts[inputId]}
bind:isComplete={accountComplete}
imask={payway.imask||{mask:/.*/}}
autocomplete={payway.autocomplete}
inputmode={payway.inputmode||"numeric"}
placeholder={payway.placeholder}
class="form-control"/>
</label>
<label class="form-label mb-3">
Amount: {payway.currency} {payway.min} {payway.max}
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">{curr[payway.currency]}</span>
</div>
<InputMask bind:value={amounts[payway.id]}
unmask
imask={amountMask}
placeholder="determined by payer"
inputmode={"numeric"}
class="form-control"/>
<button class="btn btn-outline-secondary"
type="button"
on:click={()=> amounts[payway.id]=payway.min.toString()}>Min
</button>
<button class="btn btn-outline-secondary"
type="button"
on:click={()=> amounts[payway.id]=payway.max.toString()}>Max
</button>
</div>
</label>
{/key}
<label class="form-label mb-3">Lnurl MEMO
<input bind:value={memo} placeholder="{autoMemo}"
class="form-control"/>
</label>
</SiteCard>
<SiteCard>
{#if lnurl}
<CTC let:id let:action force text={lnurl}>
<div class="form-text user-select-all mb-2 mt-2"
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
on:click={action} id={id}>{lnurl}
</div>
</CTC>
{:else}
<div class="form-text mb-2 mt-2">Expecting: {payway.acc.toLowerCase()}</div>
{/if}
<div class="d-flex justify-content-center align-items-stretch m-2"
class:invisible={!lnurl}>
<!-- {#key lnurl} -->
<a href="lightning:{lnurl}">
<QR value={lnurl} size="{230}" />
</a>
<!-- {/key} -->
</div>
<div class="d-flex justify-content-center align-items-stretch"
class:invisible={!lnurl}>
<p class="form-text">You might want to save image and share it
as you like. All form data are present in lnurl: don't share what you wanted to hide.</p>
</div>
<div class="btn-group flex-wrap mt-auto mb-2"
role="group" class:invisible={!lnurl}>
<CTC let:id let:action text={lnurl}>
<button type="button" class="btn btn-outline-secondary"
id={id} on:click={action}>Copy</button>
</CTC>
{#if canShare}
<button type="button" class="btn btn-outline-secondary"
on:click={()=>{ navigator.share({text:lnurl})}}>Share
</button>
{/if}
<Tipped let:id>
<a slot="thing" role="button" class="btn btn-outline-secondary"
href="lightning:{lnurl}" {id}>Pay</a>
<div slot="tip">open in your wallet</div>
</Tipped>
<Tipped let:id>
<button slot="thing" {id} type="button"
class="btn btn-outline-secondary"
on:click="{()=>getInvoiceFor=lnurl}">
Invoice</button>
<div slot="tip">get an invoice for wallets with no lnurl-pay</div>
</Tipped>
</div>
</SiteCard>
</SiteDeck>
<PayFlow bind:lnurl={getInvoiceFor}/>
<!-- <Styles/> -->