diff options
| author | Adam Soltys <[email protected]> | 2023-03-17 20:28:00 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-03-17 20:28:00 -0700 |
| commit | 93f23786af35bbe932bc849c8a301d5af1b82d58 (patch) | |
| tree | d7d6d408fb34ec1892b67aa56398cffe726d0eab /src/routes/(app) | |
| parent | c4757b998cd9be2db18ac1805557bdf175fc86c3 (diff) | |
| parent | cdc3a2677c8728af27084024daba288153c2bd52 (diff) | |
| download | coinos-ui-93f23786af35bbe932bc849c8a301d5af1b82d58.tar.gz coinos-ui-93f23786af35bbe932bc849c8a301d5af1b82d58.zip | |
Merge branch 'master' into hashme
Diffstat (limited to 'src/routes/(app)')
34 files changed, 296 insertions, 189 deletions
diff --git a/src/routes/(app)/+layout.server.js b/src/routes/(app)/+layout.server.js index ef278744..e80e1e64 100644 --- a/src/routes/(app)/+layout.server.js +++ b/src/routes/(app)/+layout.server.js @@ -30,6 +30,9 @@ export async function load({ cookies, request, url, params }) { throw redirect(307, '/login'); } + if (user && !user.pubkey && !pathname.includes('generate')) + throw redirect(307, `/${user.username}/generate`); + try { rate = await get('/rate'); rates = await get('/rates'); diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 45469bdb..0dcdc1b2 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -25,7 +25,6 @@ }; $: $selectedRate = r * (rates[u?.currency || 'USD'] / rates.USD); - $: $selectedRate = $rate * (rates[u?.currency || 'USD'] / rates.USD); onMount(() => { let localStorageLocale = localStorage.getItem(localeLocalStorageKey); diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index 6eb2a850..bbb2379e 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -4,7 +4,6 @@ import { Icon } from '$comp'; import { t } from '$lib/translations'; import { sign, send } from '$lib/nostr'; - import { v4 } from 'uuid'; export let data; let events, user, subject, src, text; @@ -60,6 +59,9 @@ t++; }, 10); }; + + let hideBio = true; + let toggleBio = () => (hideBio = false); </script> <div class="container mx-auto w-full px-4 mb-4 flex flex-wrap lg:flex-nowrap"> @@ -67,7 +69,11 @@ <div class="w-[240px] lg:absolute space-y-5 left-20 mx-auto lg:mr-10 mb-10"> <h1 class="text-3xl font-bold text-center mx-auto">{display || username}</h1> - <div class="text-secondary mx-auto text-center lg:text-left lg:mx-0"> + <div + class="text-secondary mx-auto text-center lg:text-left lg:mx-0" + class:line-clamp-3={hideBio} + on:click={toggleBio} + > {subject.address && subject.address !== 'null' ? subject.address : ''} </div> diff --git a/src/routes/(app)/[username]/(profile)/+page.server.js b/src/routes/(app)/[username]/(profile)/+page.server.js index d6cf3984..e37db1fe 100644 --- a/src/routes/(app)/[username]/(profile)/+page.server.js +++ b/src/routes/(app)/[username]/(profile)/+page.server.js @@ -5,31 +5,31 @@ export async function load({ cookies, params, parent, url }) { let { pubkey } = subject; let { since = 0 } = params; - let messages, invoices, sent, received; - messages = invoices = sent = received = []; + let messages, invoices, sent, received, notes; + messages = invoices = sent = received = notes = []; + + if (pubkey) { + if (user) { + try { + messages = await get(`/${user.pubkey}/${since}/messages`); + messages = messages.sort((a, b) => b.created_at - a.created_at); + } catch (e) { + console.log(`failed to fetch nostr messages`, e); + } + + ({ invoices, sent, received } = await get('/requests', auth(cookies))); + } - if (user) { try { - messages = await get(`/${user.pubkey}/${since}/messages`); - messages = messages.sort((a, b) => b.created_at - a.created_at); + notes = await get(`/${pubkey}/notes`); } catch (e) { - console.log(`failed to fetch nostr messages`, e); + console.log(`failed to fetch nostr notes for ${pubkey}`, e); } - ({ invoices, sent, received } = await get('/requests', auth(cookies))); + notes.map((e) => { + e.seen = e.created_at; + }); } - let notes = []; - - try { - notes = await get(`/${pubkey}/notes`); - } catch (e) { - console.log(`failed to fetch nostr notes for ${pubkey}`, e); - } - - notes.map((e) => { - e.seen = e.created_at; - }); - return { invoices, messages, notes, sent, received }; } diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index 168556e4..09335e9c 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -36,7 +36,7 @@ let initialize = async (p) => { ready = false; if (!p) return; - while (latest.length < 3 && i < messages.length) { + while (i < messages.length) { let event = messages[i]; let k = event.author.id === user.id ? event.recipient.pubkey : event.author.pubkey; if (!keys.has(k)) { diff --git a/src/routes/(app)/[username]/(profile)/followers/+page.svelte b/src/routes/(app)/[username]/(profile)/followers/+page.svelte index 77b337b6..56b3ba16 100644 --- a/src/routes/(app)/[username]/(profile)/followers/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/followers/+page.svelte @@ -1,4 +1,5 @@ <script> + import { t } from '$lib/translations'; import { Avatar } from '$comp'; import { browser } from '$app/environment'; import VirtualScroll from 'svelte-virtual-scroll-list'; @@ -14,7 +15,9 @@ <svelte:window bind:innerWidth={w} /> <div class="px-3 md:px-0 w-full md:w-[400px] mx-auto space-y-8"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold">Followers</h1> + <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> + {$t('user.followers')} + </h1> {#if browser} {#if followers.length} diff --git a/src/routes/(app)/[username]/(profile)/follows/+page.svelte b/src/routes/(app)/[username]/(profile)/follows/+page.svelte index 78566fc4..b238c3a7 100644 --- a/src/routes/(app)/[username]/(profile)/follows/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/follows/+page.svelte @@ -1,4 +1,5 @@ <script> + import { t } from '$lib/translations'; import { Avatar } from '$comp'; import { browser } from '$app/environment'; import VirtualScroll from 'svelte-virtual-scroll-list'; @@ -13,7 +14,9 @@ <svelte:window bind:innerWidth={w} /> <div class="px-3 md:px-0 w-full md:w-[400px] mx-auto space-y-8"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold">Following</h1> + <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> + {$t('user.following')} + </h1> {#if browser} {#if follows.length} diff --git a/src/routes/(app)/[username]/dashboard/+page.svelte b/src/routes/(app)/[username]/dashboard/+page.svelte index 499034e6..d8761ea9 100644 --- a/src/routes/(app)/[username]/dashboard/+page.svelte +++ b/src/routes/(app)/[username]/dashboard/+page.svelte @@ -7,7 +7,6 @@ import { goto } from '$app/navigation'; import { t } from '$lib/translations'; import { events } from '$lib/store'; - import { v4 } from 'uuid'; export let data; $: ({ invoices, requests } = data); diff --git a/src/routes/(app)/[username]/invoice/+server.js b/src/routes/(app)/[username]/invoice/+server.js index 1321739e..461d380c 100644 --- a/src/routes/(app)/[username]/invoice/+server.js +++ b/src/routes/(app)/[username]/invoice/+server.js @@ -1,5 +1,7 @@ import { auth, post } from '$lib/utils'; import { json } from '@sveltejs/kit'; -export let POST = async ({ cookies: c, request: r }) => - json(await post('/invoice', await r.json(), auth(c))); +export let POST = async ({ cookies: c, request: r }) => { + let j = await r.json(); + return json(await post('/invoice', j, auth(c))); +}; diff --git a/src/routes/(app)/[username]/invoice/[hash]/+layout.server.js b/src/routes/(app)/[username]/invoice/[hash]/+layout.server.js index b5323d3f..7cf87e14 100644 --- a/src/routes/(app)/[username]/invoice/[hash]/+layout.server.js +++ b/src/routes/(app)/[username]/invoice/[hash]/+layout.server.js @@ -19,7 +19,7 @@ export async function load({ depends, params, url, parent }) { if (paid && !url.pathname.endsWith('paid')) throw redirect(307, `/${params.username}/invoice/${hash}/paid`); - let sm = Qr.drawImg(invoice.text, { size: 300 }); + let sm = Qr.drawImg(invoice.text || '', { size: 300 }); return { hash, invoice, sm, lg: sm }; } diff --git a/src/routes/(app)/[username]/invoice/[hash]/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/+page.svelte index 2ff92687..fff2b22c 100644 --- a/src/routes/(app)/[username]/invoice/[hash]/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[hash]/+page.svelte @@ -7,7 +7,6 @@ import { last } from '$lib/store'; import { Avatar, Icon, Heart, Image } from '$comp'; import { t } from '$lib/translations'; - import screenfull from 'screenfull'; import { goto, invalidate } from '$app/navigation'; export let data; @@ -67,14 +66,6 @@ $: link = type === 'bitcoin' ? text : `lightning:${text}`; $: txt = type === 'bitcoin' ? hash : text; - let full; - let toggle = () => { - screenfull.toggle(qr); - full = !full; - if (full) src = lg; - else src = sm; - }; - let toggleType = async () => { invoice.type = invoice.type === types.lightning ? types.bitcoin : types.lightning; ({ hash } = await post(`/${username}/invoice`, { @@ -111,21 +102,18 @@ <div class="my-auto">Bitcoin</div> </button> </div> - <div class="relative flex"> - <div class="flex mx-auto w-[360px] h-[360px]"> - <img - {src} - class:p-4={full} - class="w-[300px] h-[300px] mx-auto z-10 mt-[20px]" - bind:this={qr} - on:click={toggle} - on:keydown={toggle} - alt={txt} - /> - </div> - <div - class="absolute m-auto left-0 right-0 w-[340px] h-[340px] rounded-full bg-gradient-to-r from-[#F2F6FC] to-[#E1E3FF] z-0" - /> + + <div> + <a href={invoice.type === 'bitcoin' ? invoice.text : 'lightning:' + invoice.text}> + <div class="relative flex"> + <div class="flex mx-auto w-[360px] h-[360px]"> + <img {src} class="w-[300px] h-[300px] mx-auto z-10 mt-[20px]" bind:this={qr} alt={txt} /> + </div> + <div + class="absolute m-auto left-0 right-0 w-[340px] h-[340px] rounded-full bg-gradient-to-r from-[#F2F6FC] to-[#E1E3FF] z-0" + /> + </div> + </a> </div> {#if amount > 0} diff --git a/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte index 3a281728..4d7aae51 100644 --- a/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte @@ -21,7 +21,7 @@ {#if received} <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(fiat(received - tip, rate), currency)} + {f(fiat(received, rate), currency)} {#if tip} <span class="text-lg"> + {f(fiat(tip, rate), currency)} @@ -29,7 +29,7 @@ {/if} </h2> <h3 class="text-secondary md:text-lg mb-6 mt-1"> - ⚡️{s(received - tip)} + ⚡️{s(received)} {#if tip} <span class="text-lg"> @@ -48,7 +48,7 @@ {/if} </h2> <h3 class="text-secondary md:text-lg mb-6 mt-1"> - ⚡️{s(pending - tip)} + ⚡️{s(pending)} {#if tip} <span class="text-lg"> + ⚡️{s(tip)} diff --git a/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte index 296ef9c6..9d9021a6 100644 --- a/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte @@ -59,6 +59,7 @@ let { invoice, id, user } = data; let { amount, + hash, type, rate, received, @@ -79,6 +80,7 @@ ({ invoice, id } = data); ({ amount, + hash, type, rate, received, @@ -110,6 +112,8 @@ <input type="hidden" name="rate" value={rate} /> <input type="hidden" name="prompt" value="false" /> <input type="hidden" name="type" value={type} /> + <input type="hidden" name="hash" value={hash} /> + <input type="hidden" name="request_id" value={invoice.request?.id} /> <h1 class="text-4xl font-semibold my-8">{$t('invoice.addTipq')}</h1> diff --git a/src/routes/(app)/[username]/messages/+page.server.js b/src/routes/(app)/[username]/messages/+page.server.js index 7b651389..8347c184 100644 --- a/src/routes/(app)/[username]/messages/+page.server.js +++ b/src/routes/(app)/[username]/messages/+page.server.js @@ -11,6 +11,8 @@ export async function load({ params, parent, url }) { messages = messages .filter((m) => m.recipient.id === subject.id || m.author.id === subject.id) .sort((a, b) => a.created_at - b.created_at); + + if (user.id === subject.id) messages = messages.filter((m) => m.recipient.id === m.author.id); } catch (e) { console.log(`failed to fetch nostr messages`, e); } diff --git a/src/routes/(app)/[username]/messages/+page.svelte b/src/routes/(app)/[username]/messages/+page.svelte index 5de18c66..7a10d605 100644 --- a/src/routes/(app)/[username]/messages/+page.svelte +++ b/src/routes/(app)/[username]/messages/+page.svelte @@ -2,7 +2,7 @@ import { cubicInOut } from 'svelte/easing'; import { browser } from '$app/environment'; import { t } from '$lib/translations'; - import { format, parseISO } from 'date-fns'; + import { format } from 'date-fns'; import { scale, fade, fly } from 'svelte/transition'; import { enhance } from '$app/forms'; import { Avatar, Icon } from '$comp'; @@ -68,7 +68,6 @@ event.message = message; message = ''; - input.focus(); event.author = user; event.recipient = subject; @@ -92,9 +91,16 @@ message = ''; submitting = false; }; + + let keydown = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + submit(); + } + }; </script> -<div class="container max-w-xl mx-auto px-4"> +<div class="container max-w-xl mx-auto px-4 space-y-5"> <div class="h-[50vh] max-h-[50vh] overflow-y-scroll scrollbar-thin scrollbar-thumb-[#F2F6FC] scrollbar-track-white pr-8" bind:this={pane} @@ -133,22 +139,24 @@ {/each} </div> - <form method="POST" class="space-y-5 relative" on:submit|preventDefault={submit}> + <form + method="POST" + class="w-full border rounded-xl outline-none gap-4 flex p-0 pr-2" + on:submit|preventDefault={submit} + > <input type="hidden" name="requester_id" value={user.id} /> <input type="hidden" name="recipient" value={subject.username} /> - <button type="submit" class="absolute right-2 bottom-2"> - <Icon icon="send" style="w-10" /> - </button> - - <input + <div use:focus - name="message" - placeholder={$t('payments.sendMessage')} - class="w-full p-4 border rounded-xl outline-none" - bind:value={message} - bind:this={input} + contenteditable + class="grow break-all py-4 outline-none mt-0 pl-4" + bind:innerHTML={message} + on:keydown={keydown} /> + <button type="submit" class="my-auto shrink-0"> + <Icon icon="send" style="w-8" /> + </button> </form> </div> diff --git a/src/routes/(app)/[username]/payments/[...page]/+page.svelte b/src/routes/(app)/[username]/payments/[...page]/+page.svelte index aacba81e..c9cc5c40 100644 --- a/src/routes/(app)/[username]/payments/[...page]/+page.svelte +++ b/src/routes/(app)/[username]/payments/[...page]/+page.svelte @@ -1,7 +1,7 @@ <script> import { Avatar, Icon } from '$comp'; import { onMount } from 'svelte'; - import { format, parseISO } from 'date-fns'; + import { format } from 'date-fns'; import { newPayment, payments } from '$lib/store'; import { t } from '$lib/translations'; import { get, f, s, sat, sats } from '$lib/utils'; @@ -60,9 +60,11 @@ payments = payments.map((p) => ({ ...p, created: new Date(p.created), + total: p.amount + (p.tip || 0), amount_fiat: f((p.amount * p.rate) / sats, p.currency), fee_fiat: p.fee ? f((p.fee * p.rate) / sats, p.currency) : null, - tip_fiat: p.tip ? f((p.tip * p.rate) / sats, p.currency) : null + tip_fiat: p.tip ? f((p.tip * p.rate) / sats, p.currency) : null, + total_fiat: f(((p.amount + (p.tip || 0)) * p.rate) / sats, p.currency) })); let keys = [ @@ -72,11 +74,13 @@ 'rate', 'currency', 'amount', - 'fee', 'tip', + 'total', + 'fee', 'amount_fiat', - 'fee_fiat', - 'tip_fiat' + 'tip_fiat', + 'total_fiat', + 'fee_fiat' ]; let csv = @@ -143,24 +147,20 @@ <a href={`/payment/${p.id}`}> <div class="grid grid-cols-3 border-b h-24 hover:bg-gray-100 px-4"> <div class="whitespace-nowrap my-auto"> - <div class="font-bold"> - {f(p.amount * (p.rate / sats), p.currency)} - + <div class="font-bold" class:text-red-800={p.amount < 0}> + {f((Math.abs(p.amount) + (p.tip || 0)) * (p.rate / sats), p.currency)} {#if p.tip} - <span class="text-sm"> - +{f(p.tip * (p.rate / sats), p.currency)} + <span class="text-xs text-secondary"> + {f(Math.abs(p.amount) * (p.rate / sats), p.currency)} + {f( + p.tip * (p.rate / sats), + p.currency + )} </span> {/if} </div> <div class="text-secondary"> - {sat(p.amount)} - - {#if p.tip} - <span class="text-sm"> - +{sat(p.tip)} - </span> - {/if} + {sat(p.amount + (p.tip || 0))} </div> </div> diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte index 5638a22b..997d8b4a 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte @@ -5,7 +5,7 @@ import { Icon, Spinner, Pin } from '$comp'; import { t } from '$lib/translations'; - import { fail, post, success } from '$lib/utils'; + import { fail, post, warning, success } from '$lib/utils'; import { avatar, banner, password, pin } from '$lib/store'; import { upload } from '$lib/upload'; import { page } from '$app/stores'; @@ -55,7 +55,12 @@ let data = new FormData(formElement); if (data.get('password')) { - data.set('cipher', await reEncryptEntropy(user, data.get('password'))); + try { + data.set('cipher', await reEncryptEntropy(user, data.get('password'))); + } catch (e) { + console.log('Failed to encrypt keys with new password'); + throw e; + } } if ($avatar) { @@ -80,8 +85,12 @@ tags: [] }; - await sign({ event, user }); - await send(event); + try { + await sign({ event, user }); + await send(event); + } catch (e) { + warning('nostr profile could not be updated'); + } const response = await fetch(formElement.action, { method: 'POST', @@ -150,7 +159,7 @@ {#if loading} <Spinner /> {:else} - <div class="my-auto">Save Settings</div> + <div class="my-auto">{$t('user.settings.saveSettings')}</div> {/if} </button> </div> diff --git a/src/routes/(app)/admin/+layout.server.js b/src/routes/(app)/admin/+layout.server.js new file mode 100644 index 00000000..26449467 --- /dev/null +++ b/src/routes/(app)/admin/+layout.server.js @@ -0,0 +1,11 @@ +import { auth, get } from '$lib/utils'; +import { redirect } from '@sveltejs/kit'; + +export async function load({ cookies, parent }) { + let token = cookies.get('token'); + if (!token) throw redirect(307, '/login'); + let user = await get('/me', auth(cookies)); + if (!user) throw redirect(307, '/login'); + + return { user }; +} diff --git a/src/routes/(app)/admin/+layout.svelte b/src/routes/(app)/admin/+layout.svelte new file mode 100644 index 00000000..d7561e32 --- /dev/null +++ b/src/routes/(app)/admin/+layout.svelte @@ -0,0 +1,10 @@ +<script> + import { LandingHeader } from '$comp'; + export let data; + let { user } = data; +</script> + +<LandingHeader {user} /> +<main class="container px-10 md:px-40 mx-auto min-h-[600px] pb-20"> + <slot /> +</main> diff --git a/src/routes/(app)/admin/+page.server.js b/src/routes/(app)/admin/+page.server.js new file mode 100644 index 00000000..c4079a2f --- /dev/null +++ b/src/routes/(app)/admin/+page.server.js @@ -0,0 +1,10 @@ +import { get } from '$lib/utils'; +import { redirect } from '@sveltejs/kit'; + +export async function load({ parent }) { + let { user } = await parent(); + if (!user) throw redirect(307, '/login'); + + let users = (await get('/users')).sort((a, b) => b.balance - a.balance); + return { users }; +} diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte new file mode 100644 index 00000000..1a747f1f --- /dev/null +++ b/src/routes/(app)/admin/+page.svelte @@ -0,0 +1,11 @@ +<script> + export let data; + let { users } = data; +</script> + +{#each users as { balance, username }} + <div class="grid grid-cols-2"> + <div>{username}</div> + <div>{balance}</div> + </div> +{/each} diff --git a/src/routes/(app)/launch/thanks/[asset]/+page.server.js b/src/routes/(app)/launch/thanks/[asset]/+page.server.js deleted file mode 100644 index e9e01376..00000000 --- a/src/routes/(app)/launch/thanks/[asset]/+page.server.js +++ /dev/null @@ -1 +0,0 @@ -// export const load = ({ parent }) => parent(); diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index b8a23605..cf30db35 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -7,6 +7,7 @@ export let data; let { user, payment: p } = data; + let { username } = user; let { id, amount, created, rate, type, ref, tip, ourfee, fee, currency } = p; let a = Math.abs(amount); @@ -26,42 +27,51 @@ {#if p.with} <div> <span class="text-lg text-secondary my-auto mr-2">{amount > 0 ? 'From' : 'To'}</span> - <a href={`/${p.with.username}`}> - <div class="flex"> - <div class="my-auto"> - <Avatar user={p.with} size={20} /> + <a href={`/${p.with.username}`}> + <div class="flex"> + <div class="my-auto"> + <Avatar user={p.with} size={20} /> + </div> + <div class="my-auto ml-1">{p.with.username}</div> </div> - <div class="my-auto ml-1">{p.with.username}</div> - </div> - </a> + </a> </div> {/if} - <div> <span class="text-lg text-secondary">Amount</span> <div> {f(fiat(a, rate), currency)} - {#if tip} - <span class="text-lg"> - + {f(fiat(tip, rate), currency)} - </span> - {/if} - <span class="text-secondary">⚡️{`${s(a)}`} - - {#if tip} - <span class="text-lg"> - + ⚡️{s(tip)} - </span> - {/if} - </span> + <span class="text-secondary text-lg"> + ⚡️{s(a)} + </span> </div> </div> + {#if tip} + <div> + <span class="text-lg text-secondary">Tip</span> + <div> + {f(fiat(tip, rate), currency)} + <span class="text-secondary text-lg"> + ⚡️{s(tip)} + </span> + </div> + </div> + + <div> + <span class="text-lg text-secondary">Total</span> + <div> + {f(fiat(a + (tip || 0), rate), currency)} + <span class="text-secondary text-lg">⚡️{`${s(a + (tip || 0))}`} </span> + </div> + </div> + {/if} + <div> <span class="text-lg text-secondary">Network fee</span> <div> {f(fiat(fee, rate), currency)} - <span class="text-secondary">⚡️{`${s(fee)}`}</span> + <span class="text-secondary text-lg">⚡️{`${s(fee)}`}</span> </div> </div> diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte index 5f37cad5..3abc5a1a 100644 --- a/src/routes/(app)/send/[...text]/+page.svelte +++ b/src/routes/(app)/send/[...text]/+page.svelte @@ -7,7 +7,6 @@ import { t } from '$lib/translations'; import { AppHeader, Avatar, Icon, Spinner } from '$comp'; import { back, fail } from '$lib/utils'; - import { format, parseISO } from 'date-fns'; export let data; export let form; diff --git a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte index b3a944f4..77d5fde6 100644 --- a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte +++ b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte @@ -22,7 +22,7 @@ loading = false; if (form?.message?.includes('pin')) $pin = undefined; if (form) ({ min, max, feeRate, fee, ourfee, subtract } = form); - if (!ourfee) ourfee = 0; + if (!ourfee) ourfee = 0; if (feeRate) confirmed = true; stale = false; }; @@ -77,7 +77,9 @@ {f(toFiat(fee + ourfee, $selectedRate), currency)} </h2> <h3 class="text-secondary mb-6 mt-1">⚡️{s(fee + ourfee)}</h3> - <button class="absolute right-1/4 top-0 text-secondary p-4" on:click={toggleAdjusting}><Icon icon="settings" style="opacity-30" /></button> + <button class="absolute right-1/4 top-0 text-secondary p-4" on:click={toggleAdjusting} + ><Icon icon="settings" style="opacity-30" /></button + > </div> </div> {:else} @@ -104,7 +106,9 @@ <div class="my-auto"> <Toggle id="subtract" checked={subtract} bind:value={subtract} /> </div> - <label for="subtract" class="text-secondary text-lg my-auto mb-2">Take fee from amount</label> + <label for="subtract" class="text-secondary text-lg my-auto mb-2" + >Take fee from amount</label + > </div> {/if} diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.js b/src/routes/(app)/send/invoice/[id]/+page.server.js index dc0d3a3d..c9c2b222 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.server.js +++ b/src/routes/(app)/send/invoice/[id]/+page.server.js @@ -1,21 +1,30 @@ import { error, fail, redirect } from '@sveltejs/kit'; -import { fd, btc as asset, auth, get, post } from '$lib/utils'; +import { fd, auth, get, post } from '$lib/utils'; -export async function load({ params: { id }, parent }) { +export async function load({ params: { id }, parent, url }) { let { user } = await parent(); - let { amount, address, tip, text, user: recipient } = await get(`/invoice/${id}`); + let { + amount, + address, + hash, + rate, + prompt, + tip, + text, + user: recipient + } = await get(`/invoice/${id}`); + + if (prompt && tip === null) throw redirect(307, `/${recipient.username}/invoice/${id}/tip`); if (recipient.username === user.username) throw error(500, { message: 'Cannot send to self' }); - if (tip) amount += tip; - return { amount, address, payreq: text, recipient }; + return { amount, address, hash, tip, rate, payreq: text, recipient }; } export const actions = { - default: async ({ cookies, params: { hash }, request }) => { + default: async ({ cookies, params: { id }, request }) => { try { let body = await fd(request); - body.amount = parseInt(body.amount); - body.hash = hash; + body.hash = id; await post('/payments', body, auth(cookies)); } catch (e) { diff --git a/src/routes/(app)/send/invoice/[id]/+page.svelte b/src/routes/(app)/send/invoice/[id]/+page.svelte index 7570a61a..c9cb9392 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.svelte +++ b/src/routes/(app)/send/invoice/[id]/+page.svelte @@ -5,11 +5,11 @@ import { enhance } from '$app/forms'; import { Avatar, Icon, Numpad, Spinner } from '$comp'; import { page } from '$app/stores'; - import { back, f, s, sats } from '$lib/utils'; + import { back, f, fiat as toFiat, s, sats } from '$lib/utils'; export let data; export let form; - let { address, payreq, recipient, user } = data; + let { address, payreq, recipient, rate, tip, user } = data; let { currency } = user; let amount = form?.amount || data.amount; @@ -49,9 +49,23 @@ <h1 class="text-xl md:text-2xl text-secondary mb-2"> {$t('payments.send')} </h1> - <p class="text-6xl break-words mb-4"> - {fiat ? f(amountFiat, currency) : '⚡️' + s(amount)} - </p> + <h2 class="text-2xl md:text-3xl font-semibold"> + {f(toFiat(amount, rate), currency)} + {#if tip} + <span class="text-lg"> + + {f(toFiat(tip, rate), currency)} + </span> + {/if} + </h2> + <h3 class="text-secondary md:text-lg mb-6 mt-1"> + ⚡️{s(amount)} + + {#if tip} + <span class="text-lg"> + + ⚡️{s(tip)} + </span> + {/if} + </h3> <h1 class="text-xl md:text-2xl text-secondary mb-2">{$t('payments.to')}</h1> diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.server.js b/src/routes/(app)/send/lightning/[payreq]/+page.server.js index 02511a8f..94231376 100644 --- a/src/routes/(app)/send/lightning/[payreq]/+page.server.js +++ b/src/routes/(app)/send/lightning/[payreq]/+page.server.js @@ -1,5 +1,5 @@ import { fail, redirect } from '@sveltejs/kit'; -import { fd, btc as asset, auth, post } from '$lib/utils'; +import { fd, auth, post } from '$lib/utils'; export async function load({ params }) { return post('/parse', params); diff --git a/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js b/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js index ad0219e0..c63328e2 100644 --- a/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js +++ b/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js @@ -1,5 +1,5 @@ import { error, fail, redirect } from '@sveltejs/kit'; -import { fd, btc as asset, auth, get, post } from '$lib/utils'; +import { fd, auth, get, post } from '$lib/utils'; export async function load({ params, parent }) { let { user } = await parent(); @@ -13,9 +13,6 @@ export const actions = { default: async ({ cookies, request }) => { try { let body = await fd(request); - let { amount } = body; - amount = parseInt(amount); - await post('/payments', body, auth(cookies)); } catch (e) { console.log(e); diff --git a/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte b/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte index 74da1fa8..af6a6368 100644 --- a/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte +++ b/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte @@ -17,22 +17,28 @@ let a, af, fiat = !amount, - hash; + hash, + rate, + amountFiat = 0; - $: amountFiat = amount * ($selectedRate / sats); + selectedRate.subscribe((r) => rate || (amountFiat = amount * (r / sats))); let setAmount = async () => { amount = a; - amountFiat = af; - + amountFiat = parseFloat(af).toFixed(2); + rate = fiat ? (sats * amountFiat) / amount : $selectedRate; ({ hash } = await post(`/${subject.username}/invoice`, { invoice: { amount, + hash: 'internal', rate: rates[subject.currency], + prompt: subject.prompt, type: 'internal' }, user: subject })); + + goto(`/${subject.username}/invoice/${hash}`); }; let loading; @@ -54,17 +60,7 @@ {/if} <div class="container px-4 mt-20 max-w-xl mx-auto space-y-8"> - {#if amount} - <h1 class="text-center text-3xl md:text-4xl font-bold mb-6">Sending</h1> - <div class="text-center mb-8"> - <h2 class="text-2xl md:text-3xl font-semibold"> - {f(amountFiat, currency)} - </h2> - <h3 class="text-secondary md:text-lg mb-6 mt-1">{sat(amount)}</h3> - </div> - {:else} - <Numpad bind:amount={a} bind:amountFiat={af} {currency} bind:fiat /> - {/if} + <Numpad bind:amount={a} bind:amountFiat={af} {currency} bind:fiat /> <form method="POST" use:enhance on:submit={submit}> <input name="amount" value={amount} type="hidden" /> diff --git a/src/routes/(app)/sent/+page.svelte b/src/routes/(app)/sent/+page.svelte index 72511487..dbd18c2e 100644 --- a/src/routes/(app)/sent/+page.svelte +++ b/src/routes/(app)/sent/+page.svelte @@ -7,7 +7,7 @@ export let data; let { payments, user } = data; - let { currency, username } = user; + let { currency, username } = user; let payment = payments[0]; let { amount, rate, tip } = payment; @@ -20,7 +20,7 @@ <div class="flex w-full max-w-[200px] mx-auto py-20" in:scale={{ start: 0.5 }}> <Icon icon="check" style="mx-auto" /> </div> - <h1 class="text-3xl md:text-4xl font-bold mb-6">Sent!</h1> + <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('payments.sent')}!</h1> <h2 class="text-2xl md:text-3xl font-semibold"> {f(fiat(amount, rate), currency)} {#if tip} diff --git a/src/routes/(app)/support/+page.server.js b/src/routes/(app)/support/+page.server.js deleted file mode 100644 index 6d0af616..00000000 --- a/src/routes/(app)/support/+page.server.js +++ /dev/null @@ -1,15 +0,0 @@ -import { fd, post } from '$lib/utils'; -import { fail } from '@sveltejs/kit'; - -export const actions = { - default: async ({ cookies, request }) => { - let form = await fd(request); - try { - await post('/email', form); - } catch (e) { - return fail(400, { error: e.message }); - } - - return { success: true }; - } -}; diff --git a/src/routes/(app)/support/+page.svelte b/src/routes/(app)/support/+page.svelte index d00cc069..8dbfc1af 100644 --- a/src/routes/(app)/support/+page.svelte +++ b/src/routes/(app)/support/+page.svelte @@ -1,10 +1,10 @@ <script> - import { enhance } from '$app/forms'; + import { fail, success, post } from '$lib/utils'; import { scale } from 'svelte/transition'; import { AppHeader, Icon } from '$comp'; import { t } from '$lib/translations'; - export let data, form; + export let data; let { user } = data; $: if (user) { @@ -13,41 +13,58 @@ let email; let message; + let sent; + + let submit = (e) => { + e.preventDefault(); + grecaptcha.ready(() => { + grecaptcha + .execute('6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM', { action: 'submit' }) + .then((token) => + post('/support', { email, message, token }) + .then(() => (sent = true)) + .catch(() => fail('problem submitting')) + ); + }); + }; </script> +<svelte:head> + <script + src="https://www.google.com/recaptcha/api.js?render=6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM" + ></script> +</svelte:head> + {#if user} <AppHeader {data} /> {/if} -{#if form?.error} - <div class="text-red-600 text-center"> - {form.error} - </div> -{/if} +<div class="container px-4 max-w-lg mx-auto mt-20 space-y-8"> + {#if sent} + <h1 class="text-center text-3xl md:text-4xl font-semibold">Thank you!</h1> + <div class="text-center text-lg text-secondary">Someone will be in touch shortly.</div> -<div class="container px-4 max-w-lg mx-auto mt-20 space-y-5"> - {#if form?.success} - <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8">Thank you!</h1> - <p class="text-center mb-8">Someone will be in touch shortly.</p> - - <a href={user ? `/${user.username}` : '/'}> - <button class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full mb-2" - >Done</button - > - </a> + <div> + <a href={user ? `/${user.username}` : '/'}> + <button + class="rounded-full border py-2 px-5 font-bold hover:opacity-80 w-full bg-black text-white" + >Ok</button + > + </a> + </div> {:else} <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8"> {$t('user.support.header')} </h1> - <p class="text-secondary"> + <p class="text-secondary text-lg"> Fill out this form or email us directly at <a class="underline" href="mailto:[email protected]">[email protected]</a > and we'll do our best to get back to you in a timely manner. </p> - <form method="POST" use:enhance> + <form on:submit={submit}> <div class="mb-4"> <label for="account" class="font-semibold">{$t('user.support.accountName')}</label> <input @@ -79,7 +96,7 @@ <button type="submit" disabled={!email || !message} - class="{!email || !message + class="g-recaptcha {!email || !message ? 'opacity-50' : 'opacity-100'} bg-black text-white font-bold rounded-xl py-3 w-full mx-auto {email && message diff --git a/src/routes/(app)/support/+server.js b/src/routes/(app)/support/+server.js new file mode 100644 index 00000000..6b1778a8 --- /dev/null +++ b/src/routes/(app)/support/+server.js @@ -0,0 +1,9 @@ +import { json } from '@sveltejs/kit'; +import { auth, post } from '$lib/utils'; + +export const prerender = false; + +export async function POST({ cookies, request }) { + let result = await post('/email', await request.json(), auth(cookies)); + return json(result); +} |
