diff options
| author | Adam Soltys <[email protected]> | 2025-01-16 14:56:32 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2025-01-16 14:56:32 -0800 |
| commit | ac3a6407a95879ce68e28a1633697de6d7a95770 (patch) | |
| tree | 49f98fa864c4afe5ee01f6549d62ec3ec28d2968 /src | |
| parent | 7a695f5ae0f78eaedea46cd2e612e1c4ac3de7d7 (diff) | |
| download | coinos-ui-ac3a6407a95879ce68e28a1633697de6d7a95770.tar.gz coinos-ui-ac3a6407a95879ce68e28a1633697de6d7a95770.zip | |
event viewer and zaps
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/utils.ts | 9 | ||||
| -rw-r--r-- | src/routes/(app)/e/[id]/+page.server.ts | 8 | ||||
| -rw-r--r-- | src/routes/(app)/e/[id]/+page.svelte | 32 | ||||
| -rw-r--r-- | src/routes/(app)/post/+server.ts | 9 | ||||
| -rw-r--r-- | src/routes/(app)/post/[...path]/+server.ts | 12 | ||||
| -rw-r--r-- | src/routes/(app)/send/zap/[pubkey]/[...id]/+page.server.ts | 41 | ||||
| -rw-r--r-- | src/routes/(app)/send/zap/[pubkey]/[...id]/+page.svelte | 99 |
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> |
