aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2023-03-17 20:28:00 -0700
committerAdam Soltys <[email protected]>2023-03-17 20:28:00 -0700
commit93f23786af35bbe932bc849c8a301d5af1b82d58 (patch)
treed7d6d408fb34ec1892b67aa56398cffe726d0eab /src/routes/(app)
parentc4757b998cd9be2db18ac1805557bdf175fc86c3 (diff)
parentcdc3a2677c8728af27084024daba288153c2bd52 (diff)
downloadcoinos-ui-93f23786af35bbe932bc849c8a301d5af1b82d58.tar.gz
coinos-ui-93f23786af35bbe932bc849c8a301d5af1b82d58.zip
Merge branch 'master' into hashme
Diffstat (limited to 'src/routes/(app)')
-rw-r--r--src/routes/(app)/+layout.server.js3
-rw-r--r--src/routes/(app)/+layout.svelte1
-rw-r--r--src/routes/(app)/[username]/(profile)/+layout.svelte10
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.server.js38
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte2
-rw-r--r--src/routes/(app)/[username]/(profile)/followers/+page.svelte5
-rw-r--r--src/routes/(app)/[username]/(profile)/follows/+page.svelte5
-rw-r--r--src/routes/(app)/[username]/dashboard/+page.svelte1
-rw-r--r--src/routes/(app)/[username]/invoice/+server.js6
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/+layout.server.js2
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/+page.svelte36
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte6
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte4
-rw-r--r--src/routes/(app)/[username]/messages/+page.server.js2
-rw-r--r--src/routes/(app)/[username]/messages/+page.svelte36
-rw-r--r--src/routes/(app)/[username]/payments/[...page]/+page.svelte34
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/+page.svelte19
-rw-r--r--src/routes/(app)/admin/+layout.server.js11
-rw-r--r--src/routes/(app)/admin/+layout.svelte10
-rw-r--r--src/routes/(app)/admin/+page.server.js10
-rw-r--r--src/routes/(app)/admin/+page.svelte11
-rw-r--r--src/routes/(app)/launch/thanks/[asset]/+page.server.js1
-rw-r--r--src/routes/(app)/payment/[id]/+page.svelte54
-rw-r--r--src/routes/(app)/send/[...text]/+page.svelte1
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte10
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.server.js25
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.svelte24
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.server.js2
-rw-r--r--src/routes/(app)/send/user/[username]/[...amount]/+page.server.js5
-rw-r--r--src/routes/(app)/send/user/[username]/[...amount]/+page.svelte26
-rw-r--r--src/routes/(app)/sent/+page.svelte4
-rw-r--r--src/routes/(app)/support/+page.server.js15
-rw-r--r--src/routes/(app)/support/+page.svelte57
-rw-r--r--src/routes/(app)/support/+server.js9
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"
> 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);
+}