aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-01-16 14:56:32 -0800
committerAdam Soltys <[email protected]>2025-01-16 14:56:32 -0800
commitac3a6407a95879ce68e28a1633697de6d7a95770 (patch)
tree49f98fa864c4afe5ee01f6549d62ec3ec28d2968 /src
parent7a695f5ae0f78eaedea46cd2e612e1c4ac3de7d7 (diff)
downloadcoinos-ui-ac3a6407a95879ce68e28a1633697de6d7a95770.tar.gz
coinos-ui-ac3a6407a95879ce68e28a1633697de6d7a95770.zip
event viewer and zaps
Diffstat (limited to 'src')
-rw-r--r--src/lib/utils.ts9
-rw-r--r--src/routes/(app)/e/[id]/+page.server.ts8
-rw-r--r--src/routes/(app)/e/[id]/+page.svelte32
-rw-r--r--src/routes/(app)/post/+server.ts9
-rw-r--r--src/routes/(app)/post/[...path]/+server.ts12
-rw-r--r--src/routes/(app)/send/zap/[pubkey]/[...id]/+page.server.ts41
-rw-r--r--src/routes/(app)/send/zap/[pubkey]/[...id]/+page.svelte99
7 files changed, 210 insertions, 0 deletions
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index e39c2adc..c175986c 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -2,7 +2,9 @@ import { browser } from "$app/environment";
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { PUBLIC_COINOS_NETWORK, PUBLIC_COINOS_URL } from "$env/static/public";
+import { bytesToHex } from "@noble/hashes/utils";
import { toast } from "@zerodevx/svelte-toast";
+import { decrypt } from "nostr-tools/nip49";
import { get as getStore } from "svelte/store";
export function scroll(section: any) {
@@ -169,6 +171,13 @@ export const login = async (
if (u.language) cookies.set("lang", u.language, opts);
cookies.set("username", user.username, opts);
cookies.set("token", token, opts);
+ if (u.nsec) {
+ cookies.set("sk", bytesToHex(decrypt(u.nsec, user.password)), {
+ ...opts,
+ httpOnly: false,
+ sameSite: "lax",
+ });
+ }
};
export const auth = (cookies) => ({
diff --git a/src/routes/(app)/e/[id]/+page.server.ts b/src/routes/(app)/e/[id]/+page.server.ts
new file mode 100644
index 00000000..e544d261
--- /dev/null
+++ b/src/routes/(app)/e/[id]/+page.server.ts
@@ -0,0 +1,8 @@
+import { get } from "$lib/utils";
+
+export async function load({ params }) {
+ const event = await get(`/event/${params.id}`);
+ const author = await get(`/users/${event.pubkey}`);
+ const zaps = await get(`/zaps/${params.id}`);
+ return { author, event, zaps };
+}
diff --git a/src/routes/(app)/e/[id]/+page.svelte b/src/routes/(app)/e/[id]/+page.svelte
new file mode 100644
index 00000000..6e8c1b56
--- /dev/null
+++ b/src/routes/(app)/e/[id]/+page.svelte
@@ -0,0 +1,32 @@
+<script>
+ import Avatar from "$comp/Avatar.svelte";
+ let { data } = $props();
+ let { author, event, zaps } = $derived(data);
+
+ let zap = () => {};
+</script>
+
+<div class="container px-4 max-w-xl mx-auto space-y-5 break-words">
+ <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold">
+ Event
+ </h1>
+ <div class="flex items-center gap-2 text-2xl">
+ <Avatar user={author} size={16} />
+ <div>{event.content}</div>
+ </div>
+ <a href={`/send/zap/${event.pubkey}/${event.id}`} class="btn btn-accent">
+ <iconify-icon noobserver icon="ph:lightning-fill" class="text-yellow-300"
+ ></iconify-icon>
+ Zap
+ </a>
+ <div class="flex flex-wrap gap-2">
+ {#each zaps as { amount, user }}
+ <a href={`/${user.pubkey}`}>
+ <div class="flex gap-1 items-center">
+ <Avatar {user} size={8} disabled={true} />
+ <div>{amount}</div>
+ </div>
+ </a>
+ {/each}
+ </div>
+</div>
diff --git a/src/routes/(app)/post/+server.ts b/src/routes/(app)/post/+server.ts
new file mode 100644
index 00000000..35c04186
--- /dev/null
+++ b/src/routes/(app)/post/+server.ts
@@ -0,0 +1,9 @@
+export async function POST({ cookies, params, request }) {
+ const body = await request.json();
+ try {
+ const result = await post("/event", body, auth(cookies));
+ return json(result);
+ } catch (e: any) {
+ error(500, e.message);
+ }
+}
diff --git a/src/routes/(app)/post/[...path]/+server.ts b/src/routes/(app)/post/[...path]/+server.ts
new file mode 100644
index 00000000..84df9a36
--- /dev/null
+++ b/src/routes/(app)/post/[...path]/+server.ts
@@ -0,0 +1,12 @@
+import { PUBLIC_COINOS_URL as base } from "$env/static/public";
+import { auth } from "$lib/utils";
+
+export async function POST({ cookies, fetch, params, request }) {
+ const { path } = params;
+
+ return fetch(`${base}/${path}`, {
+ method: "POST",
+ body: JSON.stringify(await request.json()),
+ headers: { "Content-Type": "application/json", ...auth(cookies) },
+ });
+}
diff --git a/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.server.ts b/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.server.ts
new file mode 100644
index 00000000..1dd80d20
--- /dev/null
+++ b/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.server.ts
@@ -0,0 +1,41 @@
+import getRates from "$lib/rates";
+import { auth, fd, post } from "$lib/utils";
+import { fail, redirect } from "@sveltejs/kit";
+
+export async function load({ params, parent }) {
+ const { user } = await parent();
+ const data = { ...params };
+ const rates = await getRates();
+
+ data.rate = rates[user.currency];
+ return data;
+}
+
+export const actions = {
+ setAmount: async ({ cookies, params, request }) => {
+ const data = await fd(request);
+ const { id, pubkey } = params;
+ const { amount } = data;
+
+ data.request = await post(
+ "/zapRequest",
+ { id, amount, pubkey },
+ auth(cookies),
+ );
+
+ return data;
+ },
+
+ send: async ({ cookies, request }) => {
+ let p;
+ try {
+ const body = await fd(request);
+
+ p = await post("/payments", body, auth(cookies));
+ } catch (_) {
+ return fail(400, { message: "payments.failedToRoute" });
+ }
+
+ redirect(307, `/sent/${p.id}`);
+ },
+};
diff --git a/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.svelte b/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.svelte
new file mode 100644
index 00000000..4a4928ea
--- /dev/null
+++ b/src/routes/(app)/send/zap/[pubkey]/[...id]/+page.svelte
@@ -0,0 +1,99 @@
+<script>
+ import { goto } from "$app/navigation";
+ import { untrack } from "svelte";
+ import { t } from "$lib/translations";
+ import { enhance } from "$app/forms";
+ import Amount from "$comp/Amount.svelte";
+ import Numpad from "$comp/Numpad.svelte";
+ import Spinner from "$comp/Spinner.svelte";
+ import { page } from "$app/stores";
+ import { loc, back, post, toFiat, f, s, focus } from "$lib/utils";
+ import { sign, send } from "$lib/nostr";
+ import { rate, pin } from "$lib/store";
+
+ let { data, form } = $props();
+
+ let { id, request, user } = $derived({ ...data, ...form });
+ let a = $state();
+ let { currency } = $derived(user);
+ let locale = loc(user);
+ let event = $state();
+
+ $effect(() => ($rate ||= data.rate));
+ $effect(async () => {
+ if (form) {
+ loading = false;
+ event = await sign(request);
+ let { pr } = await post("/post/zap", { event });
+ goto(`/send/lightning/${pr}`);
+ }
+ });
+
+ let showMax = $state();
+
+ let loading = $state();
+ let submit = () => (loading = true);
+
+ let next = $state();
+ let toggle = () => (show = !show);
+ let amount = $derived(form?.amount || data.amount);
+ let maxfee = $state(Math.max(5, Math.round(untrack(() => amount) * 0.005)));
+</script>
+
+<div class="container px-4 max-w-xl mx-auto text-center space-y-2">
+ {#if form?.message}
+ <div class="text-red-600 text-center">
+ {$t(form.message)}
+ </div>
+ {/if}
+ {#if amount}
+ <div>
+ <h1 class="text-lg text-secondary">
+ {$t("payments.send")}
+ </h1>
+
+ <Amount {amount} rate={$rate} {currency} {locale} />
+ </div>
+
+ <form
+ method="POST"
+ use:enhance
+ onsubmit={submit}
+ action="?/send"
+ class="space-y-2"
+ >
+ <input name="event" value={event} type="hidden" />
+ <input name="amount" value={amount} type="hidden" />
+ <input name="pin" value={$pin} type="hidden" />
+
+ <button
+ type="submit"
+ class="btn btn-primary"
+ disabled={loading}
+ use:focus
+ >
+ {#if loading}
+ <Spinner />
+ {:else}
+ {$t("payments.send")}
+ {/if}
+ </button>
+ </form>
+ {:else}
+ <form method="POST" action="?/setAmount" class="space-y-2" use:enhance>
+ <input type="hidden" value={a} name="amount" />
+ <input name="rate" value={$rate} type="hidden" />
+
+ <Numpad
+ bind:amount={a}
+ {currency}
+ {locale}
+ bind:rate={$rate}
+ submit={next}
+ />
+ <button type="submit" class="btn" bind:this={next}
+ >{$t("payments.next")}</button
+ >
+ </form>
+ {/if}
+</div>