aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-26 14:48:30 -0800
committerAdam Soltys <[email protected]>2026-02-26 14:48:30 -0800
commit2a59047dc8fc10560a7fde614238ee821cfb6b1b (patch)
treeedf33331d3715f2b615c49c62d454be2ac32a899 /src
parentd915b18b3883e53e9a10ab5de6d617361c61cf7d (diff)
downloadcoinos-ui-2a59047dc8fc10560a7fde614238ee821cfb6b1b.tar.gz
coinos-ui-2a59047dc8fc10560a7fde614238ee821cfb6b1b.zip
payment details redesign
Diffstat (limited to 'src')
-rw-r--r--src/routes/(app)/payment/[id]/+page.svelte275
1 files changed, 138 insertions, 137 deletions
diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte
index af729233..ca3d5b6a 100644
--- a/src/routes/(app)/payment/[id]/+page.svelte
+++ b/src/routes/(app)/payment/[id]/+page.svelte
@@ -16,6 +16,8 @@
import locales from "$lib/locales";
import { goto } from "$app/navigation";
+ let expanded: Set<string> = $state(new Set());
+
let { data } = $props();
let user = $derived(data.user);
let p = $derived(data.payment);
@@ -72,16 +74,16 @@
</script>
{#snippet field(title, amount)}
- <div>
- <span class="text-lg text-secondary">{$t(title)}</span>
+ <div class="flex justify-between items-center py-4 border-b border-base-300 min-h-20">
+ <span class="text-secondary">{$t(title)}</span>
<button
type="button"
- class="flex gap-2 items-end"
+ class="flex gap-1 items-center text-right text-lg"
onclick={toggleFiat}
aria-label="Toggle currency display"
>
{#if $fiat}
- <div class="flex items-center">{f(toFiat(amount, rate), currency, userLocale)}</div>
+ <div>{f(toFiat(amount, rate), currency, userLocale)}</div>
{:else}
<div class="flex items-center">
<iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
@@ -92,155 +94,154 @@
</div>
{/snippet}
-<div class="container mx-auto max-w-lg px-4 space-y-8 break-all text-2xl">
- <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-10">
- {$t(amount < 0 ? "payments.sent" : "payments.received")}
- </h1>
+{#snippet copyable(label, value, href)}
+ <div class="flex justify-between items-center gap-4 py-4 border-b border-base-300 min-h-20">
+ <span class="text-secondary shrink-0">{label}</span>
+ <div class="flex items-center gap-2 min-w-0">
+ <button
+ class="font-mono text-sm text-right break-all hover:opacity-80"
+ onclick={() => {
+ if (expanded.has(label)) {
+ expanded.delete(label);
+ } else {
+ expanded.add(label);
+ }
+ expanded = new Set(expanded);
+ }}
+ aria-label={expanded.has(label) ? "Collapse" : "Expand"}
+ >
+ {#if expanded.has(label)}
+ {value}
+ {:else}
+ {value.slice(0, 8)}...{value.slice(-8)}
+ {/if}
+ </button>
+ <button
+ class="shrink-0 hover:opacity-80"
+ onclick={() => copy(value)}
+ aria-label="Copy {label}"
+ >
+ <iconify-icon noobserver icon="ph:copy-bold" width="20" class="text-secondary"></iconify-icon>
+ </button>
+ {#if href}
+ <a {href} target="_blank" rel="noreferrer" class="shrink-0 hover:opacity-80" aria-label="View in explorer">
+ <iconify-icon noobserver icon="ph:arrow-square-out-bold" width="20" class="text-secondary"></iconify-icon>
+ </a>
+ {/if}
+ </div>
+ </div>
+{/snippet}
+
+<div class="container mx-auto max-w-lg px-4 pb-12">
+ <div class="flex flex-col items-center gap-2 mb-8">
+ <h1 class="text-2xl font-semibold">
+ {$t(amount < 0 ? "payments.sent" : "payments.received")}
+ </h1>
+ <button
+ type="button"
+ class="text-4xl font-bold tracking-tight"
+ onclick={toggleFiat}
+ aria-label="Toggle currency display"
+ >
+ {#if $fiat}
+ {f(toFiat(a, rate), currency, userLocale)}
+ {:else}
+ <span class="flex items-center">
+ <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
+ {s(a, userLocale)}
+ </span>
+ {/if}
+ </button>
+ <div class="text-secondary">
+ {format(new Date(created), "MMM d, yyyy", { locale })} &middot; {format(new Date(created), "h:mmaaa", { locale })}
+ </div>
+ </div>
{#if p.with}
- <a href={`/${p.with.username}`}>
- <span class="text-lg text-secondary my-auto mr-2">{direction}</span>
- <div class="flex">
- <div class="my-auto">
- <Avatar user={p.with} size={20} disabled={true} />
- </div>
- <div class="my-auto ml-1">{p.with.username}</div>
+ <a href={`/${p.with.username}`} class="flex items-center gap-3 py-3 border-b border-base-300">
+ <span class="text-secondary">{direction}</span>
+ <div class="flex items-center gap-2 ml-auto">
+ <Avatar user={p.with} size={20} disabled={true} />
+ <span>{p.with.username}</span>
</div>
</a>
{/if}
- {@render field("payments.amount", a)}
+ <div class="mt-2">
+ {#if tip}
+ {@render field("payments.amount", a)}
+ {@render field("invoice.tip", tip)}
+ {@render field("payments.total", a + (tip || 0))}
+ {/if}
- {#if tip}
- {@render field("invoice.tip", tip)}
- {@render field("payments.total", a + (tip || 0))}
- {/if}
+ {@render field("payments.networkFee", fee)}
- {@render field("payments.networkFee", fee)}
+ {#if ourfee > 0}
+ {@render field("payments.platformFee", ourfee)}
+ {/if}
- {#if ourfee > 0}
- {@render field("payments.platformFee", ourfee)}
- {/if}
-
- <div>
- <span class="text-lg text-secondary">{$t("payments.exchangeRate")}</span>
- <div class="flex justify-left gap-2">
- <div class="text-secondary flex">
- <div class="flex mr-1">
- <div class="my-auto mr-1">1</div>
- <img src="/images/bitcoin.svg" class="w-5 my-auto" alt="Bitcoin" />
+ <div class="flex justify-between items-center py-4 border-b border-base-300 min-h-20">
+ <span class="text-secondary">{$t("payments.exchangeRate")}</span>
+ <div class="flex gap-3 text-secondary">
+ <div class="flex items-center gap-1">
+ <span>1</span>
+ <img src="/images/bitcoin.svg" class="w-4" alt="Bitcoin" />
+ <span>&#61; {f(rate, currency, userLocale, 0, 0)}</span>
</div>
- <div>&#61; {f(rate, currency, userLocale, 0, 0)}</div>
</div>
- <div class="text-secondary flex">
- <div class="flex items-center">
- <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
- {s((1 * sats) / rate)} = {f(1, currency, userLocale, 0, 0)}
- </div>
- </div>
- </div>
- </div>
-
- <div>
- <span class="text-lg text-secondary">{$t("payments.date")}</span>
- <div>
- {format(new Date(created), "MMM d, yyyy", { locale })} {format(new Date(created), "h:mmaaa", { locale })}
</div>
- </div>
- {#if type === types.ecash && amount < 0}
- <a href={`/ecash/${memo}`} class="btn">
- <img src="/images/cash.png" class="w-8" alt="Cash" />
- <div>{$t("payments.ecashToken")}</div>
- </a>
- {:else if type === types.fund}
- <a href={`/fund/${memo}`} class="btn btn-accent">
- <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
- {$t(
- "payments.viewFund",
- )}
- </a>
- {:else if memo?.includes("9734")}
- {@const eid = JSON.parse(memo).tags.find((t) => t[0] === "e")[1]}
- <a href={`/e/${eid}`} class="btn btn-accent">
- <img src="/images/nostr.png" class="w-8" alt="Nostr" />
- <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
- {$t(
- "payments.zappedEvent",
- )}
- </a>
- {:else if memo}
- <div>
- <span class="text-lg text-secondary">{$t("payments.memo")}</span>
- <div>
- {#if memo.includes("text/plain")}
- {JSON.parse(memo)[0][1]}
- {:else}
- {memo}
- {/if}
+ {#if type === types.ecash && amount < 0}
+ <div class="pt-4">
+ <a href={`/ecash/${memo}`} class="btn w-full">
+ <img src="/images/cash.png" class="w-6" alt="Cash" />
+ {$t("payments.ecashToken")}
+ </a>
</div>
- </div>
- {/if}
-
- {#if type === types.lightning || type === types.bolt12}
- <div>
- <span class="text-lg text-secondary">{$t("payments.invoice")}</span>
- <div>{hash}</div>
- </div>
-
- <div>
- <span class="text-lg text-secondary">{$t("payments.preimage")}</span>
- <div>{ref}</div>
- </div>
- {/if}
-
- {#if type === types.ark && hash}
- <div>
- <span class="text-lg text-secondary">Txid</span>
- <div class="flex">
- <div>{hash}</div>
- <button
- class="flex font-bold hover:opacity-80 mb-auto my-auto"
- onclick={() => copy(hash)}
- aria-label="Copy transaction ID"
- ></button>
+ {:else if type === types.fund}
+ <div class="pt-4">
+ <a href={`/fund/${memo}`} class="btn btn-accent w-full">
+ <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
+ {$t("payments.viewFund")}
+ </a>
</div>
- </div>
- {/if}
-
- {#if type === "bitcoin" || type === "liquid"}
- <div>
- <span class="text-lg text-secondary">Txid</span>
- <div class="flex">
- <div>
- <a
- href={`${expl}/tx/${txid}${vout ? "#vout=" + vout : ""}`}
- target="_blank"
- rel="noreferrer"
- >
- {txid}
- </a>
+ {:else if memo?.includes("9734")}
+ {@const eid = JSON.parse(memo).tags.find((t) => t[0] === "e")[1]}
+ <div class="pt-4">
+ <a href={`/e/${eid}`} class="btn btn-accent w-full">
+ <img src="/images/nostr.png" class="w-6" alt="Nostr" />
+ <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"></iconify-icon>
+ {$t("payments.zappedEvent")}
+ </a>
+ </div>
+ {:else if memo}
+ <div class="flex justify-between items-start gap-4 py-3 border-b border-base-300">
+ <span class="text-sm text-secondary shrink-0">{$t("payments.memo")}</span>
+ <div class="text-right break-all">
+ {#if memo.includes("text/plain")}
+ {JSON.parse(memo)[0][1]}
+ {:else}
+ {memo}
+ {/if}
</div>
- <button
- class="flex font-bold hover:opacity-80 mb-auto my-auto"
- onclick={() => copy(txid)}
- aria-label="Copy transaction ID"
- ></button>
</div>
- </div>
- {/if}
+ {/if}
- {#if path}
- <div>
- <span class="text-lg text-secondary">Path</span>
- <div class="flex">
- <div>{path}</div>
- <button
- class="flex font-bold hover:opacity-80 mb-auto my-auto"
- onclick={() => copy(path)}
- aria-label="Copy path"
- ></button>
- </div>
- </div>
- {/if}
+ {#if type === types.lightning || type === types.bolt12}
+ {@render copyable($t("payments.invoice"), hash)}
+ {@render copyable($t("payments.preimage"), ref)}
+ {/if}
+
+ {#if type === types.ark && hash}
+ {@render copyable("Txid", hash)}
+ {/if}
+
+ {#if type === "bitcoin" || type === "liquid"}
+ {@render copyable("Txid", txid, `${expl}/tx/${txid}${vout ? "#vout=" + vout : ""}`)}
+ {/if}
+
+ {#if path}
+ {@render copyable("Path", path)}
+ {/if}
+ </div>
</div>