diff options
| -rw-r--r-- | package.json | 1 | ||||
| -rw-r--r-- | pnpm-lock.yaml | 12 | ||||
| -rw-r--r-- | src/components/Qr.svelte | 22 | ||||
| -rw-r--r-- | src/components/Tip.svelte | 135 | ||||
| -rw-r--r-- | src/lib/invoice.js | 20 | ||||
| -rw-r--r-- | src/lib/socket.js | 13 | ||||
| -rw-r--r-- | src/locales/en.json | 2 | ||||
| -rw-r--r-- | src/routes/[username]/receive/+page.server.js | 20 | ||||
| -rw-r--r-- | src/routes/invoice/[id]/+page.server.js | 5 | ||||
| -rw-r--r-- | src/routes/invoice/[id]/+page.svelte | 9 | ||||
| -rw-r--r-- | src/routes/invoice/[id]/paid/+page.svelte | 23 | ||||
| -rw-r--r-- | static/icons/check.svg | 35 |
12 files changed, 115 insertions, 182 deletions
diff --git a/package.json b/package.json index 5663853d..3afd183a 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "format": "prettier --write --plugin-search-dir=. ." }, "devDependencies": { - "@lottiefiles/svelte-lottie-player": "^0.2.0", "@sveltejs/adapter-node": "next", "@sveltejs/kit": "1.0.0-next.505", "@zerodevx/svelte-toast": "^0.7.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4538dda2..52f20ba5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,7 +1,6 @@ lockfileVersion: 5.4 specifiers: - '@lottiefiles/svelte-lottie-player': ^0.2.0 '@sveltejs/adapter-node': next '@sveltejs/kit': 1.0.0-next.505 '@zerodevx/svelte-toast': ^0.7.2 @@ -27,7 +26,6 @@ specifiers: vite: ^3.1.4 devDependencies: - '@lottiefiles/svelte-lottie-player': 0.2.0 '@sveltejs/adapter-node': 1.0.0-next.96 '@sveltejs/kit': [email protected][email protected] '@zerodevx/svelte-toast': 0.7.2 @@ -72,12 +70,6 @@ packages: dev: true optional: true - /@lottiefiles/svelte-lottie-player/0.2.0: - resolution: {integrity: sha512-sV8YkO8hCDGq67LCCqjT+JW6cAbVCIw9wtgrOWz+Ao6Q8cD7ZvdsCiipSIMIH55Ja6MWwEXP4N4nKD+jL3XQLg==} - dependencies: - lottie-web: 5.9.6 - dev: true - /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1059,10 +1051,6 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /lottie-web/5.9.6: - resolution: {integrity: sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA==} - dev: true - /magic-string/0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: diff --git a/src/components/Qr.svelte b/src/components/Qr.svelte index 099d5fa5..23282589 100644 --- a/src/components/Qr.svelte +++ b/src/components/Qr.svelte @@ -1,4 +1,5 @@ <script> + import { fly, fade } from 'svelte/transition'; import screenfull from 'screenfull'; import { browser } from '$app/environment'; import { onMount, tick } from 'svelte'; @@ -7,16 +8,14 @@ export let image, text, qr, fullQr, full; let toggle = async () => { + console.log('FULL', full); full = !full; await tick(); screenfull.toggle(fullQr.firstChild); }; let opts = { - height: 300, - width: 300, type: 'canvas', - data: text, backgroundOptions: { color: 'rgba(0, 0, 0, 0)' }, @@ -33,26 +32,33 @@ } }; + let mask = false; $: update(text); let update = async (text, fullscreen) => { + mask = true; if (!(browser && text)) return; let { default: QRCodeStyling } = await import('qr-code-styling'); + opts.data = text; + opts.height = opts.width = 300; const qrCode = new QRCodeStyling(opts); - opts.height = Math.min(window.innerWidth, window.innerHeight); - opts.width = opts.height; + opts.height = opts.width = Math.min(window.innerWidth, window.innerHeight); const fullQrCode = new QRCodeStyling(opts); - while (qr.firstChild) qr.removeChild(qr.lastChild); + while (qr && qr.firstChild) qr.removeChild(qr.lastChild); qrCode.append(qr); - while (fullQr.firstChild) fullQr.removeChild(fullQr.lastChild); + while (fullQr && fullQr.firstChild) fullQr.removeChild(fullQr.lastChild); fullQrCode.append(fullQr); + mask = false; }; </script> -<div bind:this={qr} on:click={toggle} class:hidden={full} /> +{#if mask} + <div class="absolute bg-white w-[300px] h-[300px] t-0 l-0 z-10" out:fade /> +{/if} +<div bind:this={qr} on:click={toggle} class:hidden={full} class="relative overflow-visible" /> <div bind:this={fullQr} on:click={toggle} class:hidden={!full} /> <style> diff --git a/src/components/Tip.svelte b/src/components/Tip.svelte index 83bf0dfa..093fef46 100644 --- a/src/components/Tip.svelte +++ b/src/components/Tip.svelte @@ -1,24 +1,15 @@ <script> + import { enhance } from '$app/forms'; import { Icon } from '$comp'; import { t } from '$lib/translations'; import { f, post, s } from '$lib/utils'; import { tick } from 'svelte'; import { goto } from '$app/navigation'; - export let amountFiat, - showCustomAmount, - showMobileTip, - tipPercent, - tipAmount, - amount, - currency, - tip, - prompt, - rate, - text, - username; + export let amountFiat, showMobileTip, tipPercent, tipAmount, amount, currency, tip, username; const tipAmounts = ['None', '10%', '15%', '20%']; + let showCustomAmount; let customInput; let customTipAmount; @@ -26,42 +17,17 @@ let apply = async () => { if (customTipAmount > 0) { tipPercent = (customTipAmount / amountFiat) * 100; - update(); showMobileTip = false; showCustomAmount = false; + update(); } }; - let update = async () => { - await tick(); - let { uuid } = await post(`/invoice`, { - amount: parseInt(amount + tip), - prompt, - rate, - tip, - text, - user: { username } - }); - - goto(`/invoice/${uuid}`); - }; - const handleCustomTipAmount = (e) => { tipPercent = 0; customTipAmount = e.target.value; }; - const handleMobileClose = () => { - tipPercent = 0; - if (customInput) { - customInput.value = ''; - } - customTipAmount = 0; - tipAmount = 0; - showMobileTip = false; - showCustomAmount = false; - }; - let timeout; const handleSlide = (e) => { customTipAmount = ''; @@ -71,7 +37,7 @@ tipPercent = e.target.value; clearTimeout(timeout); - timeout = setTimeout(update, 100); + timeout = setTimeout(update, 800); }; const handleTipButtonClick = (amount) => { @@ -88,6 +54,12 @@ showMobileTip = false; update(); }; + + let submit; + let update = async () => { + await tick(); + submit.click(); + }; </script> <div @@ -95,40 +67,34 @@ ? 'bottom-0' : '-top-full'} bg-white p-6 md:p-0 rounded-t-3xl md:rounded-none left-0 md:static text-center space-y-5" > - <div class="flex justify-end items-center"> - <button class="block md:hidden bg-primary rounded-full p-2" on:click={handleMobileClose} - ><Icon icon="close" /></button - > - <button - class="hidden {showCustomAmount ? 'md:block' : ''}" - on:click={() => (showCustomAmount = false)} - ><Icon icon="close" style="hover:opacity-80" /></button - > - </div> - <h1 class="hidden md:block text-4xl font-semibold">{$t('invoice.addTipq')}</h1> - {#if !showCustomAmount} - <div> - <span class="font-semibold mr-1">{f(tipAmount, currency)}</span><span - class="text-secondary font-semibold text-sm">{`(${s(tip)} SAT)`}</span - > - <span class="block text-secondary text-sm">{Math.round(tipPercent)}%</span> - </div> + <form method="POST" use:enhance> + <input type="hidden" name="amount" value={amount} /> + <input type="hidden" name="tip" value={tip} /> + <input type="hidden" name="username" value={username} /> + <input type="hidden" name="prompt" value="true" /> - <input - id="slider" - type="range" - min="0" - max="100" - value={tipPercent} - class="px-2 py-0" - on:input={handleSlide} - on:change={() => (showMobileTip = false)} - /> - {/if} - <div> + <h1 class="hidden md:block text-4xl font-semibold">{$t('invoice.addTipq')}</h1> {#if !showCustomAmount} + <div> + <span class="font-semibold mr-1">{f(tipAmount, currency)}</span><span + class="text-secondary font-semibold text-sm">{`(${s(tip)} SAT)`}</span + > + <span class="block text-secondary text-sm">{Math.round(tipPercent)}%</span> + </div> + + <input + id="slider" + type="range" + min="0" + max="100" + value={tipPercent} + class="px-2 py-0 mb-4" + on:input={handleSlide} + on:change={() => (showMobileTip = false)} + /> {#each tipAmounts as amount} <button + type="button" class="bg-black text-white md:text-black md:bg-primary md:hover:bg-black md:hover:text-white w-16 md:w-20 py-3 m-1 rounded-2xl font-semibold {customTipAmount ? '' : Math.round(tipPercent) === parseInt(amount.slice(0, 2)) || @@ -138,8 +104,21 @@ on:click={() => handleTipButtonClick(amount)}>{amount}</button > {/each} + + <div> + <button + type="button" + class="w-full md:w-auto mt-2 bg-black md:bg-primary text-white md:text-black md:hover:bg-black md:hover:text-white font-semibold py-3 px-7 rounded-2xl" + on:click={() => (showCustomAmount = true)}>Custom amount</button + > + </div> {/if} - {#if showCustomAmount} + + <button type="submit" bind:this={submit} /> + </form> + + {#if showCustomAmount} + <form on:submit|preventDefault={apply}> <div class="relative"> <span class="absolute top-[18px] left-5 font-semibold {!customTipAmount @@ -149,28 +128,22 @@ <input bind:this={customInput} type="number" + step="0.01" on:input={(e) => handleCustomTipAmount(e)} class="pl-10" placeholder="Other" /> <button + type="submit" class="w-full mt-2 bg-black text-white font-semibold py-3 px-7 rounded-2xl {!customTipAmount ? 'opacity-50' : 'opacity-100 hover:opacity-80'}" - disabled={!customTipAmount} - on:click={apply}>Apply</button + disabled={!customTipAmount}>Apply</button > <!-- found missing translation ---> </div> - {:else} - <div> - <button - class="w-full md:w-auto mt-2 bg-black md:bg-primary text-white md:text-black md:hover:bg-black md:hover:text-white font-semibold py-3 px-7 rounded-2xl" - on:click={() => (showCustomAmount = true)}>Custom amount</button - > - </div> - {/if} - </div> + </form> + {/if} </div> <div diff --git a/src/lib/invoice.js b/src/lib/invoice.js new file mode 100644 index 00000000..a0aa8402 --- /dev/null +++ b/src/lib/invoice.js @@ -0,0 +1,20 @@ +import { auth, get, post } from '$lib/utils'; +import { redirect } from '@sveltejs/kit'; + +export default async ({ cookies, request }) => { + let form = await request.formData(); + + let invoice = { + amount: parseInt(form.get('amount')), + tip: parseInt(form.get('tip')), + network: 'lightning', + prompt: form.get('prompt') === 'true', + rate: await get('/rate') + }; + + let user = { username: form.get('username') }; + + let { uuid } = await post('/invoice', { invoice, user }, auth(cookies)); + + throw redirect(307, `/invoice/${uuid}`); +}; diff --git a/src/lib/socket.js b/src/lib/socket.js index 6317595b..a419faeb 100644 --- a/src/lib/socket.js +++ b/src/lib/socket.js @@ -19,12 +19,16 @@ export const messages = (data) => ({ }, payment() { - if (data.invoice) invoices.set({ ...get(invoices), [data.invoice.uuid]: data.invoice }); + let { amount, invoice } = data; + if (invoice) { + console.log('updating invoice', invoice.uuid, invoice.received, invoice.amount); + invoices.set({ ...get(invoices), [invoice.uuid]: invoice }); + } newPayment.set(true); - if (data.amount > 0) { - success(`Received ${data.amount} sats!`); + if (amount > 0) { + success(`Received ${amount} sats!`); } else { - success(`Sent ${-data.amount} sats!`); + success(`Sent ${-amount} sats!`); } }, @@ -37,7 +41,6 @@ const maxReconnectDelay = 16000; let currentReconnectDelay = initialReconnectDelay; export function connect(t) { - console.log('CONNECT'); token = t; clearInterval(interval); diff --git a/src/locales/en.json b/src/locales/en.json index 1d1a9749..86c1085b 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -96,7 +96,7 @@ "addTip": "Add a tip", "addTipq": "Add a tip?", "done": "Done", - "paymentSuccessful": "Payment Successful!", + "paymentSuccessful": "Payment received!", "invoice": "Invoice", "total": "Total", "tip": "Tip" diff --git a/src/routes/[username]/receive/+page.server.js b/src/routes/[username]/receive/+page.server.js index 60e94f0e..1068f273 100644 --- a/src/routes/[username]/receive/+page.server.js +++ b/src/routes/[username]/receive/+page.server.js @@ -1,21 +1,5 @@ -import { auth, get, post } from '$lib/utils'; -import { redirect } from '@sveltejs/kit'; +import invoice from '$lib/invoice'; export const actions = { - default: async ({ cookies, request }) => { - let form = await request.formData(); - - let invoice = { - amount: parseInt(form.get('amount')), - network: 'lightning', - prompt: form.get('prompt') === 'true', - rate: await get('/rate') - }; - - let user = { username: form.get('username') }; - - let { uuid } = await post('/invoice', { invoice, user }, auth(cookies)); - - throw redirect(307, `/invoice/${uuid}`); - } + default: invoice }; diff --git a/src/routes/invoice/[id]/+page.server.js b/src/routes/invoice/[id]/+page.server.js new file mode 100644 index 00000000..1068f273 --- /dev/null +++ b/src/routes/invoice/[id]/+page.server.js @@ -0,0 +1,5 @@ +import invoice from '$lib/invoice'; + +export const actions = { + default: invoice +}; diff --git a/src/routes/invoice/[id]/+page.svelte b/src/routes/invoice/[id]/+page.svelte index 9d140bd5..04a31813 100644 --- a/src/routes/invoice/[id]/+page.svelte +++ b/src/routes/invoice/[id]/+page.svelte @@ -19,7 +19,6 @@ user: { username, currency } } = invoice; - let showCustomAmount = false; let showMobileTip = false; let qr; @@ -39,15 +38,13 @@ user: { username, currency } } = invoice); - amount -= tip; - tipPercent = (tip / amount) * 100; }; $: tip = Math.round((amount / 100) * tipPercent); $invoices[id] = { amount, id, rate, received, text, tip, username }; - $: $invoices[id]?.received >= $invoices[id]?.amount && goto(`/invoice/${id}/paid`); + $: browser && $invoices[id]?.received >= $invoices[id]?.amount && goto(`/invoice/${id}/paid`); $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); @@ -73,15 +70,11 @@ {#if invoice.prompt} <Tip bind:amountFiat - bind:showCustomAmount bind:showMobileTip bind:tipPercent bind:tipAmount bind:amount bind:tip - bind:rate - bind:prompt - bind:text bind:currency bind:username /> diff --git a/src/routes/invoice/[id]/paid/+page.svelte b/src/routes/invoice/[id]/paid/+page.svelte index 456ee3ba..1b212a92 100644 --- a/src/routes/invoice/[id]/paid/+page.svelte +++ b/src/routes/invoice/[id]/paid/+page.svelte @@ -1,15 +1,19 @@ <script> + import { scale } from 'svelte/transition'; + import { onMount } from 'svelte'; + import { quintOut } from 'svelte/easing'; + import { Icon } from '$comp'; import { toast } from '@zerodevx/svelte-toast'; import { browser } from '$app/environment'; import { t } from '$lib/translations'; import { f, s, sats } from '$lib/utils'; - import { LottiePlayer } from '@lottiefiles/svelte-lottie-player'; import { goto } from '$app/navigation'; import { invoices } from '$lib/store'; export let data; let { invoice } = data; let { amount, rate } = invoice; + let yeah; toast.pop(0); @@ -21,19 +25,10 @@ }; </script> -<div class="text-center mt-20 md:mt-0"> - {#if browser} - <div class="w-full mx-auto max-w-xl"> - <LottiePlayer - src="/lottie/success.json" - autoplay={true} - loop={true} - controls={false} - renderer="svg" - background="transparent" - /> - </div> - {/if} +<div class="container px-4 text-center"> + <div class="flex w-full py-10" in:scale={{ start: 0.5 }}> + <Icon icon="check" style="mx-auto" /> + </div> <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('invoice.paymentSuccessful')}</h1> <h2 class="text-2xl md:text-3xl font-semibold"> {f(amountFiat, invoice.currency)} diff --git a/static/icons/check.svg b/static/icons/check.svg index 6bc4c06e..f29f8718 100644 --- a/static/icons/check.svg +++ b/static/icons/check.svg @@ -1,42 +1,9 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - width="405.272px" height="405.272px" viewBox="0 0 405.272 405.272" style="enable-background:new 0 0 405.272 405.272;" + width="405.272px" height="405.272px" viewBox="0 0 405.272 405.272" style="fill: #7ACC8F;" xml:space="preserve"> <g> <path d="M393.401,124.425L179.603,338.208c-15.832,15.835-41.514,15.835-57.361,0L11.878,227.836 c-15.838-15.835-15.838-41.52,0-57.358c15.841-15.841,41.521-15.841,57.355-0.006l81.698,81.699L336.037,67.064 c15.841-15.841,41.523-15.829,57.358,0C409.23,82.902,409.23,108.578,393.401,124.425z"/> </g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> -<g> -</g> </svg> |
