diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Numpad.svelte | 18 | ||||
| -rw-r--r-- | src/components/Qr.svelte | 2 | ||||
| -rw-r--r-- | src/lib/utils.js | 5 | ||||
| -rw-r--r-- | src/locales/en.json | 8 | ||||
| -rw-r--r-- | src/routes/+error.svelte | 24 | ||||
| -rw-r--r-- | src/routes/+layout.server.js | 1 | ||||
| -rw-r--r-- | src/routes/[username]/dashboard/+page.svelte | 54 | ||||
| -rw-r--r-- | src/routes/[username]/transactions/[...page]/+page.svelte | 4 | ||||
| -rw-r--r-- | src/routes/send/+page.server.js | 17 | ||||
| -rw-r--r-- | src/routes/send/+page.svelte | 17 | ||||
| -rw-r--r-- | src/routes/send/user/[username]/+page.server.js | 23 | ||||
| -rw-r--r-- | src/routes/send/user/[username]/+page.svelte | 71 | ||||
| -rw-r--r-- | src/routes/sent/+page.svelte | 2 |
13 files changed, 178 insertions, 68 deletions
diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte index 9de4a0dc..f7a18aad 100644 --- a/src/components/Numpad.svelte +++ b/src/components/Numpad.svelte @@ -4,10 +4,8 @@ import { f, s, post, warning, sats } from '$lib/utils'; import { t } from '$lib/translations'; - export let amount, currency; + export let amount, amountFiat = 0, currency, fiat = true; - let useFiat = true; - let amountFiat = 0; let amountSats = 0; let loading = false; @@ -28,7 +26,7 @@ KRW: '₩' }[currency] || ''; - $: amount = parseInt(useFiat ? Math.round(amountFiat / ($selectedRate / sats)) : amountSats); + $: amount = parseInt(fiat ? Math.round(amountFiat / ($selectedRate / sats)) : amountSats); $: amountSatsFormatted = s(amountSats); @@ -39,7 +37,7 @@ const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<']; const handleInput = (value) => { - if (useFiat) { + if (fiat) { if (amountFiat === 0 && value !== '.' && value !== '<' && value !== '0') { amountFiat = value; } else if ((amountFiat === 0 || amountFiat === '0') && value === '0') { @@ -89,17 +87,17 @@ <div class="space-y-5"> <div class="text-center"> <div class="text-5xl md:text-6xl font-semibold tracking-widest mb-1"> - {useFiat ? `${symbol}${amountFiat}` : amountSatsFormatted}<span - class="tracking-normal text-base font-normal">{useFiat ? currency : 'SAT'}</span + {fiat ? `${symbol}${amountFiat}` : amountSatsFormatted}<span + class="tracking-normal text-base font-normal">{fiat ? currency : 'SAT'}</span > </div> <span class="text-secondary mr-1" - >{useFiat ? `${amountSatsConverted} SAT` : amountFiatConverted}</span + >{fiat ? `${amountSatsConverted} SAT` : amountFiatConverted}</span > <button type="button" on:click={() => { - if (useFiat) { + if (fiat) { amountSats = parseInt((amountFiat / ($selectedRate / sats)).toFixed(0)); } else { amountFiat = @@ -107,7 +105,7 @@ ? (amountSats * ($selectedRate / sats)).toFixed(2) : 0; } - useFiat = !useFiat; + fiat = !fiat; }}><Icon icon="swap" style="inline hover:opacity-80" /></button > </div> diff --git a/src/components/Qr.svelte b/src/components/Qr.svelte index 3456b607..0ae028b9 100644 --- a/src/components/Qr.svelte +++ b/src/components/Qr.svelte @@ -1,5 +1,5 @@ <script> - import { fly, fade } from 'svelte/transition'; + import { fade } from 'svelte/transition'; import screenfull from 'screenfull'; import { browser } from '$app/environment'; import { onMount, tick } from 'svelte'; diff --git a/src/lib/utils.js b/src/lib/utils.js index 7a988469..baf2176d 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -119,8 +119,5 @@ export const s = (s) => new Intl.NumberFormat('en-US', { maximumFractionDigits: export const sats = 100000000; -export const back = () => { - browser && history.go(-1); -}; - +export const back = () => browser && history.go(-1); export const focus = (el) => setTimeout(() => el.focus()); diff --git a/src/locales/en.json b/src/locales/en.json index 86c1085b..e9af5557 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -44,7 +44,7 @@ }, "locations": { "header": "Locations", - "description": "These are businesses that are accepting bitcoin with Coinos. If you are using our application, please <a href=\"mailto:[email protected]\" class=\"underline underline-offset-4 hover:opacity-80\">let us know!</a>" + "description": "Here are some businesses that are accepting bitcoin with Coinos. If you are using our application, please <a href=\"mailto:[email protected]\" class=\"underline underline-offset-4 hover:opacity-80\">let us know!</a>" } }, "error": { @@ -121,7 +121,7 @@ "info2": { "title": "Simple to use", "description1": "Just enter an amount in your local currency, share the QR code and you’re done.", - "description2": "Coinos gives you free access to use our hosted bitcoin and lightning nodes, eliminating the need to understand how bitcoin or lightning works. We do all the heavy lifting so you can focus on your business.", + "description2": "We do all the heavy lifting so you can focus on your business.", "description3": "You always have the option of taking custody of your funds by withdrawing instantly at any time." }, "info3": { @@ -172,8 +172,8 @@ "fetchingRate": "fetching rate...", "optionalNote": "Note (Optional)", "send": "Send", - "receive": "Receive a Payment", - "withdraw": "Withdraw Funds" + "receive": "Receive", + "withdraw": "Send" }, "receive": { "lessThan1BTCWarning": "Please enter an amount less than 1 bitcoin.", diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index 58a3144d..e5556b44 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -2,22 +2,26 @@ import { page } from '$app/stores'; import { Icon, PageNotFound } from '$comp'; import { t } from '$lib/translations'; + + export let data; + let { user } = data; </script> {#if $page.error.message.includes('not found') || $page.status === 404} <PageNotFound /> {:else} - <div class="flex justify-center items-center mt-20"> - <div class="space-y-5 text-center"> - <a href="/"> - <Icon icon="logo" style="mx-auto" /> - </a> + <div class="container px-4 max-w-md mx-auto mt-20 text-center"> + + <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8"> + {$t('error.header')} + </h1> - <Icon icon="error" style="mx-auto w-56" /> + <p class="px-1 break-all mb-8">{$page.error.message}</p> - <h1 class="font-bold text-5xl">{$t('error.header')}</h1> - <p class="px-1 w-full md:w-96 break-all font-bold">{$page.error.message}</p> - <p>{$t('error.message')}</p> - </div> + <a href={`/${user.username}/dashboard`}> + <button class="rounded-full bg-black text-white py-2 px-5 font-bold hover:opacity-80 mb-2" + >Go Home</button + > + </a> </div> {/if} diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js index e9b01593..84e5ce5c 100644 --- a/src/routes/+layout.server.js +++ b/src/routes/+layout.server.js @@ -18,7 +18,6 @@ export async function load({ cookies, request, url, params }) { if (token && token !== 'undefined') { try { - console.log("GETTING USER"); user = await get('/me', auth(cookies)); } catch (e) { throw redirect(307, '/logout'); diff --git a/src/routes/[username]/dashboard/+page.svelte b/src/routes/[username]/dashboard/+page.svelte index 8d77b699..05f821ec 100644 --- a/src/routes/[username]/dashboard/+page.svelte +++ b/src/routes/[username]/dashboard/+page.svelte @@ -51,37 +51,37 @@ {/if} </div> -<div class="px-3 md:px-0 flex justify-center items-center mt-10 lg:mt-0 mb-20"> - <div> - <span class="text-3xl font-bold block mb-1" - >{$selectedRate - ? f(accountBalanceFiat, user.currency) - : $t('user.dashboard.fetchingRate')}</span - > +<div class="container px-4 max-w-md mx-auto"> + <h1 class="text-center text-3xl md:text-4xl font-semibold mb-10"> + Dashboard + </h1> - <span class="text-secondary text-xl block"> - {accountBalanceSats} SAT - </span> + <div class="text-5xl font-bold mb-2"> + {$selectedRate ? f(accountBalanceFiat, user.currency) : $t('user.dashboard.fetchingRate')} + </div> + + <div class="text-secondary text-2xl"> + {accountBalanceSats} SAT + </div> - <div class="grid sm:grid-cols-2 gap-2 mt-8"> - <a href={`/${user.username}/receive`}> + <div class="grid sm:grid-cols-2 gap-2 mt-8"> + <a href={`/${user.username}/receive`}> + <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" + >{$t('user.dashboard.receive')}</button + > + </a> + {#if user.account.balance > 0} + <a href="/send"> + <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" + >{$t('user.dashboard.withdraw')}</button + > + </a> + {:else} + <a href={`/${user.username}/settings`}> <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" - >{$t('user.dashboard.receive')}</button + >Setup Account</button > </a> - {#if user.account.balance > 0} - <a href="/send"> - <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" - >{$t('user.dashboard.withdraw')}</button - > - </a> - {:else} - <a href={`/${user.username}/settings`}> - <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" - >Setup Account</button - > - </a> - {/if} - </div> + {/if} </div> </div> diff --git a/src/routes/[username]/transactions/[...page]/+page.svelte b/src/routes/[username]/transactions/[...page]/+page.svelte index 223418a3..18990fa3 100644 --- a/src/routes/[username]/transactions/[...page]/+page.svelte +++ b/src/routes/[username]/transactions/[...page]/+page.svelte @@ -23,9 +23,9 @@ <div class="flex flex-wrap justify-end mb-8"> {#if pages.length > 1} {#each pages as _, i} - <a href={`/${user.username}/transactions/${i + 1}`} class:active={page === i + 1}> + <a class="mr-1 last:mr-0" href={`/${user.username}/transactions/${i + 1}`} class:active={page === i + 1}> <div - class="border py-2 px-4 rounded-full border-2 w-12 h-12 hover:opacity-80 mr-1 text-center my-auto" + class="border py-2 px-4 rounded-full border-2 w-12 h-12 hover:opacity-80 text-center my-auto" > {i + 1} </div> diff --git a/src/routes/send/+page.server.js b/src/routes/send/+page.server.js index 4108bcb5..c8edb1cc 100644 --- a/src/routes/send/+page.server.js +++ b/src/routes/send/+page.server.js @@ -16,7 +16,14 @@ export const actions = { // bitcoin if (validate(t)) { - throw redirect(303, `/send/bitcoin/${t}`); + let user; + try { + ({ user } = await get(`/invoice/${t}`)); + } catch (e) { + throw redirect(303, `/send/bitcoin/${t}`); + } + + if (user) throw redirect(303, `/send/user/${user.username}`); } // ln address @@ -28,7 +35,13 @@ export const actions = { } // user + let user; + try { + user = await get(`/users/${t}`); + } catch (e) {} + + if (user) throw redirect(303, `/send/user/${t}`); - return invalid(403, { error: 'Failed to parse destination' }); + return invalid(403, { error: 'Failed to recognize input' }); } }; diff --git a/src/routes/send/+page.svelte b/src/routes/send/+page.svelte index 8a695ac6..87d06e35 100644 --- a/src/routes/send/+page.svelte +++ b/src/routes/send/+page.svelte @@ -1,4 +1,5 @@ <script> + import { fly } from 'svelte/transition'; import { enhance } from '$app/forms'; import { onMount } from 'svelte'; import { browser } from '$app/environment'; @@ -9,26 +10,29 @@ export let form; let el; - let placeholder = 'Address, Invoice, Username'; + let placeholder = 'Address, Invoice or Username'; let text = placeholder; let focus = () => text === placeholder && (text = ''); - let keypress = (e) => e.key === 'Enter' && e.preventDefault() && el.submit(); + let keypress = (e) => e.key === 'Enter' && (e.preventDefault() || el.click()); let paste = async () => { text = await navigator.clipboard.readText(); }; - - onMount(() => form?.error && failure(form.error)); </script> <button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}> <Icon icon="arrow-left" style="w-10" /> </button> -<form method="POST" class="container px-4 mt-20 max-w-xl mx-auto" bind:this={el} use:enhance> +<form method="POST" class="container px-4 mt-20 max-w-xl mx-auto" use:enhance> + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} <div class="mb-2"> - <label for="invoice" class="font-bold mb-1 block">Destination</label> + <label for="invoice" class="font-bold mb-1 block">To</label> <input type="hidden" name="text" bind:value={text} /> <div @@ -65,6 +69,7 @@ </button> <button + bind:this={el} type="submit" class="{!text ? 'opacity-50' diff --git a/src/routes/send/user/[username]/+page.server.js b/src/routes/send/user/[username]/+page.server.js new file mode 100644 index 00000000..37a8d594 --- /dev/null +++ b/src/routes/send/user/[username]/+page.server.js @@ -0,0 +1,23 @@ +import { error, invalid, redirect } from '@sveltejs/kit'; +import { btc as asset, auth, get, post } from '$lib/utils'; + +export async function load({ params, parent }) { + let { user } = await parent(); + let recipient = await get(`/users/${params.username}`); + if (recipient.username === user.username) throw error(500, { message: 'Cannot send to self' }); + return { recipient }; +} + +export const actions = { + default: async ({ cookies, request }) => { + let body = Object.fromEntries(await request.formData()); + let { amount, confirmed } = body; + + if (!confirmed) { + return invalid(403, { amount, confirm: true }); + } + + await post('/send', body, auth(cookies)); + throw redirect(307, '/sent'); + } +}; diff --git a/src/routes/send/user/[username]/+page.svelte b/src/routes/send/user/[username]/+page.svelte new file mode 100644 index 00000000..fa159538 --- /dev/null +++ b/src/routes/send/user/[username]/+page.svelte @@ -0,0 +1,71 @@ +<script> + import { selectedRate } from '$lib/store'; + import { enhance } from '$app/forms'; + import { Icon, Numpad, Spinner } from '$comp'; + import { page } from '$app/stores'; + import { back, f, s, sats } from '$lib/utils'; + export let data; + export let form; + + let { recipient, user } = data; + let { currency } = user; + + let amount = form?.amount || data.amount; + let a, + af, + amountFiat, + fiat = true; + + let setAmount = () => { + console.log('setting', a, af); + amount = a; + amountFiat = af; + }; + + let handleBack = () => { + if (amount) amount = undefined; + else back(); + }; +</script> + +<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={handleBack}> + <Icon icon="arrow-left" style="w-10" /> +</button> + +<div class="container px-4 mt-20 max-w-xl mx-auto"> + {#if amount} + <div class="text-center mb-8"> + <h1 class="text-xl md:text-2xl text-secondary mb-2">Sending</h1> + <p class="text-6xl break-words mb-4">{fiat ? f(amountFiat, currency) : `${s(a)} sats`}</p> + + <h1 class="text-xl md:text-2xl text-secondary mb-2">To</h1> + <p class="text-6xl break-words">{recipient.username}</p> + </div> + {:else} + <Numpad bind:amount={a} bind:amountFiat={af} {currency} bind:fiat /> + {/if} + + <form method="POST" use:enhance> + <input name="amount" value={amount} type="hidden" /> + <input name="confirmed" value={form?.confirm} type="hidden" /> + + <div class="flex w-full"> + {#if amount} + <button + type="submit" + class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" + > + Send + </button> + {:else} + <button + type="button" + class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" + on:click={setAmount} + > + Next + </button> + {/if} + </div> + </form> +</div> diff --git a/src/routes/sent/+page.svelte b/src/routes/sent/+page.svelte index 95bce839..c70aea39 100644 --- a/src/routes/sent/+page.svelte +++ b/src/routes/sent/+page.svelte @@ -13,7 +13,7 @@ <div class="flex w-full py-20"> <Icon icon="check" style="mx-auto" /> </div> - <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('invoice.paymentSuccessful')}</h1> + <h1 class="text-3xl md:text-4xl font-bold mb-6">Sent!</h1> <a href={`/${user.username}/transactions`}> <button class="bg-black text-white rounded-2xl w-20 py-3 font-bold hover:opacity-80"> {$t('invoice.done')} |
