aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-03 21:46:49 -0800
committerAdam Soltys <[email protected]>2026-02-11 15:34:18 -0800
commit0a4c48eef92e45e5c12a7b8be321caf165fddb43 (patch)
treeeda11e154d1d9c2d7fc0fce6d30fc3445e124fbb /src
parenta4c2b673ded38c31d869f93fdb8b0a656ff01c17 (diff)
downloadcoinos-ui-0a4c48eef92e45e5c12a7b8be321caf165fddb43.tar.gz
coinos-ui-0a4c48eef92e45e5c12a7b8be321caf165fddb43.zip
accounts redesign
Diffstat (limited to 'src')
-rw-r--r--src/components/Account.svelte76
-rw-r--r--src/components/Balance.svelte2
-rw-r--r--src/components/Numpad.svelte8
-rw-r--r--src/lib/utils.ts19
-rw-r--r--src/locales/en.json3
-rw-r--r--src/routes/(app)/[username]/(profile)/+layout.svelte4
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte6
-rw-r--r--src/routes/(app)/[username]/receive/+page.svelte2
-rw-r--r--src/routes/(app)/apps/[pubkey]/payments/+page.svelte2
-rw-r--r--src/routes/(app)/fund/[id]/+page.svelte2
-rw-r--r--src/routes/(app)/fund/[id]/gift/+page.svelte2
-rw-r--r--src/routes/(app)/fund/[id]/withdraw/+page.svelte2
-rw-r--r--src/routes/(app)/invoice/[id]/+page.svelte2
-rw-r--r--src/routes/(app)/invoice/[id]/tip/+page.svelte2
-rw-r--r--src/routes/(app)/pay/[username]/[...amount]/+page.svelte2
-rw-r--r--src/routes/(app)/payment/[id]/+page.svelte2
-rw-r--r--src/routes/(app)/payments/[...page]/+page.svelte2
-rw-r--r--src/routes/(app)/send/ark/[address]/+layout.server.ts3
-rw-r--r--src/routes/(app)/send/ark/[address]/+page.svelte2
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/+page.svelte2
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte14
-rw-r--r--src/routes/(app)/send/fund/[...name]/[...amount]/+page.svelte2
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte2
-rw-r--r--src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte2
24 files changed, 93 insertions, 72 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte
index 12fa8100..33c769de 100644
--- a/src/components/Account.svelte
+++ b/src/components/Account.svelte
@@ -9,7 +9,7 @@
import { t } from "$lib/translations";
import { arkkey } from "$lib/ark";
- let { user, rate, account, last } = $props();
+ let { user, rate, account } = $props();
let {
name,
seed,
@@ -53,43 +53,45 @@
};
let displayType = $derived(
- accountType === "ark" ? "Ark" : seed ? "Savings" : "Cash",
+ accountType === "ark" ? "Ark" : seed ? "Bitcoin" : "Custodial",
);
let isArk = $derived(accountType === "ark");
</script>
-<div
- class="block space-y-2 border-primary py-4"
- class:border-b-8={!last}
- aria-label="Payments"
->
- <div class="flex">
- <Balance {balance} {user} {rate} {id} />
+<div class="rounded-2xl bg-base-200 p-5 shadow space-y-4" aria-label="Payments">
+ <div class="flex items-center gap-3">
+ {#if isArk}
+ <img src="/images/ark.png" class="w-8 h-8 rounded-full object-cover" alt="Ark" />
+ {:else if seed}
+ <iconify-icon noobserver icon="cryptocurrency-color:btc" width="32"></iconify-icon>
+ {:else}
+ <img src="/images/icon.png" class="w-8 h-8" />
+ {/if}
+ <span class="font-bold text-lg">{displayType}</span>
{#if id !== user.id}
<a
- href={id === user.id ? "/settings/nostr" : `/account/${id}`}
- class="contents"
+ href={`/account/${id}`}
+ class="ml-auto opacity-40 hover:opacity-100 transition-opacity"
aria-label="Settings"
>
- <button class="flex gap-1 mb-auto pb-4 pl-4 ml-auto" aria-label="Settings">
- <iconify-icon
- noobserver
- icon="ph:gear-bold"
- width="32"
- aria-label="Settings"
- ></iconify-icon>
- </button>
+ <iconify-icon
+ noobserver
+ icon="ph:gear-bold"
+ width="24"
+ ></iconify-icon>
</a>
{/if}
</div>
- <div class="flex justify-center w-full text-xl gap-2">
+ <Balance {balance} {user} {rate} {id} />
+
+ <div class="flex w-full text-xl gap-2">
<a
href={"/invoice"}
class="contents"
onclick={(e) => setAccount(e, "/invoice")}
>
- <button class="btn !w-auto flex-grow">
+ <button class="btn !w-auto flex-1">
<iconify-icon
noobserver
icon="ph:hand-coins-bold"
@@ -100,27 +102,27 @@
</button>
</a>
- <!-- <a -->
- <!-- href={"/payments"} -->
- <!-- class="contents" -->
- <!-- onclick={(e) => setAccount(e, "/payments")} -->
- <!-- > -->
- <!-- <button class="btn !w-auto flex-grow"> -->
- <!-- <iconify-icon -->
- <!-- noobserver -->
- <!-- icon="ph:clock-bold" -->
- <!-- width="32" -->
- <!-- flip="horizontal" -->
- <!-- ></iconify-icon> -->
- <!-- </button> -->
- <!-- </a> -->
+ <a
+ href={"/payments"}
+ class="contents"
+ onclick={(e) => setAccount(e, "/payments")}
+ >
+ <button class="btn !w-auto flex-1">
+ <iconify-icon
+ noobserver
+ icon="ph:clock-bold"
+ width="32"
+ ></iconify-icon>
+ <div class="my-auto">{$t("user.dashboard.history")}</div>
+ </button>
+ </a>
<a
href={`/send`}
- class="contents grow"
+ class="contents"
onclick={(e) => setAccount(e, "/send")}
>
- <button type="button" class="btn !w-auto flex-grow">
+ <button type="button" class="btn !w-auto flex-1">
<iconify-icon noobserver icon="ph:paper-plane-right-bold" width="32"
></iconify-icon>
<div class="my-auto">{$t("user.dashboard.send")}</div>
diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte
index 9b8839ca..3d45b543 100644
--- a/src/components/Balance.svelte
+++ b/src/components/Balance.svelte
@@ -8,7 +8,7 @@
let show = $state();
let { id, user, rate, balance } = $props();
let { currency, locked } = $derived(user);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let toggleShow = (e) => {
e.preventDefault();
e.stopPropagation();
diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte
index c321e0bc..5e3e8fa6 100644
--- a/src/components/Numpad.svelte
+++ b/src/components/Numpad.svelte
@@ -27,10 +27,14 @@
let position = $state("before");
function getCurrencyInfo(locale = "en-US", currency) {
- const formatter = new Intl.NumberFormat(locale, {
+ const l = typeof locale === "function" ? locale() : locale || "en-US";
+ const region = l.length >= 2 ? l.slice(-2) : "";
+ const currencyDisplay =
+ region && currency.startsWith(region) ? "narrowSymbol" : "symbol";
+ const formatter = new Intl.NumberFormat(l, {
style: "currency",
currency,
- currencyDisplay: "symbol",
+ currencyDisplay,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 33737b50..897b0f5a 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -334,16 +334,25 @@ export const f = (
locale = "en-US",
minimumFractionDigits = 2,
maximumFractionDigits = 2,
-) =>
- new Intl.NumberFormat(locale, {
+) => {
+ const l = typeof locale === "function" ? locale() : locale || "en-US";
+ const cur = currency || "USD";
+ const region = l.length >= 2 ? l.slice(-2) : "";
+ const currencyDisplay =
+ region && cur.startsWith(region) ? "narrowSymbol" : "symbol";
+ return new Intl.NumberFormat(l, {
style: "currency",
- currency: currency || "USD",
+ currency: cur,
+ currencyDisplay,
minimumFractionDigits,
maximumFractionDigits,
}).format(s);
+};
-export const s = (s: number, locale = "en-US"): string =>
- new Intl.NumberFormat(locale, { maximumFractionDigits: 0 }).format(s);
+export const s = (s: number, locale = "en-US"): string => {
+ const l = typeof locale === "function" ? locale() : locale || "en-US";
+ return new Intl.NumberFormat(l, { maximumFractionDigits: 0 }).format(s);
+};
export const sat = (s: number): string => `${si(Math.abs(s)).toString()}`;
diff --git a/src/locales/en.json b/src/locales/en.json
index cfcbdf36..a09caff1 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -275,7 +275,8 @@
"receive": "Receive",
"withdraw": "Send",
"deposit": "Deposit",
- "voucher": "Voucher"
+ "voucher": "Voucher",
+ "history": "History"
},
"receive": {
"lessThan1BTCWarning": "Please enter an amount less than 1 bitcoin.",
diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte
index 45009035..4a55c6e6 100644
--- a/src/routes/(app)/[username]/(profile)/+layout.svelte
+++ b/src/routes/(app)/[username]/(profile)/+layout.svelte
@@ -21,7 +21,7 @@
let { events, rate, user, subject, src, text } = $derived(data);
let { currency, npub, username: n, display } = $derived(subject);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let showBio = $state();
@@ -275,7 +275,7 @@
{#if currency}
<div
class="flex fixed w-full px-4 bg-base-100/90 py-2 pb-3 bottom-0 tabular-nums"
- style="bottom: calc(var(--safe-area-inset-bottom) + 8px);"
+ style="bottom: var(--safe-area-inset-bottom);"
>
<div class="text-secondary flex mr-auto">
<div class="flex mr-1">
diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte
index a3ced17d..6e37242a 100644
--- a/src/routes/(app)/[username]/(profile)/+page.svelte
+++ b/src/routes/(app)/[username]/(profile)/+page.svelte
@@ -64,9 +64,9 @@
>
{/if}
{#if user?.id && user.id === subject.id}
- <div class="space-y-5" data-sveltekit-preload-data="false">
- {#each accounts as account, i}
- <Account {user} {rate} {account} last={i === accounts.length - 1} />
+ <div class="space-y-4 pb-8" data-sveltekit-preload-data="false">
+ {#each accounts as account}
+ <Account {user} {rate} {account} />
{/each}
</div>
diff --git a/src/routes/(app)/[username]/receive/+page.svelte b/src/routes/(app)/[username]/receive/+page.svelte
index 368af25c..99dc9f7e 100644
--- a/src/routes/(app)/[username]/receive/+page.svelte
+++ b/src/routes/(app)/[username]/receive/+page.svelte
@@ -32,7 +32,7 @@
let id = $state();
let { rate, subject, user, text } = $derived(data);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let { currency, username } = $derived(subject);
let type = types.lightning;
diff --git a/src/routes/(app)/apps/[pubkey]/payments/+page.svelte b/src/routes/(app)/apps/[pubkey]/payments/+page.svelte
index e5a6f14c..d3fb3bc3 100644
--- a/src/routes/(app)/apps/[pubkey]/payments/+page.svelte
+++ b/src/routes/(app)/apps/[pubkey]/payments/+page.svelte
@@ -5,7 +5,7 @@
let { data } = $props();
let { app, user } = $derived(data);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let { payments } = $derived(app);
</script>
diff --git a/src/routes/(app)/fund/[id]/+page.svelte b/src/routes/(app)/fund/[id]/+page.svelte
index 73e13819..226e0249 100644
--- a/src/routes/(app)/fund/[id]/+page.svelte
+++ b/src/routes/(app)/fund/[id]/+page.svelte
@@ -16,7 +16,7 @@
let { amount, payments, managers, rate, user } = data;
let { id } = $page.params;
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let currency = user ? user.currency : "CAD";
diff --git a/src/routes/(app)/fund/[id]/gift/+page.svelte b/src/routes/(app)/fund/[id]/gift/+page.svelte
index b53c7c70..f7594126 100644
--- a/src/routes/(app)/fund/[id]/gift/+page.svelte
+++ b/src/routes/(app)/fund/[id]/gift/+page.svelte
@@ -10,7 +10,7 @@
let { id, user, amount, rate } = $derived(data);
let text = $page.url.href.replace("gift", "sweep");
let currency = $derived(() => (user ? user.currency : "CAD"));
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
</script>
<div class="container px-4 max-w-4xl mx-auto space-y-5 pb-10">
diff --git a/src/routes/(app)/fund/[id]/withdraw/+page.svelte b/src/routes/(app)/fund/[id]/withdraw/+page.svelte
index 54725f03..42f7972e 100644
--- a/src/routes/(app)/fund/[id]/withdraw/+page.svelte
+++ b/src/routes/(app)/fund/[id]/withdraw/+page.svelte
@@ -16,7 +16,7 @@
let loading = $state();
let { id, balance, rate } = $derived(data);
let { amount } = $state(data);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let submit = $state();
let submitting = $state();
diff --git a/src/routes/(app)/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte
index d66bdb12..fe039870 100644
--- a/src/routes/(app)/invoice/[id]/+page.svelte
+++ b/src/routes/(app)/invoice/[id]/+page.svelte
@@ -47,7 +47,7 @@
let { aid, amount, rate, tip, hash, text, type } = $derived(invoice);
let memo = $state();
let { username, currency } = $derived(invoice.user);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let tipPercent = $derived(tip ? (tip / amount) * 100 : 0);
diff --git a/src/routes/(app)/invoice/[id]/tip/+page.svelte b/src/routes/(app)/invoice/[id]/tip/+page.svelte
index 2dca611e..341bbf03 100644
--- a/src/routes/(app)/invoice/[id]/tip/+page.svelte
+++ b/src/routes/(app)/invoice/[id]/tip/+page.svelte
@@ -76,7 +76,7 @@
tip,
user: { username },
} = $state(invoice);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let qr;
let tipPercent = $state();
diff --git a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte
index df506d43..daf5bc08 100644
--- a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte
+++ b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte
@@ -14,7 +14,7 @@
let rate = $derived(data.rate);
let user = $derived(data.user);
let currency = $derived(subject?.currency || "USD");
- let locale = $derived(() => loc(subject));
+ let locale = $derived(loc(subject));
let next = $state();
let initialAmount = $derived(form?.amount || data.amount);
diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte
index 3ccf5a37..71441dff 100644
--- a/src/routes/(app)/payment/[id]/+page.svelte
+++ b/src/routes/(app)/payment/[id]/+page.svelte
@@ -24,7 +24,7 @@
let { data } = $props();
let { user, payment: p } = $state(data);
let locale = user ? locales[user.language] : locales["en"];
- let userLocale = $derived(() => loc(user));
+ let userLocale = $derived(loc(user));
let {
id,
diff --git a/src/routes/(app)/payments/[...page]/+page.svelte b/src/routes/(app)/payments/[...page]/+page.svelte
index a7039e5d..1de317f6 100644
--- a/src/routes/(app)/payments/[...page]/+page.svelte
+++ b/src/routes/(app)/payments/[...page]/+page.svelte
@@ -22,7 +22,7 @@
page: p,
} = $derived(data);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let change = ({ target: { value } }) => goto(value);
let link = (p) => {
diff --git a/src/routes/(app)/send/ark/[address]/+layout.server.ts b/src/routes/(app)/send/ark/[address]/+layout.server.ts
index e7a216d6..cf16ea36 100644
--- a/src/routes/(app)/send/ark/[address]/+layout.server.ts
+++ b/src/routes/(app)/send/ark/[address]/+layout.server.ts
@@ -18,7 +18,8 @@ export async function load({ cookies, params, parent }) {
const recipient = await get(`/users/${invoice.uid}`);
let r = `/pay/${recipient.username}`;
if (amount) r += `/${amount}`;
- if (recipient?.id !== user.id) redirect(307, r);
+ if (recipient?.id !== user.id && recipient.id === invoice.aid)
+ redirect(307, r);
}
return { balance };
diff --git a/src/routes/(app)/send/ark/[address]/+page.svelte b/src/routes/(app)/send/ark/[address]/+page.svelte
index 014df2fb..c6a3834c 100644
--- a/src/routes/(app)/send/ark/[address]/+page.svelte
+++ b/src/routes/(app)/send/ark/[address]/+page.svelte
@@ -13,7 +13,7 @@
let { balance, user } = data;
let { address } = $page.params;
let { currency, username } = user;
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let amount = $state(0);
let a = $state(0);
diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
index 77b5b1cb..d1e5cb85 100644
--- a/src/routes/(app)/send/bitcoin/[address]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/+page.svelte
@@ -12,7 +12,7 @@
let { balance, user } = data;
let { address } = $page.params;
let { currency, username } = user;
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let amount = $state(0);
let a = $state(0);
diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
index 70e68c79..609e795b 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte
@@ -52,7 +52,7 @@
import("@scure/btc-signer"),
import("@scure/bip32"),
import("@scure/bip39"),
- import("@scure/bip39/wordlists/english"),
+ import("@scure/bip39/wordlists/english.js"),
]);
let entropy = await decrypt(account.seed, password);
let mnemonic = entropyToMnemonic(entropy, wordlist);
@@ -60,14 +60,18 @@
let master = HDKey.fromMasterSeed(seed, network);
let child = master.derive("m/84'/0'/0'");
- let tx = Transaction.fromRaw(decode(hex));
+ let raw = decode(hex);
+ let isPSBT = raw[0] === 0x70 && raw[1] === 0x73 && raw[2] === 0x62 && raw[3] === 0x74;
+ let tx = isPSBT ? Transaction.fromPSBT(raw) : Transaction.fromRaw(raw);
for (let [i, input] of tx.inputs.entries()) {
let { witnessUtxo, path } = inputs[i];
- witnessUtxo.amount = BigInt(witnessUtxo.amount);
- witnessUtxo.script = decode(witnessUtxo.script);
+ if (!isPSBT) {
+ witnessUtxo.amount = BigInt(witnessUtxo.amount);
+ witnessUtxo.script = decode(witnessUtxo.script);
+ tx.updateInput(i, { witnessUtxo });
+ }
let key = child.derive(path);
- tx.updateInput(i, { witnessUtxo });
tx.signIdx(key.privateKey, i);
}
diff --git a/src/routes/(app)/send/fund/[...name]/[...amount]/+page.svelte b/src/routes/(app)/send/fund/[...name]/[...amount]/+page.svelte
index 021a37bf..f6b8cb6d 100644
--- a/src/routes/(app)/send/fund/[...name]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/fund/[...name]/[...amount]/+page.svelte
@@ -15,7 +15,7 @@
let { name, rate } = $derived(data);
let loading = $state();
let fiat = $state();
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let submit = $state();
let submitting = $state();
diff --git a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
index af66cebf..bc9e72b6 100644
--- a/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
+++ b/src/routes/(app)/send/lightning/[payreq]/[...memo]/+page.svelte
@@ -14,7 +14,7 @@
let { alias, memo, payreq, ourfee, user } = $derived({ ...data, ...form });
let a = $state();
let { currency, locked } = $derived(user);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
$effect(() => ($rate ||= data.rate));
$effect(() => form && (loading = false));
diff --git a/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte b/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
index 551a84e4..b0ffa37e 100644
--- a/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/zap/[id]/[...amount]/+page.svelte
@@ -17,7 +17,7 @@
let { id, request, user } = $derived({ ...data, ...form });
let a = $state(data.amount);
let { currency } = $derived(user);
- let locale = $derived(() => loc(user));
+ let locale = $derived(loc(user));
let event = $state();
$effect(() => ($rate ||= data.rate));