aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-11-14 13:32:52 -0800
committerAdam Soltys <[email protected]>2024-11-14 16:09:51 -0800
commit0f35462ebdde3701e8fe927b3debace9abf79305 (patch)
tree786d8c833e16762b87a193fb4c09d634784f7744 /src
parent614fbd99b7963ec89666b8b4252fa5f73c81653c (diff)
downloadcoinos-ui-0f35462ebdde3701e8fe927b3debace9abf79305.tar.gz
coinos-ui-0f35462ebdde3701e8fe927b3debace9abf79305.zip
payment amount helpers
Diffstat (limited to 'src')
-rw-r--r--src/components/InvoiceTypes.svelte4
-rw-r--r--src/components/Success.svelte59
-rw-r--r--src/lib/invoice.ts1
-rw-r--r--src/lib/socket.ts17
-rw-r--r--src/routes/(app)/+layout.svelte10
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte8
-rw-r--r--src/routes/(app)/[username]/receive/+page.svelte2
-rw-r--r--src/routes/(app)/invoice/[id]/[email protected]27
-rw-r--r--src/routes/(app)/invoice/[id]/paid/+page.svelte74
-rw-r--r--src/routes/(app)/payment/[id]/+page.svelte40
-rw-r--r--src/routes/(app)/payments/[...page]/+page.svelte33
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.svelte25
-rw-r--r--src/routes/(app)/sent/[id]/+page.svelte18
-rw-r--r--src/routes/(app)/settings/preferences/+page.svelte6
-rw-r--r--src/routes/(static)/login/+page.server.ts1
15 files changed, 127 insertions, 198 deletions
diff --git a/src/components/InvoiceTypes.svelte b/src/components/InvoiceTypes.svelte
index 4dae235a..4e1e5b20 100644
--- a/src/components/InvoiceTypes.svelte
+++ b/src/components/InvoiceTypes.svelte
@@ -30,9 +30,9 @@
class:text-secondary={type === types.lightning}
onclick={() => setType(types.lightning)}
>
- <div class="bg-base-100 rounded-full w-8 h-8 text-center flex">
+ <div class="bg-base-100 rounded-full w-8 h-8 items-center justify-center flex">
<div class="m-auto">
- <iconify-icon icon="ph:lightning-fill" class="text-yellow-300"
+ <iconify-icon icon="ph:lightning-fill" class="text-yellow-300 text-3xl"
></iconify-icon>
</div>
</div>
diff --git a/src/components/Success.svelte b/src/components/Success.svelte
new file mode 100644
index 00000000..f82a4dcb
--- /dev/null
+++ b/src/components/Success.svelte
@@ -0,0 +1,59 @@
+<script>
+ import { browser } from "$app/environment";
+ import { scale } from "svelte/transition";
+ import Amount from "$comp/Amount.svelte";
+ import { Confetti } from "svelte-confetti";
+ const { amount, tip, rate, currency, title } = $props();
+
+ let loaded = $state(false);
+ $effect(() => {
+ if (browser)
+ window.requestAnimationFrame((p) => {
+ loaded = true;
+ });
+ });
+</script>
+
+<div class="text-center mt-20 md:mt-0">
+ {#if loaded}
+ <div class="relative flex justify-center">
+ <div class="absolute top-64 pointer-events-none">
+ <Confetti
+ amount="20"
+ size="40"
+ duration="1600"
+ delay={[0, 500]}
+ fallDistance="50px"
+ colorArray={["url(/images/bolt.svg)"]}
+ />
+ <Confetti
+ amount="40"
+ delay={[0, 500]}
+ size="15"
+ fallDistance="50px"
+ duration="1600"
+ colorArray={[
+ "#FFD700", // Gold
+ "#FF6F61", // Coral
+ "#6BCB77", // Mint green
+ "#4D96FF", // Light blue
+ "#FF9CEE", // Light pink
+ "#FFD580", // Soft orange
+ "#87CEEB", // Sky blue
+ "#FFB6C1", // Light coral pink
+ "#C1C7FF", // Lavender
+ ]}
+ />
+ </div>
+ </div>
+
+ <iconify-icon
+ icon="ph:check-fat-fill"
+ class="text-green-400"
+ width="160"
+ in:scale={{ start: 0.2, duration: 500 }}
+ />
+ {/if}
+ <h1 class="text-3xl md:text-4xl font-bold mb-6">{title}</h1>
+ <Amount {amount} {tip} {rate} {currency} />
+</div>
diff --git a/src/lib/invoice.ts b/src/lib/invoice.ts
index a48e02a4..9563d924 100644
--- a/src/lib/invoice.ts
+++ b/src/lib/invoice.ts
@@ -2,6 +2,7 @@ import { auth, get, post } from "$lib/utils";
import { redirect } from "@sveltejs/kit";
export default async ({ cookies, request }) => {
+ console.log("LOADING");
const form = await request.formData();
const aid = form.get("aid") || cookies.get("aid");
diff --git a/src/lib/socket.ts b/src/lib/socket.ts
index 02d441bf..566e989d 100644
--- a/src/lib/socket.ts
+++ b/src/lib/socket.ts
@@ -1,8 +1,8 @@
-import { invalidate } from "$app/navigation";
-import { navigating } from "$app/stores";
+import { goto, invalidate } from "$app/navigation";
+import { navigating, page } from "$app/stores";
import { PUBLIC_SOCKET } from "$env/static/public";
import { event, invoice, last, request } from "$lib/store";
-import { sat, sleep, success, wait } from "$lib/utils";
+import { s, sleep, success, wait } from "$lib/utils";
import { get } from "svelte/store";
let socket;
@@ -38,13 +38,20 @@ export const messages = (data) => ({
},
async payment() {
- const { amount, confirmed } = data;
+ const { amount, confirmed, iid } = data;
invalidate("app:user");
invalidate("app:invoice");
invalidate("app:payments");
+ const {
+ url: { pathname },
+ } = get(page);
+
if (amount > 0) {
- success(`${confirmed ? "Received" : "Detected"} ${sat(amount)}!`);
+ if (pathname.includes("receive")) {
+ await wait(() => !get(navigating));
+ await goto(`/invoice/${iid}`);
+ } else success(`${confirmed ? "Received" : "Detected"} ⚡️${s(amount)}!`);
}
},
diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte
index ba1eb49a..aaaf543f 100644
--- a/src/routes/(app)/+layout.svelte
+++ b/src/routes/(app)/+layout.svelte
@@ -1,6 +1,4 @@
<script>
- import { run } from "svelte/legacy";
-
import { SvelteToast } from "@zerodevx/svelte-toast";
import { onDestroy, onMount } from "svelte";
import { close, connect, send } from "$lib/socket";
@@ -26,7 +24,7 @@
let { data, children } = $props();
- let { generate, rate, user, subject, token, rates } = $derived(data);
+ let { user, subject, token } = $derived(data);
let { theme } = $state(data);
$themeStore = theme;
@@ -113,13 +111,9 @@
<SvelteToast options={{ reversed: true, intro: { y: 192 } }} />
-<main class="pb-20 min-h-dvh" data-theme={theme}>
+<main class="pb-4 min-h-dvh" data-theme={theme}>
<AppHeader {user} {subject} />
{#if !$loading}
{@render children?.()}
{/if}
</main>
-
-{#if $invoice}
- <Invoice {user} />
-{/if}
diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte
index e956aab7..b3b91405 100644
--- a/src/routes/(app)/[username]/(profile)/+page.svelte
+++ b/src/routes/(app)/[username]/(profile)/+page.svelte
@@ -1,6 +1,5 @@
<script>
- import { run } from 'svelte/legacy';
-
+ import { scale } from "svelte/transition";
import { btc, f, sat } from "$lib/utils";
import Icon from "$comp/Icon.svelte";
import Account from "$comp/Account.svelte";
@@ -22,11 +21,6 @@
let rate = $derived(rates[currency]);
let total = $derived(items.reduce((a, b) => a + b.price * b.quantity, 0));
- let refresh = (d) => ({ accounts, items, subject, user, rates } = d);
- run(() => {
- refresh(data);
- });
-
let install = async () => {
if (!$installPrompt) return;
await $installPrompt.prompt();
diff --git a/src/routes/(app)/[username]/receive/+page.svelte b/src/routes/(app)/[username]/receive/+page.svelte
index 17cb4f09..be4ed3d0 100644
--- a/src/routes/(app)/[username]/receive/+page.svelte
+++ b/src/routes/(app)/[username]/receive/+page.svelte
@@ -1,7 +1,5 @@
<script>
import { run } from "svelte/legacy";
-
- import { send } from "$lib/socket";
import { btc, post, copy, f, get, types, sat, s, sats } from "$lib/utils";
import { tick, onMount, onDestroy } from "svelte";
import { browser } from "$app/environment";
diff --git a/src/routes/(app)/invoice/[id]/[email protected] b/src/routes/(app)/invoice/[id]/[email protected]
index 05fd603f..13b121d8 100644
--- a/src/routes/(app)/invoice/[id]/[email protected]
+++ b/src/routes/(app)/invoice/[id]/[email protected]
@@ -1,6 +1,4 @@
<script>
- import { run } from 'svelte/legacy';
-
import { SvelteToast } from "@zerodevx/svelte-toast";
import { onDestroy, onMount } from "svelte";
import { close, connect, send } from "$lib/socket";
@@ -26,13 +24,12 @@
let { data, children } = $props();
- let { generate, rate, user, subject, token, rates, theme } = $state(data);
-
- let update = (data) => {
- ({ rate, user, subject, token, rates, theme } = data);
- };
+ let { user, subject, token } = $derived(data);
+ let { theme } = $state(data);
$themeStore = theme;
+ $effect(() => (theme = $themeStore));
+ $effect(() => browser && connect(token));
onMount(async () => {
if (browser) {
@@ -58,7 +55,6 @@
}
});
-
let lost,
checkTimer,
expireTimer,
@@ -83,15 +79,6 @@
clearTimeout(expireTimer);
}
});
- run(() => {
- update(data);
- });
- run(() => {
- theme = $themeStore;
- });
- run(() => {
- browser && connect(token);
- });
</script>
{#if browser && user && $passwordPrompt}
@@ -115,13 +102,9 @@
<SvelteToast options={{ reversed: true, intro: { y: 192 } }} />
-<main class="min-h-dvh" data-theme={theme}>
+<main class="pb-4 min-h-dvh" data-theme={theme}>
<AppHeader {user} {subject} />
{#if !$loading}
{@render children?.()}
{/if}
</main>
-
-{#if $invoice}
- <Invoice {user} />
-{/if}
diff --git a/src/routes/(app)/invoice/[id]/paid/+page.svelte b/src/routes/(app)/invoice/[id]/paid/+page.svelte
index d6cfaa46..b031dd8c 100644
--- a/src/routes/(app)/invoice/[id]/paid/+page.svelte
+++ b/src/routes/(app)/invoice/[id]/paid/+page.svelte
@@ -1,70 +1,26 @@
<script>
- import { run } from "svelte/legacy";
-
- import { scale } from "svelte/transition";
- import Icon from "$comp/Icon.svelte";
- import { toast } from "@zerodevx/svelte-toast";
- import { browser } from "$app/environment";
+ import Success from "$comp/Success.svelte";
import { t } from "$lib/translations";
- import { toFiat, f, s, sat, sats } from "$lib/utils";
let { data } = $props();
- let amount,
- currency = $state(),
- rate = $state(),
- received = $state(),
- pending = $state(),
- tip = $state(),
- user = $state(),
- id;
- let update = (data) => {
- ({ amount, currency, rate, received, pending, tip, user, id } =
- data.invoice);
- };
+ let { amount, currency, rate, received, pending, tip, user, id } = $derived(
+ data.invoice,
+ );
- toast.pop(0);
- run(() => {
- update(data);
- });
+ // toast.pop(0);
</script>
<div class="container px-4 text-center mx-auto">
- {#if received}
- <div
- class="flex w-full py-5 max-w-[200px] mx-auto"
- 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(toFiat(received - tip, 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(received - tip)}
-
- {#if tip}
- <span class="text-lg">
- + ⚡️{s(tip)}
- </span>
- {/if}
- </h3>
- {/if}
+ <Success
+ amount={received - tip}
+ {rate}
+ {tip}
+ {currency}
+ title={$t("invoice.paymentSuccessful")}
+ />
{#if pending}
- <div
- class="flex w-full py-5 max-w-[200px] mx-auto"
- in:scale={{ start: 0.5 }}
- >
+ <div class="flex w-full py-5 max-w-[200px] mx-auto">
<Icon icon="orangeclock" style="mx-auto" />
</div>
@@ -88,9 +44,9 @@
</div>
<a href={`/${user.username}`}>
- <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div>
+ <div class="opacity-0 w-screen h-screen fixed top-24 left-0 z-50"></div>
</a>
-<div class="flex justify-center">
+<div class="flex justify-center mt-4">
{$t("payments.tapAnywhere")}
</div>
diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte
index 45dc8642..94226931 100644
--- a/src/routes/(app)/payment/[id]/+page.svelte
+++ b/src/routes/(app)/payment/[id]/+page.svelte
@@ -25,31 +25,6 @@
let { user, payment: p } = $state(data);
let locale = locales[user.language];
- let refresh = (d) => {
- ({ user, payment: p } = d);
- ({
- id,
- hash,
- amount,
- created,
- confirmed,
- memo,
- rate,
- type,
- ref,
- path,
- tip,
- ourfee,
- fee,
- currency,
- } = p);
-
- if (amount > 0) [txid, vout] = ref.split(":");
- else txid = hash;
-
- if (!fee) fee = 0;
- };
-
let { username } = user;
let {
id,
@@ -64,9 +39,10 @@
path,
tip,
ourfee,
- fee,
+ fee = 0,
currency,
- } = $state(p);
+ } = $derived(p);
+ let [txid, vout] = $derived(amount > 0 ? ref.split(":") : [hash]);
let a = Math.abs(amount);
let expl = {
@@ -87,11 +63,6 @@
}
};
- let txid = $state(),
- vout = $state();
- if (amount > 0) [txid, vout] = ref.split(":");
- else txid = hash;
-
let direction = $state("");
onMount(() => {
direction = amount > 0 ? $t("payments.from") : $t("payments.to");
@@ -100,9 +71,6 @@
direction =
direction[0].toUpperCase() + direction.substr(1, direction.length);
});
- run(() => {
- refresh(data);
- });
</script>
{#snippet field(title, amount)}
@@ -111,7 +79,7 @@
<div class="flex gap-2 items-end">
<div class="flex items-center">
<iconify-icon icon="ph:lightning-fill" class="text-yellow-300"
- ></iconify-icon>{amount}
+ ></iconify-icon>{s(amount)}
</div>
<span class="text-secondary text-lg">
{f(toFiat(amount, rate), currency)}
diff --git a/src/routes/(app)/payments/[...page]/+page.svelte b/src/routes/(app)/payments/[...page]/+page.svelte
index d2f9782b..e651ba90 100644
--- a/src/routes/(app)/payments/[...page]/+page.svelte
+++ b/src/routes/(app)/payments/[...page]/+page.svelte
@@ -214,12 +214,14 @@
class="font-bold flex items-center"
class:text-red-800={p.amount < 0}
>
- <iconify-icon
- icon="ph:lightning-fill"
- width="24"
- class="text-yellow-300"
- ></iconify-icon>
- {si(Math.abs(p.amount) + (p.tip || 0), 0, 1)}
+ <div class="flex items-center">
+ <iconify-icon
+ icon="ph:lightning-fill"
+ width="24"
+ class="text-yellow-300"
+ ></iconify-icon>
+ <div>{si(Math.abs(p.amount), 0, 1)}</div>
+ </div>
{#if p.tip}
<span class="text-sm text-secondary">
@@ -256,28 +258,25 @@
</div>
</div>
{:else}
- <div class="text-secondary flex gap-2">
+ <div class="text-secondary flex items-center gap-1">
{#if p.type === types.lightning}
- <div class="text-3xl"><iconify-icon icon="ph:lightning-fill" class="text-yellow-300"
- ></iconify-icon></div>
+ <iconify-icon
+ icon="ph:lightning-fill"
+ class="text-yellow-300 text-3xl"
+ ></iconify-icon>
{:else if p.type === types.ecash}
<img src="/images/cash.png" class="w-12" />
{:else if p.type === types.reconcile}
<iconify-icon icon="ph:scales-bold" width="32"
></iconify-icon>
{:else if p.type === types.bitcoin}
- <div class="my-auto">
- <img
- src="/images/bitcoin.svg"
- class="w-12 border-4 border-transparent"
- alt="Bitcoin"
- />
- </div>
+ <iconify-icon icon="logos:bitcoin" class="text-3xl"
+ ></iconify-icon>
{:else if p.type === types.liquid}
<div class="my-auto">
<img
src="/images/liquid.svg"
- class="w-12 border-4 border-transparent"
+ class="w-10 border-4 border-transparent"
alt="Liquid"
/>
</div>
diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
index af3e09f4..d8bd5f8c 100644
--- a/src/routes/(app)/send/lightning/[payreq]/+page.svelte
+++ b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
@@ -1,9 +1,7 @@
<script>
- import { run } from "svelte/legacy";
-
import { t } from "$lib/translations";
import { enhance } from "$app/forms";
- import Icon from "$comp/Icon.svelte";
+ import Amount from "$comp/Amount.svelte";
import Numpad from "$comp/Numpad.svelte";
import Spinner from "$comp/Spinner.svelte";
import { page } from "$app/stores";
@@ -21,15 +19,7 @@
} = $state(data);
let a = $state();
- let reload = (data) => {
- ({
- alias,
- ourfee,
- rates,
- user: { currency },
- } = data);
- if (!$rate) $rate = rates[currency];
- };
+ $effect(() => ($rate ||= rates[currency]));
let showMax = $state();
@@ -42,17 +32,8 @@
let show;
let toggle = () => (show = !show);
- run(() => {
- reload(data);
- });
let amount = $derived(form?.amount || data.amount);
- let maxfee;
- run(() => {
- maxfee = Math.max(5, Math.round(amount * 0.005));
- });
- run(() => {
- update(form);
- });
+ let maxfee = $state(Math.max(5, Math.round(amount * 0.005)));
</script>
<div class="container px-4 max-w-xl mx-auto text-center space-y-2">
diff --git a/src/routes/(app)/sent/[id]/+page.svelte b/src/routes/(app)/sent/[id]/+page.svelte
index f2f14fef..2eb1f18b 100644
--- a/src/routes/(app)/sent/[id]/+page.svelte
+++ b/src/routes/(app)/sent/[id]/+page.svelte
@@ -1,27 +1,15 @@
<script>
- import { f, focus, s, sat, sats } from "$lib/utils";
- import { scale } from "svelte/transition";
- import Amount from "$comp/Amount.svelte";
- import Icon from "$comp/Icon.svelte";
- import { toast } from "@zerodevx/svelte-toast";
+ import { focus } from "$lib/utils";
import { t } from "$lib/translations";
+ import Success from "$comp/Success.svelte";
let { data } = $props();
let { amount, rate, tip, user } = $state(data);
let { currency, username } = user;
amount = Math.abs(amount);
-
- toast.pop(0);
</script>
-<div class="text-center mt-20 md:mt-0">
- <div class="flex w-full max-w-[200px] mx-auto py-4" in:scale={{ start: 0.5 }}>
- <Icon icon="check" style="mx-auto" />
- </div>
- <h1 class="text-3xl md:text-4xl font-bold mb-6">{$t("payments.sent")}!</h1>
- <Amount {amount} {tip} {rate} {currency} />
-</div>
-
+<Success {amount} {rate} {tip} {currency} title={`${$t("payments.sent")}!`} />
<a href={`/${username}`} use:focus>
<div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div>
</a>
diff --git a/src/routes/(app)/settings/preferences/+page.svelte b/src/routes/(app)/settings/preferences/+page.svelte
index 1f761ecb..a08eb952 100644
--- a/src/routes/(app)/settings/preferences/+page.svelte
+++ b/src/routes/(app)/settings/preferences/+page.svelte
@@ -179,7 +179,8 @@
>
<button type="button" class="flex w-full" onclick={editThreshold}>
<div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-base-200">
- ⚡️
+ <iconify-icon icon="ph:lightning-fill" class="text-yellow-300"
+ ></iconify-icon>
</div>
<div
class="border-l-0 rounded-l-none pl-2 w-full p-4 border rounded-2xl text-left"
@@ -199,7 +200,8 @@
>
<button type="button" class="flex w-full" onclick={editReserve}>
<div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-base-200">
- ⚡️
+ <iconify-icon icon="ph:lightning-fill" class="text-yellow-300"
+ ></iconify-icon>
</div>
<div
class="border-l-0 rounded-l-none pl-2 w-full p-4 border rounded-2xl text-left"
diff --git a/src/routes/(static)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts
index f77f24f2..6e268c92 100644
--- a/src/routes/(static)/login/+page.server.ts
+++ b/src/routes/(static)/login/+page.server.ts
@@ -18,7 +18,6 @@ export const actions = {
await login(user, cookies, request.headers.get("cf-connecting-ip"));
} catch (e) {
const { message } = e as Error;
- console.log("message", message);
return fail(400, { error: "Login failed", message, ...form });
}