diff options
| author | Adam Soltys <[email protected]> | 2024-09-10 20:39:47 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-09-17 09:18:36 -0700 |
| commit | 1f63848ca9fb01336f04b41434de1cc06a5b3d93 (patch) | |
| tree | 2affa3041863be365f33d99e1f32bda60cf93a32 | |
| parent | 6e48c584605bec5623c12c470d04d07303983801 (diff) | |
| download | coinos-ui-1f63848ca9fb01336f04b41434de1cc06a5b3d93.tar.gz coinos-ui-1f63848ca9fb01336f04b41434de1cc06a5b3d93.zip | |
move routes
| -rw-r--r-- | src/components/Account.svelte | 9 | ||||
| -rw-r--r-- | src/components/AppHeader.svelte | 25 | ||||
| -rw-r--r-- | src/components/Invoice.svelte | 2 | ||||
| -rw-r--r-- | src/components/Items.svelte | 51 | ||||
| -rw-r--r-- | src/components/LandingHeader.svelte | 6 | ||||
| -rw-r--r-- | src/components/LocationsMap.svelte | 12 | ||||
| -rw-r--r-- | src/components/Request.svelte | 2 | ||||
| -rw-r--r-- | src/lib/invoice.ts | 6 | ||||
| -rw-r--r-- | src/locales/en.json | 2 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.server.ts | 24 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.svelte | 3 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+layout.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 18 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+layout.server.ts | 12 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+layout.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/[...account]/receive/[...param]/+page.svelte | 116 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/address/+page.server.ts | 9 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/card/[serial]/+page.server.ts | 16 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/card/[serial]/+page.svelte | 36 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/customers/+page.svelte | 0 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/funds/+page.server.ts | 0 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/funds/+page.svelte | 52 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/map/+page.server.ts | 12 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/map/+page.svelte | 8 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/reset/+server.ts | 10 | ||||
| -rw-r--r-- | src/routes/(app)/account/setup/+page.svelte (renamed from src/routes/(app)/[username]/account/setup/+page.svelte) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/account/setup/step2/+page.svelte (renamed from src/routes/(app)/[username]/account/setup/step2/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/admin/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/ecash/[id]/[...version]/+layout.svelte | 1 | ||||
| -rw-r--r-- | src/routes/(app)/fund/[id]/+page.server.ts | 2 | ||||
| -rw-r--r-- | src/routes/(app)/fund/[id]/sweep/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/generate/+page.svelte (renamed from src/routes/(app)/[username]/generate/+page.svelte) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/generate/+server.ts (renamed from src/routes/(app)/[username]/generate/+server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/+page.server.ts (renamed from src/routes/(app)/[username]/[...account]/receive/[...param]/+page.server.ts) | 6 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/+page.svelte (renamed from src/routes/(app)/[username]/address/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/+server.ts (renamed from src/routes/(app)/[username]/invoice/+server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+layout.server.ts (renamed from src/routes/(app)/[username]/invoice/[id]/+layout.server.ts) | 5 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+layout.svelte (renamed from src/routes/(app)/[username]/invoice/[id]/+layout.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+page.server.ts (renamed from src/routes/(app)/[username]/invoice/[id]/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/+page.svelte (renamed from src/routes/(app)/[username]/invoice/[id]/+page.svelte) | 91 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/memo/+page.server.ts (renamed from src/routes/(app)/[username]/invoice/[id]/memo/+page.server.ts) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/memo/+page.svelte (renamed from src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/paid/+page.svelte (renamed from src/routes/(app)/[username]/invoice/[id]/paid/+page.svelte) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/tip/+page.server.ts (renamed from src/routes/(app)/[username]/invoice/[id]/tip/+page.server.ts) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/tip/+page.svelte (renamed from src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/sent/+page.svelte (renamed from src/routes/(app)/[username]/invoice/sent/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/items/[id]/+page.server.ts (renamed from src/routes/(app)/[username]/items/[id]/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/items/[id]/+page.svelte (renamed from src/routes/(app)/[username]/items/[id]/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/items/create/+page.server.ts (renamed from src/routes/(app)/[username]/items/create/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/items/create/+page.svelte (renamed from src/routes/(app)/[username]/items/create/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/ln/[lnurl]/+page.server.ts | 2 | ||||
| -rw-r--r-- | src/routes/(app)/ln/withdrawal/sent/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/login/+page.svelte | 188 | ||||
| -rw-r--r-- | src/routes/(app)/messages/+page.server.ts (renamed from src/routes/(app)/[username]/messages/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/messages/+page.svelte (renamed from src/routes/(app)/[username]/messages/+page.svelte) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/messages/[recipient]/+page.server.ts (renamed from src/routes/(app)/[username]/messages/[recipient]/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/messages/[recipient]/+page.svelte (renamed from src/routes/(app)/[username]/messages/[recipient]/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/pay/[username]/[...amount]/+page.server.ts | 2 | ||||
| -rw-r--r-- | src/routes/(app)/pay/[username]/[...amount]/+page.svelte | 5 | ||||
| -rw-r--r-- | src/routes/(app)/payment/[id]/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/payments/[...page]/+page.server.ts (renamed from src/routes/(app)/[username]/[...account]/payments/[...page]/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/payments/[...page]/+page.svelte (renamed from src/routes/(app)/[username]/[...account]/payments/[...page]/+page.svelte) | 4 | ||||
| -rw-r--r-- | src/routes/(app)/payments/[...page]/+server.ts (renamed from src/routes/(app)/[username]/[...account]/payments/[...page]/+server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/receive/[...token]/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/register/+page.svelte | 314 | ||||
| -rw-r--r-- | src/routes/(app)/send/[...text]/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/send/invoice/[id]/+page.server.ts | 6 | ||||
| -rw-r--r-- | src/routes/(app)/send/invoice/[id]/+page.svelte | 4 | ||||
| -rw-r--r-- | src/routes/(app)/sent/+page.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/+page.server.ts (renamed from src/routes/(app)/[username]/settings/[...tab]/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/+page.svelte (renamed from src/routes/(app)/[username]/settings/[...tab]/+page.svelte) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/_account.svelte (renamed from src/routes/(app)/[username]/settings/[...tab]/_account.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/_pos.svelte (renamed from src/routes/(app)/[username]/settings/[...tab]/_pos.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/_security.svelte (renamed from src/routes/(app)/[username]/settings/[...tab]/_security.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/settings/[...tab]/_shopify.svelte (renamed from src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(app)/verify/[code]/+page.server.ts (renamed from src/routes/(app)/[username]/verify/[code]/+page.server.ts) | 2 | ||||
| -rw-r--r-- | src/routes/(app)/verify/[code]/+page.svelte (renamed from src/routes/(app)/[username]/verify/[code]/+page.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/(static)/+layout.svelte | 2 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.server.ts (renamed from src/routes/(app)/login/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.svelte | 171 | ||||
| -rw-r--r-- | src/routes/(static)/register/+page.server.ts (renamed from src/routes/(app)/register/+page.server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/(static)/register/+page.svelte | 292 | ||||
| -rw-r--r-- | src/routes/(static)/support/+page.svelte (renamed from src/routes/(app)/support/+page.svelte) | 19 | ||||
| -rw-r--r-- | src/routes/(static)/support/+server.ts (renamed from src/routes/(app)/support/+server.ts) | 0 | ||||
| -rw-r--r-- | src/routes/+error.svelte (renamed from src/routes/(app)/+error.svelte) | 0 | ||||
| -rw-r--r-- | src/routes/start/+server.ts | 2 |
86 files changed, 667 insertions, 914 deletions
diff --git a/src/components/Account.svelte b/src/components/Account.svelte index a9b3d6ba..eb1b0bac 100644 --- a/src/components/Account.svelte +++ b/src/components/Account.svelte @@ -5,10 +5,10 @@ export let user, rate, account; let { seed, balance, id } = account; - $: type = seed ? "Savings":"Cash"; + $: type = seed ? "Savings" : "Cash"; </script> -<a href={`/${user.username}/${id}/payments`.replace(/undefined\//, "")}> +<a href={`/payments`} class="block"> <div class="border rounded-xl shadow p-4 space-y-5"> <div class="flex justify-center lg:justify-start"> <Balance {balance} {user} {rate} /> @@ -30,10 +30,7 @@ </button> </a> - <a - href={`/${user.username}/${id}/receive`.replace(/undefined\//, "")} - class="contents" - > + <a href={`/invoice`} class="contents"> <button class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-primary grow" > diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 3b0303a8..b777e0b5 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -7,11 +7,7 @@ import { loading, t } from "$lib/translations"; import { page } from "$app/stores"; - export let data; - - let { subject, user } = data; - $: update(data); - let update = (data) => ({ subject, user } = data); + export let user, subject; let menuButtons; $: if (user) @@ -19,14 +15,14 @@ { key: "nav.settings", icon: "settings", - href: `/${user.username}/settings`, + href: `/settings`, }, { key: "nav.support", icon: "support", href: `/support` }, - { key: "nav.map", icon: "map", href: `/${user.username}/map` }, + { key: "nav.map", icon: "map", href: `/map` }, { key: "nav.messages", icon: "message", - href: `/${user.username}/messages`, + href: `/messages`, }, { key: "nav.merch", icon: "shop", href: `https://coinosmerch.com` }, { key: "nav.signOut", icon: "logout", href: `/logout` }, @@ -60,19 +56,19 @@ ><Icon icon="home" style="mx-auto w-6 sm:w-8" /> </button> </a> - <a href={`/${user.username}/receive`}> + <a href={`/invoice`}> <button class="bg-white p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}/receive` + .url.pathname.includes('invoice') ? 'opacity-100' : 'opacity-70 hover:opacity-80'}" ><Icon icon="receive" style="mx-auto w-6 sm:w-8" /> </button> </a> - <a href={`/${user.username}/payments`}> + <a href={`/payments`}> <button class="bg-white p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}/payments` + .url.pathname === `/payments` ? 'opacity-100' : 'opacity-70 hover:opacity-80'} relative" ><Icon icon="clock" style="mx-auto w-6 sm:w-8" /> @@ -102,9 +98,8 @@ <div class="relative"> <OutClick on:outclick={() => (showMenu = false)}> <button - class="bg-white p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}` || - $page.url.pathname === `/${user.username}/settings` || + class="bg-white p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl border border-black/10 { + $page.url.pathname === `/settings` || $page.url.pathname === `/support` ? 'opacity-100' : `opacity-70 hover:opacity-80 ${ diff --git a/src/components/Invoice.svelte b/src/components/Invoice.svelte index ba436649..563a2fee 100644 --- a/src/components/Invoice.svelte +++ b/src/components/Invoice.svelte @@ -27,7 +27,7 @@ </div> </div> <div class="mx-auto my-auto flex gap-2"> - <a href={`/${invoice.user.username}/invoice/${$invoice.id}/tip`}> + <a href={`/invoice/${$invoice.id}/tip`}> <button class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32" > diff --git a/src/components/Items.svelte b/src/components/Items.svelte index f449215c..f991e114 100644 --- a/src/components/Items.svelte +++ b/src/components/Items.svelte @@ -1,4 +1,5 @@ <script> + import { t } from "$lib/translations"; import { btc, f, sat, post } from "$lib/utils"; import { browser } from "$app/environment"; import { goto, invalidate } from "$app/navigation"; @@ -14,7 +15,7 @@ import DeleteItem from "$comp/DeleteItem.svelte"; import Icon from "$comp/Icon.svelte"; - export let subject, user, items, total, rate, currency; + export let subject, user, items, rate, currency; let flipDurationMs = 200; let dropTargetStyle = {}; @@ -27,6 +28,8 @@ deleting = item; }; + $: total = items.reduce((a, b) => a + b.price * b.quantity, 0); + function handleConsider(e) { const { items: newItems, @@ -77,15 +80,15 @@ rate, }; - let { id } = await post(`/${subject.username}/invoice`, { + let { id } = await post(`/invoice`, { invoice, user: { username: subject.username }, }); if (invoice.memoPrompt) { - return goto(`/${subject.username}/invoice/${id}/memo`); + return goto(`/invoice/${id}/memo`); } - goto(`/${subject.username}/invoice/${id}`); + goto(`/invoice/${id}`); }; let reset = () => @@ -135,7 +138,7 @@ {#if user?.username === subject.username} <div class="flex gap-2 justify-center absolute top-2 right-2"> <button type="button" on:click|stopPropagation={() => {}}> - <a href={`/${user.username}/items/${i.id}`}> + <a href={`/items/${i.id}`}> <button class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" > @@ -157,7 +160,7 @@ on:touchstart={startDrag} on:keydown={handleKeyDown} > - <a href={`/${user.username}/items/${i.id}`}> + <a href={`/items/${i.id}`}> <button class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" > @@ -207,3 +210,39 @@ </button> {/each} </div> + +<div + class="fixed inset-x-0 mx-auto flex bottom-16" + class:static={!items.length} +> + {#if total > 0} + <button + class="rounded-2xl py-5 px-6 font-bold hover:bg-neutral-700 flex bg-black text-white mx-auto" + on:click={checkout} + > + <div class="mx-auto flex"> + <div class="my-auto text-2xl"> + {$t("user.dashboard.checkout")} + {f(total, currency)} + <span class="text-base"> + {sat(btc(total, rate), currency)} + </span> + </div> + </div> + </button> + {/if} +</div> + +<style> + .custom-shadow-item { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + visibility: visible; + background: #333; + opacity: 0.5; + margin: 0; + } +</style> diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte index d1094a1d..92de7bcd 100644 --- a/src/components/LandingHeader.svelte +++ b/src/components/LandingHeader.svelte @@ -19,10 +19,10 @@ </script> <header - class="w-full lg:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90" + class="w-full md:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90" bind:this={header} > - <nav class="block xl:flex flex-wrap justify-between items-center"> + <nav class="block md:flex justify-between items-center"> <div class="flex justify-start md:justify-center items-center md:space-x-10" > @@ -34,7 +34,7 @@ <!-- desktop nav --> <div - class="hidden space-x-10 md:flex flex-wrap justify-center items-center font-bold" + class="hidden space-x-10 md:flex justify-center items-center font-bold" > {#if $page.url.pathname === "/"} <button class="hover:opacity-80" on:click={() => scroll(howItWorks)} diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte index 79ea4bf3..bd51b125 100644 --- a/src/components/LocationsMap.svelte +++ b/src/components/LocationsMap.svelte @@ -3,7 +3,7 @@ import { browser } from "$app/environment"; import Icon from "$comp/Icon.svelte"; import Popup from "$comp/Popup.svelte"; - import { shuffleArray } from "$lib/utils"; + import { back, shuffleArray } from "$lib/utils"; import "maplibre-gl/dist/maplibre-gl.css"; @@ -220,8 +220,16 @@ class="mx-auto h-full w-full z-0" bind:this={mapContainer} /> + <div class="absolute flex top-2 left-2 gap-2"> + <button + class="rounded-full border-2 border-black bg-white w-10 h-10" + on:click={back} + > + <Icon icon="arrow-left" style="w-4 m-auto" /> + </button> + </div> <div class="relative"> - <div class="flex absolute flex top-2 right-2 gap-2"> + <div class="absolute flex top-2 right-2 gap-2"> <button class="rounded-full border-2 border-black bg-white w-10 h-10" on:click={toggle} diff --git a/src/components/Request.svelte b/src/components/Request.svelte index c085f9e2..297b7438 100644 --- a/src/components/Request.svelte +++ b/src/components/Request.svelte @@ -26,7 +26,7 @@ </div> </div> <div class="mx-auto my-auto flex gap-2"> - <a href={`/${user.username}/receive/${$request.id}`}> + <a href={`/receive/${$request.id}`}> <button class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32" > diff --git a/src/lib/invoice.ts b/src/lib/invoice.ts index 7897dadc..3c885346 100644 --- a/src/lib/invoice.ts +++ b/src/lib/invoice.ts @@ -25,9 +25,9 @@ export default async ({ cookies, request }) => { let { id } = invoice; if (invoice.prompt && invoice.tip === null) - redirect(307, `/${user.username}/invoice/${id}/tip`); + redirect(307, `/invoice/${id}/tip`); if (invoice.memoPrompt && !invoice.memo) { - redirect(307, `/${user.username}/invoice/${id}/memo`); - } else redirect(307, `/${user.username}/invoice/${id}`); + redirect(307, `/invoice/${id}/memo`); + } else redirect(307, `/invoice/${id}`); }; diff --git a/src/locales/en.json b/src/locales/en.json index ad42b8cc..b1bbe1c4 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -132,7 +132,9 @@ "haveAccount": "Already have an account?", "noAccount": "Don't have an account?", "register": "Register", + "createAccount": "Create account", "signIn": "Sign In", + "signUp": "Sign Up", "failed": "Login failed" }, "nav": { diff --git a/src/routes/(app)/+layout.server.ts b/src/routes/(app)/+layout.server.ts index 655a9425..a0e30f31 100644 --- a/src/routes/(app)/+layout.server.ts +++ b/src/routes/(app)/+layout.server.ts @@ -1,8 +1,9 @@ -import { redirect } from "@sveltejs/kit"; - import { get, auth, protectedRoutes } from "$lib/utils"; +import { error, redirect } from "@sveltejs/kit"; +import { get, auth, protectedRoutes } from "$lib/utils"; export async function load({ cookies, request, url, params }) { let { pathname } = url; + let { username } = params; let token = cookies.get("token"); let rate, rates = { USD: 1 }; @@ -14,6 +15,18 @@ export async function load({ cookies, request, url, params }) { } catch (e) {} } + let subject; + if (username) { + try { + subject = await get(`/users/${username}`); + } catch (e) { + error(500, "Unable to retrieve user account data"); + } + } + + if (!subject) subject = user; + if (!user) user = subject; + if (user?.needsMigration) { redirect(307, `/migrate`); } @@ -26,10 +39,7 @@ export async function load({ cookies, request, url, params }) { redirect(307, `/${user.username}`); } - if ( - protectedRoutes.find((p) => pathname.match(p)) && - (!user || user.username !== params.username) - ) { + if ( protectedRoutes.find((p) => pathname.match(p)) && (!user)) { redirect(307, "/login"); } @@ -44,5 +54,5 @@ export async function load({ cookies, request, url, params }) { console.log(e); } - return { user, token, rate, rates }; + return { user, token, rate, rates, subject }; } diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 8d4e2940..0ff4816d 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -14,6 +14,7 @@ import { page } from "$app/stores"; import { browser } from "$app/environment"; import LoadingSplash from "$comp/LoadingSplash.svelte"; + import AppHeader from "$comp/AppHeader.svelte"; import Invoice from "$comp/Invoice.svelte"; import Password from "$comp/Password.svelte"; import Request from "$comp/Request.svelte"; @@ -35,6 +36,7 @@ }); let { generate, rate, user, subject, token, rates } = data; + console.log("SUB", subject) $: update(data); let update = (data) => { @@ -115,6 +117,7 @@ <SvelteToast options={{ reversed: true, intro: { y: 192 } }} /> <main class="pb-20"> + <AppHeader {user} {subject} /> {#if !$loading} <slot /> {/if} diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index 2caf9b30..111fdeb6 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -219,7 +219,7 @@ {#if user && user.username !== subject.username && subject.pubkey} <a - href={`/${user.username}/messages/${subject.username}`} + href={`/messages/${subject.username}`} class="contents" > <button diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index 25244c6d..9e5babd2 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -26,16 +26,16 @@ if (user) user.savings = 0; </script> -{#if !user.balance} - <div class="mb-8"> - <p class="text-secondary text-lg"> - {$t("user.welcome")} - </p> - </div> -{/if} - <div class="space-y-2"> {#if user?.id === subject.id} + {#if !user.balance} + <div class="mb-8"> + <p class="text-secondary text-lg"> + {$t("user.welcome")} + </p> + </div> + {/if} + {#each accounts as account} <Account {user} {rate} {account} /> {/each} @@ -43,7 +43,7 @@ <button class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-black text-white" > - <a href={`/${user.username}/account/setup`}> + <a href={`/account/setup`}> <div class="mx-auto flex gap-2"> <Icon icon="plus" style="w-8 mx-auto invert" /> <div class="my-auto text-xl whitespace-nowrap">Add account</div> diff --git a/src/routes/(app)/[username]/+layout.server.ts b/src/routes/(app)/[username]/+layout.server.ts index 11e6d45c..c340544d 100644 --- a/src/routes/(app)/[username]/+layout.server.ts +++ b/src/routes/(app)/[username]/+layout.server.ts @@ -1,17 +1,25 @@ import { get } from "$lib/utils"; import { error } from "@sveltejs/kit"; -export let load = async ({ cookies, depends, params: { username } }) => { +export let load = async ({ + cookies, + depends, + params: { username }, + parent, +}) => { depends("app:user"); try { let subject = await get(`/users/${username}`); + let { user } = await parent(); + if (!user) user = subject; + console.log("SUBJECT", subject) let expires = new Date(); expires.setSeconds(expires.getSeconds() + 380 * 24 * 60 * 60); cookies.set("username", username, { path: "/", expires }); - return { subject }; + return { subject, user }; } catch (e) { error(500, "Unable to retrieve user account data"); } diff --git a/src/routes/(app)/[username]/+layout.svelte b/src/routes/(app)/[username]/+layout.svelte index cd517fa9..98569f59 100644 --- a/src/routes/(app)/[username]/+layout.svelte +++ b/src/routes/(app)/[username]/+layout.svelte @@ -1,5 +1,4 @@ <script> - import AppHeader from "$comp/AppHeader.svelte"; import { onNavigate } from "$app/navigation"; export let data; @@ -15,7 +14,6 @@ }); </script> -<AppHeader {data} /> <div class="content"> <slot /> </div> diff --git a/src/routes/(app)/[username]/[...account]/receive/[...param]/+page.svelte b/src/routes/(app)/[username]/[...account]/receive/[...param]/+page.svelte deleted file mode 100644 index f9267105..00000000 --- a/src/routes/(app)/[username]/[...account]/receive/[...param]/+page.svelte +++ /dev/null @@ -1,116 +0,0 @@ -<script> - import { page } from "$app/stores"; - import { fly } from "svelte/transition"; - import { enhance } from "$app/forms"; - import { tick } from "svelte"; - import { browser } from "$app/environment"; - import { t } from "$lib/translations"; - import AppHeader from "$comp/AppHeader.svelte"; - import Avatar from "$comp/Avatar.svelte"; - import Icon from "$comp/Icon.svelte"; - import Spinner from "$comp/Spinner.svelte"; - import { back, fail, focus } from "$lib/utils"; - - export let data; - export let form; - data.subject = data.user; - - let { contacts } = data; - let w; - - let el, text; - - let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click()); - - let paste = async () => { - text = await navigator.clipboard.readText(); - }; -</script> - -<svelte:window bind:innerWidth={w} /> - -<AppHeader {data} /> -<div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> - {$t("payments.send")} - </h1> - - <form method="POST" use:enhance class="space-y-2 text-xl"> - {#if form?.error} - <div class="mb-5"> - <div class="text-red-600"> - {$t("error.unrecognizedInput")} - </div> - </div> - {/if} - - <div class="mb-2"> - <textarea - use:focus - name="text" - placeholder={$t("user.send.placeholder")} - on:keypress={keypress} - class="w-full p-4 border rounded-xl h-48 text-xl" - bind:value={text} - autocapitalize="none" - /> - </div> - - <div class="flex gap-2"> - <a href="/scan" class="w-full"> - <button - type="button" - class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center" - > - <Icon icon="camera" style="mr-2 w-6 my-auto" /> - <div class="my-auto">{$t("user.send.scan")}</div> - </button> - </a> - - <button - type="button" - class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center" - on:click={paste} - > - <Icon icon="paste" style="mr-2 w-6 my-auto" /> - <div class="my-auto">{$t("user.send.paste")}</div> - </button> - </div> - - <button - bind:this={el} - type="submit" - class="bg-black text-white border rounded-2xl px-6 py-5 w-full font-bold" - > - {$t("user.send.next")} - </button> - </form> - - {#if contacts.length} - <div class="space-y-5"> - <h1 class="px-3 md:px-0 text-2xl font-semibold mt-10"> - {$t("user.send.contacts")} - </h1> - <div> - {#each contacts as c} - <a href={`/pay/${c.username}`}> - <div - class="border-b p-2 last:border-b-0 hover:bg-gray-100 rounded-2xl" - > - <div class="flex"> - <div> - <div class="flex"> - <Avatar user={c} size={20} disabled={true} /> - <div class="my-auto text-left"> - <p class="ml-1 text-lg break-words">{c.username}</p> - </div> - </div> - </div> - </div> - </div> - </a> - {/each} - </div> - </div> - {/if} -</div> diff --git a/src/routes/(app)/[username]/address/+page.server.ts b/src/routes/(app)/[username]/address/+page.server.ts deleted file mode 100644 index 2f7841ab..00000000 --- a/src/routes/(app)/[username]/address/+page.server.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { auth, post } from "$lib/utils"; -import { redirect } from "@sveltejs/kit"; - -export async function load({ cookies, parent }) { - let user = (await parent()).subject; - let invoice = { type: "bitcoin" }; - let { id } = await post(`/invoice`, { invoice, user }, auth(cookies)); - redirect(307, `/${user.username}/invoice/${id}`); -} diff --git a/src/routes/(app)/[username]/card/[serial]/+page.server.ts b/src/routes/(app)/[username]/card/[serial]/+page.server.ts deleted file mode 100644 index 945eee30..00000000 --- a/src/routes/(app)/[username]/card/[serial]/+page.server.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { auth, get } from "$lib/utils"; -import { redirect } from "@sveltejs/kit"; - -export let load = async ({ cookies, params }) => { - let { serial } = params; - let fund; - try { - fund = await get(`/fund/${serial}`, auth(cookies)); - } catch (e) { - console.log(e); - } - - if (fund) redirect(307, `/fund/${serial}`); - - return params; -}; diff --git a/src/routes/(app)/[username]/card/[serial]/+page.svelte b/src/routes/(app)/[username]/card/[serial]/+page.svelte deleted file mode 100644 index 1d11ebee..00000000 --- a/src/routes/(app)/[username]/card/[serial]/+page.svelte +++ /dev/null @@ -1,36 +0,0 @@ -<script> - import Card from "$comp/Card.svelte"; - import Icon from "$comp/Icon.svelte"; - export let data; - let { serial } = data; - let balance = 0; -</script> - -<div class="space-y-5"> - <div class="relative flex justify-center gap-2"> - <h1 class="text-2xl md:text-3xl font-semibold my-auto">Card {serial}</h1> - </div> - <div class="flex justify-center"> - <a href={`/send/pot/${serial}`}> - <button - class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60 bg-black text-white justify-center gap-2" - > - <svg - xmlns="http://www.w3.org/2000/svg" - class="invert text-black peer-placeholder-shown:text-gray-300 h-6 w-6 my-auto" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - > - <path - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="2" - d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" - /> - </svg> - <div class="my-auto">Add Funds</div> - </button> - </a> - </div> -</div> diff --git a/src/routes/(app)/[username]/customers/+page.svelte b/src/routes/(app)/[username]/customers/+page.svelte deleted file mode 100644 index e69de29b..00000000 --- a/src/routes/(app)/[username]/customers/+page.svelte +++ /dev/null diff --git a/src/routes/(app)/[username]/funds/+page.server.ts b/src/routes/(app)/[username]/funds/+page.server.ts deleted file mode 100644 index e69de29b..00000000 --- a/src/routes/(app)/[username]/funds/+page.server.ts +++ /dev/null diff --git a/src/routes/(app)/[username]/funds/+page.svelte b/src/routes/(app)/[username]/funds/+page.svelte deleted file mode 100644 index 25686e86..00000000 --- a/src/routes/(app)/[username]/funds/+page.svelte +++ /dev/null @@ -1,52 +0,0 @@ -<script> - import Avatar from "$comp/Avatar.svelte"; - import Icon from "$comp/Icon.svelte"; - import { t } from "$lib/translations"; - - export let data; - - let { funds } = data; -</script> - -<div class="mt-24 mb-20"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-10"> - Funds - </h1> - - <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5"> - <div class="text-base"> - <div class="grid grid-cols-3 border-b h-24 hover:bg-gray-100 px-4"> - <div class="whitespace-nowrap my-auto"> - <div class="text-secondary" /> - </div> - - <div class="flex my-auto"> - <div class="text-secondary flex"> - <div class="my-auto mr-1"> - <img src="/images/moneypot.png" class="w-12" alt="Pot" /> - </div> - - <div class="my-auto">Pot</div> - </div> - </div> - - <div class="text-secondary text-right text-sm my-auto"> - <div /> - </div> - </div> - </div> - - <button - class="ml-auto rounded-full border py-2 px-4 w-36 hover:opacity-80 flex mx-auto" - > - <Icon icon="plus" style="opacity-50 mr-2 my-auto" /> - <div class="my-auto">{$t("payments.create")}</div> - </button> - </div> -</div> - -<style> - .active * { - @apply bg-black text-white border-black; - } -</style> diff --git a/src/routes/(app)/[username]/map/+page.server.ts b/src/routes/(app)/[username]/map/+page.server.ts deleted file mode 100644 index 616d28f6..00000000 --- a/src/routes/(app)/[username]/map/+page.server.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { get } from "$lib/utils"; - -// export const prerender = true; -export let load = async () => { - let data = { locations: [] }; - - try { - data = await get("/locations"); - } catch (e) {} - - return data; -}; diff --git a/src/routes/(app)/[username]/map/+page.svelte b/src/routes/(app)/[username]/map/+page.svelte deleted file mode 100644 index bfa115e4..00000000 --- a/src/routes/(app)/[username]/map/+page.svelte +++ /dev/null @@ -1,8 +0,0 @@ -<script> - import LocationsMap from "$comp/LocationsMap.svelte"; - export let data; - - let { locations } = data; -</script> - -<LocationsMap {locations} /> diff --git a/src/routes/(app)/[username]/reset/+server.ts b/src/routes/(app)/[username]/reset/+server.ts deleted file mode 100644 index f7dba02c..00000000 --- a/src/routes/(app)/[username]/reset/+server.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { json } from "@sveltejs/kit"; -import { auth, post } from "$lib/utils"; - -export async function POST({ cookies, request, params }) { - let { username } = params; - let r = await request.json(); - let { password } = r; - let result = await post("/reset", { password, username }, auth(cookies)); - return json(result); -} diff --git a/src/routes/(app)/[username]/account/setup/+page.svelte b/src/routes/(app)/account/setup/+page.svelte index 9636ff2a..5a15316a 100644 --- a/src/routes/(app)/[username]/account/setup/+page.svelte +++ b/src/routes/(app)/account/setup/+page.svelte @@ -42,7 +42,7 @@ </div> <div> - <a href={`/${user.username}/account/setup/step2`} class="contents"> + <a href={`/account/setup/step2`} class="contents"> <button type="button" class="bg-black text-white w-full px-5 py-6 text-xl rounded-2xl font-bold" diff --git a/src/routes/(app)/[username]/account/setup/step2/+page.svelte b/src/routes/(app)/account/setup/step2/+page.svelte index 8169ce06..8169ce06 100644 --- a/src/routes/(app)/[username]/account/setup/step2/+page.svelte +++ b/src/routes/(app)/account/setup/step2/+page.svelte diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte index c61a2e45..214bf5b3 100644 --- a/src/routes/(app)/admin/+page.svelte +++ b/src/routes/(app)/admin/+page.svelte @@ -1,7 +1,7 @@ <script> import { post } from "$lib/utils"; export let data; - let reset = (username) => post(`/${username}/reset`, { password }); + let reset = (username) => post(`/reset`, { password }); let { users } = data; let password; </script> diff --git a/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte b/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte index 679fbe76..89de4b58 100644 --- a/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte +++ b/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte @@ -1,5 +1,4 @@ <script> - import AppHeader from "$comp/AppHeader.svelte"; import { copy, sats, f, s } from "$lib/utils"; import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; diff --git a/src/routes/(app)/fund/[id]/+page.server.ts b/src/routes/(app)/fund/[id]/+page.server.ts index e553b1b4..6fd3af68 100644 --- a/src/routes/(app)/fund/[id]/+page.server.ts +++ b/src/routes/(app)/fund/[id]/+page.server.ts @@ -15,7 +15,7 @@ export const actions = { if (user) { await post("/redeem", params, auth(cookies)); - redirect(307, `/${user.username}/payments`); + redirect(307, `/payments`); } redirect(307, "/register"); diff --git a/src/routes/(app)/fund/[id]/sweep/+page.svelte b/src/routes/(app)/fund/[id]/sweep/+page.svelte index 4a48edf8..e142f00d 100644 --- a/src/routes/(app)/fund/[id]/sweep/+page.svelte +++ b/src/routes/(app)/fund/[id]/sweep/+page.svelte @@ -32,7 +32,7 @@ </h3> </div> -<a href={`/${user.username}/payments`}> +<a href={`/payments`}> <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> </a> diff --git a/src/routes/(app)/[username]/generate/+page.svelte b/src/routes/(app)/generate/+page.svelte index 767b7545..49d75dc6 100644 --- a/src/routes/(app)/[username]/generate/+page.svelte +++ b/src/routes/(app)/generate/+page.svelte @@ -28,7 +28,7 @@ try { user.pin = $pin; - await post(`/${user.username}/generate`, user); + await post(`/generate`, user); goto($loginRedirect || `/${user.username}`, { invalidateAll: true }); } catch (e) { $pin = ""; diff --git a/src/routes/(app)/[username]/generate/+server.ts b/src/routes/(app)/generate/+server.ts index 5a442982..5a442982 100644 --- a/src/routes/(app)/[username]/generate/+server.ts +++ b/src/routes/(app)/generate/+server.ts diff --git a/src/routes/(app)/[username]/[...account]/receive/[...param]/+page.server.ts b/src/routes/(app)/invoice/+page.server.ts index d9614a1c..83127457 100644 --- a/src/routes/(app)/[username]/[...account]/receive/[...param]/+page.server.ts +++ b/src/routes/(app)/invoice/+page.server.ts @@ -1,5 +1,5 @@ -import { error, redirect } from "@sveltejs/kit"; import { auth, post } from "$lib/utils"; +import { error, redirect } from "@sveltejs/kit"; import type { Invoice } from "$lib/types"; export let load = async ({ cookies, params, parent }) => { @@ -24,6 +24,6 @@ export let load = async ({ cookies, params, parent }) => { let { id } = invoice; if (invoice.memoPrompt && !invoice.memo) { - redirect(307, `/${user.username}/invoice/${id}/memo`); - } else redirect(307, `/${user.username}/invoice/${id}`); + redirect(307, `/invoice/${id}/memo`); + } else redirect(307, `/invoice/${id}`); }; diff --git a/src/routes/(app)/[username]/address/+page.svelte b/src/routes/(app)/invoice/+page.svelte index e69de29b..e69de29b 100644 --- a/src/routes/(app)/[username]/address/+page.svelte +++ b/src/routes/(app)/invoice/+page.svelte diff --git a/src/routes/(app)/[username]/invoice/+server.ts b/src/routes/(app)/invoice/+server.ts index 5e3d0300..5e3d0300 100644 --- a/src/routes/(app)/[username]/invoice/+server.ts +++ b/src/routes/(app)/invoice/+server.ts diff --git a/src/routes/(app)/[username]/invoice/[id]/+layout.server.ts b/src/routes/(app)/invoice/[id]/+layout.server.ts index 41554c9f..e7144b15 100644 --- a/src/routes/(app)/[username]/invoice/[id]/+layout.server.ts +++ b/src/routes/(app)/invoice/[id]/+layout.server.ts @@ -26,10 +26,7 @@ export async function load({ depends, params, url, parent }) { (!amount && (pending || received)) || (amount > 0 && (pending >= amount || received >= amount)); if (paid && !url.pathname.endsWith("paid")) { - redirect( - 307, - `/${params.username}/invoice/${id}/paid` + - (options ? "?options=true" : "") + redirect( 307, `/invoice/${id}/paid` + (options ? "?options=true" : "") ); } diff --git a/src/routes/(app)/[username]/invoice/[id]/+layout.svelte b/src/routes/(app)/invoice/[id]/+layout.svelte index 4fa864ce..4fa864ce 100644 --- a/src/routes/(app)/[username]/invoice/[id]/+layout.svelte +++ b/src/routes/(app)/invoice/[id]/+layout.svelte diff --git a/src/routes/(app)/[username]/invoice/[id]/+page.server.ts b/src/routes/(app)/invoice/[id]/+page.server.ts index a57efa64..a57efa64 100644 --- a/src/routes/(app)/[username]/invoice/[id]/+page.server.ts +++ b/src/routes/(app)/invoice/[id]/+page.server.ts diff --git a/src/routes/(app)/[username]/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte index 1f2bbb51..c4810889 100644 --- a/src/routes/(app)/[username]/invoice/[id]/+page.svelte +++ b/src/routes/(app)/invoice/[id]/+page.svelte @@ -93,7 +93,7 @@ let setType = async (type) => { invoice.type = type; - ({ id } = await post(`/${username}/invoice`, { + ({ id } = await post(`/invoice`, { invoice, user: { username, currency }, })); @@ -107,7 +107,7 @@ amount = newAmount; invoice.amount = newAmount; invoice.tip = 0; - ({ id } = await post(`/${username}/invoice`, { + ({ id } = await post(`/invoice`, { invoice, user: { username, currency }, })); @@ -296,49 +296,56 @@ {/if} </div> - <!-- <div --> - <!-- class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20" --> - <!-- > --> - <!-- <div --> - <!-- class="relative top-1/3 mx-auto p-12 border w-96 shadow-lg rounded-md bg-white space-y-5" --> - <!-- > --> - <!-- <form submit={setAmount}> --> - <!-- <Numpad --> - <!-- bind:amount={newAmount} --> - <!-- bind:currency --> - <!-- bind:rate --> - <!-- bind:fiat --> - <!-- bind:submit --> - <!-- /> --> - <!-- <div class="w-full flex flex-wrap gap-2"> --> - <!-- <button --> - <!-- type="submit" --> - <!-- on:click={setAmount} --> - <!-- class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto bg-black text-white w-full" --> - <!-- > --> - <!-- <div class="my-auto">Ok</div> --> - <!-- </button> --> - <!-- <button --> - <!-- bind:this={submit} --> - <!-- type="button" --> - <!-- class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto w-full" --> - <!-- on:click={toggleAmount} --> - <!-- on:keydown={toggleAmount} --> - <!-- > --> - <!-- <div class="my-auto">Cancel</div> --> - <!-- </button> --> - <!-- </div> --> - <!-- </form> --> - <!-- --> - <!-- <div class="flex justify-between items-center"> --> - <!-- <span class="font-bold">{$t("payments.amountPrompt")}</span> --> - <!-- <Toggle id="notify" bind:value={$amountPrompt} /> --> - <!-- </div> --> - <!-- </div> --> - <!-- </div> --> +{#if settingAmount} + <div + class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50" + > + <div + class="relative mx-auto p-12 border w-96 shadow-lg rounded-md bg-white space-y-5 top-10" + > + <form submit={setAmount}> + <Numpad + bind:amount={newAmount} + bind:currency + bind:rate + bind:fiat + bind:submit + /> + <div class="w-full flex flex-wrap gap-2"> + <button + type="submit" + on:click={setAmount} + class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto bg-black text-white w-full" + > + <div class="my-auto">Ok</div> + </button> + <button + bind:this={submit} + type="button" + class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto w-full" + on:click={toggleAmount} + on:keydown={toggleAmount} + > + <div class="my-auto">Cancel</div> + </button> + </div> + </form> + + <div class="flex justify-between items-center"> + <span class="font-bold">{$t("payments.amountPrompt")}</span> + <Toggle id="notify" bind:value={$amountPrompt} /> + </div> + </div> + </div> +{/if} <style> .invoice { view-transition-name: invoice; } + + .clip-qr { + @apply overflow-hidden; + clip-path: inset(5%); + } </style> diff --git a/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.ts b/src/routes/(app)/invoice/[id]/memo/+page.server.ts index 58d56018..24dec1af 100644 --- a/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.ts +++ b/src/routes/(app)/invoice/[id]/memo/+page.server.ts @@ -4,7 +4,7 @@ import { redirect } from "@sveltejs/kit"; export async function load({ parent, params }) { let { invoice } = await parent(); if (!invoice.amount) { - redirect(307, `/${params.username}/invoice/${invoice.id}`); + redirect(307, `/invoice/${invoice.id}`); } } diff --git a/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte b/src/routes/(app)/invoice/[id]/memo/+page.svelte index 4d23ff19..4d23ff19 100644 --- a/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte +++ b/src/routes/(app)/invoice/[id]/memo/+page.svelte diff --git a/src/routes/(app)/[username]/invoice/[id]/paid/+page.svelte b/src/routes/(app)/invoice/[id]/paid/+page.svelte index 700ac972..df05f12b 100644 --- a/src/routes/(app)/[username]/invoice/[id]/paid/+page.svelte +++ b/src/routes/(app)/invoice/[id]/paid/+page.svelte @@ -76,7 +76,7 @@ {/if} </div> -<a href={`/${user.username}/receive`}> +<a href={`/receive`}> <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> </a> diff --git a/src/routes/(app)/[username]/invoice/[id]/tip/+page.server.ts b/src/routes/(app)/invoice/[id]/tip/+page.server.ts index b81e2364..8417de91 100644 --- a/src/routes/(app)/[username]/invoice/[id]/tip/+page.server.ts +++ b/src/routes/(app)/invoice/[id]/tip/+page.server.ts @@ -4,7 +4,7 @@ import { redirect } from "@sveltejs/kit"; export async function load({ parent, params }) { let { invoice } = await parent(); if (!invoice.amount) - redirect(307, `/${params.username}/invoice/${invoice.id}`); + redirect(307, `/invoice/${invoice.id}`); } export const actions = { diff --git a/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte b/src/routes/(app)/invoice/[id]/tip/+page.svelte index 35b24bf1..35b24bf1 100644 --- a/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte +++ b/src/routes/(app)/invoice/[id]/tip/+page.svelte diff --git a/src/routes/(app)/[username]/invoice/sent/+page.svelte b/src/routes/(app)/invoice/sent/+page.svelte index b95bc85e..b95bc85e 100644 --- a/src/routes/(app)/[username]/invoice/sent/+page.svelte +++ b/src/routes/(app)/invoice/sent/+page.svelte diff --git a/src/routes/(app)/[username]/items/[id]/+page.server.ts b/src/routes/(app)/items/[id]/+page.server.ts index 67cebd93..67cebd93 100644 --- a/src/routes/(app)/[username]/items/[id]/+page.server.ts +++ b/src/routes/(app)/items/[id]/+page.server.ts diff --git a/src/routes/(app)/[username]/items/[id]/+page.svelte b/src/routes/(app)/items/[id]/+page.svelte index 65720350..65720350 100644 --- a/src/routes/(app)/[username]/items/[id]/+page.svelte +++ b/src/routes/(app)/items/[id]/+page.svelte diff --git a/src/routes/(app)/[username]/items/create/+page.server.ts b/src/routes/(app)/items/create/+page.server.ts index 2e006a3e..2e006a3e 100644 --- a/src/routes/(app)/[username]/items/create/+page.server.ts +++ b/src/routes/(app)/items/create/+page.server.ts diff --git a/src/routes/(app)/[username]/items/create/+page.svelte b/src/routes/(app)/items/create/+page.svelte index b82889c9..b82889c9 100644 --- a/src/routes/(app)/[username]/items/create/+page.svelte +++ b/src/routes/(app)/items/create/+page.svelte diff --git a/src/routes/(app)/ln/[lnurl]/+page.server.ts b/src/routes/(app)/ln/[lnurl]/+page.server.ts index d1b1b86e..c078ae8e 100644 --- a/src/routes/(app)/ln/[lnurl]/+page.server.ts +++ b/src/routes/(app)/ln/[lnurl]/+page.server.ts @@ -70,6 +70,6 @@ export const actions = { let c = callback.includes("?") ? "&" : "?"; await fetch(`${callback}${c}k1=${k1}&pr=${pr}`).then((r) => r.json()); - redirect(307, `/${username}/payments`); + redirect(307, `/payments`); }, }; diff --git a/src/routes/(app)/ln/withdrawal/sent/+page.svelte b/src/routes/(app)/ln/withdrawal/sent/+page.svelte index c1a2bdb2..90814960 100644 --- a/src/routes/(app)/ln/withdrawal/sent/+page.svelte +++ b/src/routes/(app)/ln/withdrawal/sent/+page.svelte @@ -19,7 +19,7 @@ <h1 class="text-3xl md:text-4xl font-bold mb-6">Request Sent!</h1> </div> -<a href={`/${user.username}/payments`}> +<a href={`/payments`}> <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> </a> diff --git a/src/routes/(app)/login/+page.svelte b/src/routes/(app)/login/+page.svelte deleted file mode 100644 index 61ea23b7..00000000 --- a/src/routes/(app)/login/+page.svelte +++ /dev/null @@ -1,188 +0,0 @@ -<script> - import { onMount } from "svelte"; - import { applyAction, deserialize } from "$app/forms"; - import { tick } from "svelte"; - import { fly } from "svelte/transition"; - import { enhance } from "$app/forms"; - import Pin from "$comp/Pin.svelte"; - import Icon from "$comp/Icon.svelte"; - import Spinner from "$comp/Spinner.svelte"; - import { focus, fail } from "$lib/utils"; - import { password, pin, loginRedirect } from "$lib/store"; - import { t } from "$lib/translations"; - import { page } from "$app/stores"; - import { generate } from "$lib/nostr"; - import { invalidateAll } from "$app/navigation"; - - onMount(() => { - $pin = undefined; - localStorage.clear(); - sessionStorage.clear(); - - let lang = $page.url.searchParams.get("lang"); - if (lang) document.cookie = `lang=${lang} ;`; - }); - - export let form; - - let token, formElement; - let code = []; - let redirect; - - $password = undefined; - - $: need2fa = form?.message === "2fa"; - let cancel = () => (need2fa = false); - $: if (form?.message === "2fa" && form.token === token) token = ""; - - let username, email, btn; - - $: update(form); - let update = (form) => form && ({ username, password: $password } = form); - - $: token && token?.length === 6 && tick().then(() => btn.click()); - - let revealPassword = false; - - let loading; - async function handleSubmit(e) { - loading = true; - - let data = new FormData(this); - let user = Object.fromEntries(data); - await generate(user); - - for (let k in user) { - data.set(k, user[k]); - } - - const response = await fetch("/login", { - method: "POST", - body: data, - }); - - const result = deserialize(await response.text()); - - if (result.type === "success") { - await invalidateAll(); - } - - applyAction(result); - loading = false; - } -</script> - -{#if need2fa} - <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> -{/if} - -<div class="pt-10"> - <div class="w-[243px] mx-auto mb-10"> - <a href="/"> - <Icon icon="logo" /> - </a> - </div> - - <div class="flex justify-center items-center"> - <div - class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" - > - <h1 class="text-2xl font-bold text-center">{$t("login.signIn")}</h1> - - {#if form?.error} - <div class="text-red-600 text-center" in:fly> - {form.error} - </div> - {/if} - - <form - class="space-y-5" - on:submit|preventDefault={handleSubmit} - method="POST" - > - <input - type="hidden" - name="loginRedirect" - value={$loginRedirect || $page.url.searchParams.get("redirect")} - /> - <input type="hidden" name="token" value={token} /> - - <div> - <label for="username" class="font-semibold" - >{$t("login.username")}</label - > - <input - name="username" - type="text" - required - class="bg-primary" - bind:value={username} - use:focus - autocapitalize="none" - /> - </div> - - <div class="relative"> - <label for="password" class="block font-semibold" - >{$t("login.password")}</label - > - {#if revealPassword} - <input - name="password" - type="text" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {:else} - <input - name="password" - type="password" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {/if} - <button - type="button" - on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-10" - > - <Icon icon={revealPassword ? "eye" : "eye-off"} /> - </button> - </div> - - <div class="flex justify-end items-center"> - <a href="/forgot" class="underline underline-offset-4 text-black" - >{$t("login.forgotUserOrPassword")}</a - > - </div> - - <button - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" - disabled={loading} - bind:this={btn} - > - {#if loading} - <Spinner /> - {:else} - {$t("login.signIn")} - {/if} - </button> - </form> - - <p class="text-secondary text-center font-medium"> - {$t("login.noAccount")} - <a - href={"/register"} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" - > - {$t("login.register")} - </a> - </p> - </div> - </div> -</div> diff --git a/src/routes/(app)/[username]/messages/+page.server.ts b/src/routes/(app)/messages/+page.server.ts index 94659621..94659621 100644 --- a/src/routes/(app)/[username]/messages/+page.server.ts +++ b/src/routes/(app)/messages/+page.server.ts diff --git a/src/routes/(app)/[username]/messages/+page.svelte b/src/routes/(app)/messages/+page.svelte index 4738ea2c..547a1f21 100644 --- a/src/routes/(app)/[username]/messages/+page.svelte +++ b/src/routes/(app)/messages/+page.svelte @@ -71,7 +71,7 @@ <div class="relative"> {#each latest as { content, pubkey, author, recipient }} {@const user = author.id === user.id ? recipient : author} - <a href={`/${subject.username}/messages/${user.username}`}> + <a href={`/messages/${user.username}`}> <div class="flex hover:bg-gray-100 p-4 rounded-2xl"> <div class="my-auto"> <Avatar {user} size={"20"} disabled={true} /> diff --git a/src/routes/(app)/[username]/messages/[recipient]/+page.server.ts b/src/routes/(app)/messages/[recipient]/+page.server.ts index 6be9f6ec..6be9f6ec 100644 --- a/src/routes/(app)/[username]/messages/[recipient]/+page.server.ts +++ b/src/routes/(app)/messages/[recipient]/+page.server.ts diff --git a/src/routes/(app)/[username]/messages/[recipient]/+page.svelte b/src/routes/(app)/messages/[recipient]/+page.svelte index 98638389..98638389 100644 --- a/src/routes/(app)/[username]/messages/[recipient]/+page.svelte +++ b/src/routes/(app)/messages/[recipient]/+page.svelte diff --git a/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts b/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts index e9a0ec9e..7ccc23b0 100644 --- a/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts +++ b/src/routes/(app)/pay/[username]/[...amount]/+page.server.ts @@ -29,7 +29,7 @@ export async function load({ cookies, params, parent }) { auth(cookies) ); - redirect(307, `/${username}/invoice/${id}`); + redirect(307, `/invoice/${id}`); } return { amount, rate, subject }; diff --git a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte index 1652952a..f45218ea 100644 --- a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte +++ b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte @@ -3,7 +3,6 @@ import { goto } from "$app/navigation"; import { pin } from "$lib/store"; import { enhance } from "$app/forms"; - import AppHeader from "$comp/AppHeader.svelte"; import Avatar from "$comp/Avatar.svelte"; import Icon from "$comp/Icon.svelte"; import Numpad from "$comp/Numpad.svelte"; @@ -33,7 +32,7 @@ rate = fiat ? (sats * amountFiat) / amount : r; let id; - ({ id, hash } = await post(`/${subject.username}/invoice`, { + ({ id, hash } = await post(`/invoice`, { invoice: { amount, rate: rates[subject.currency], @@ -56,8 +55,6 @@ }; </script> -<AppHeader {data} /> - {#if form?.message} <div class="text-red-600 text-center"> {form.message} diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index ea07be14..9a278049 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -96,7 +96,7 @@ }); </script> -<a href={`/${username}/payments`}> +<a href={`/payments`}> <button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80"> <Icon icon="arrow-left" style="w-10" /> </button> diff --git a/src/routes/(app)/[username]/[...account]/payments/[...page]/+page.server.ts b/src/routes/(app)/payments/[...page]/+page.server.ts index c2cd5683..c2cd5683 100644 --- a/src/routes/(app)/[username]/[...account]/payments/[...page]/+page.server.ts +++ b/src/routes/(app)/payments/[...page]/+page.server.ts diff --git a/src/routes/(app)/[username]/[...account]/payments/[...page]/+page.svelte b/src/routes/(app)/payments/[...page]/+page.svelte index 1efdc2ec..b7ea7b6e 100644 --- a/src/routes/(app)/[username]/[...account]/payments/[...page]/+page.svelte +++ b/src/routes/(app)/payments/[...page]/+page.svelte @@ -65,7 +65,7 @@ : $page.url.pathname; let csv = async () => { - let url = `/${user.username}/payments`; + let url = `/payments`; if (start) url += `/${start}`; if (end) url += `/${end}`; @@ -138,7 +138,7 @@ {#each presets as { start, end, title }, i} <a class:active={selection === i} - href={`/${user.username}/payments/${getUnixTime(start) + "/"}1`} + href={`/payments/${getUnixTime(start) + "/"}1`} > <button class="text-sm md:text-lg rounded-full border py-2 px-4 hover:opacity-80 min-w-[72px]" diff --git a/src/routes/(app)/[username]/[...account]/payments/[...page]/+server.ts b/src/routes/(app)/payments/[...page]/+server.ts index a81faaf3..a81faaf3 100644 --- a/src/routes/(app)/[username]/[...account]/payments/[...page]/+server.ts +++ b/src/routes/(app)/payments/[...page]/+server.ts diff --git a/src/routes/(app)/receive/[...token]/+page.svelte b/src/routes/(app)/receive/[...token]/+page.svelte index 2fd4b879..7ff93fa9 100644 --- a/src/routes/(app)/receive/[...token]/+page.svelte +++ b/src/routes/(app)/receive/[...token]/+page.svelte @@ -5,7 +5,6 @@ import { tick } from "svelte"; import { browser } from "$app/environment"; import { t } from "$lib/translations"; - import AppHeader from "$comp/AppHeader.svelte"; import Avatar from "$comp/Avatar.svelte"; import Icon from "$comp/Icon.svelte"; import Spinner from "$comp/Spinner.svelte"; @@ -30,7 +29,6 @@ <svelte:window bind:innerWidth={w} /> -<AppHeader {data} /> <div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> {$t("payments.voucher")} diff --git a/src/routes/(app)/register/+page.svelte b/src/routes/(app)/register/+page.svelte deleted file mode 100644 index 0a761228..00000000 --- a/src/routes/(app)/register/+page.svelte +++ /dev/null @@ -1,314 +0,0 @@ -<script> - import punks from "$lib/punks"; - import { upload } from "$lib/upload"; - import { afterNavigate, invalidateAll } from "$app/navigation"; - import { applyAction, deserialize } from "$app/forms"; - import { tick } from "svelte"; - import { fly } from "svelte/transition"; - import { enhance } from "$app/forms"; - - import Pin from "$comp/Pin.svelte"; - import Icon from "$comp/Icon.svelte"; - import Spinner from "$comp/Spinner.svelte"; - - import { focus, fail } from "$lib/utils"; - import { avatar, password, loginRedirect } from "$lib/store"; - import { t } from "$lib/translations"; - import { page } from "$app/stores"; - import { generate } from "$lib/nostr"; - import { - NumberDictionary, - uniqueNamesGenerator, - colors, - adjectives, - animals, - } from "unique-names-generator"; - - export let form; - export let data; - - $: data && ($avatar = undefined); - let username; - let { index } = data; - - let cleared; - let clear = () => { - if (!cleared) { - cleared = true; - username = ""; - $password = ""; - revealPassword = false; - } - }; - - let refresh = async () => { - username = uniqueNamesGenerator({ - dictionaries: [animals, NumberDictionary.generate({ min: 10, max: 99 })], - length: 2, - separator: "", - }); - - $password = uniqueNamesGenerator({ - dictionaries: [colors, NumberDictionary.generate({ min: 100, max: 999 })], - length: 2, - separator: "", - }); - - revealPassword = true; - }; - - afterNavigate(async () => { - try { - await invalidateAll(); - } catch (e) { - console.log(e); - } - }); - - let token, formElement; - let code = []; - let redirect; - - $: need2fa = form?.message === "2fa"; - let cancel = () => (need2fa = false); - $: if (form?.message === "2fa" && form.token === token) token = ""; - - let email, btn; - - $: update(form); - let update = (form) => form && ({ username, password: $password } = form); - - $: token && token?.length === 6 && tick().then(() => btn.click()); - - let revealPassword; - - let loading; - async function handleSubmit(e) { - loading = true; - - let data = new FormData(this); - let user = Object.fromEntries(data); - await generate(user); - - for (let k in user) { - data.set(k, user[k]); - } - - data.set("profile", punks[index]); - if ($avatar) { - try { - let { hash } = JSON.parse( - await upload($avatar.file, $avatar.type, $avatar.progress, token) - ); - - data.set("profile", hash); - await fetch(`/api/public/${hash}.webp`, { - cache: "reload", - mode: "no-cors", - }); - } catch (e) { - console.log("problem uploading avatar", e); - } - } - - const response = await fetch("/register", { - method: "POST", - body: data, - }); - - const result = deserialize(await response.text()); - - if (result.type === "success") { - await invalidateAll(); - } - - applyAction(result); - loading = false; - } - - let avatarInput; - $: src = `/api/public/${punks[index]}.webp`; - let decr = () => (index = index <= 0 ? 63 : index - 1); - let incr = () => (index = index >= 63 ? 0 : index + 1); - let selectAvatar = () => avatarInput.click(); - - let progress; - let handleFile = async ({ target }) => { - let type = "profile"; - let file = target.files[0]; - if (!file) return; - - if (file.size > 10000000) form.error = "File too large"; - $avatar = { file, type, progress }; - - var reader = new FileReader(); - reader.onload = async (e) => { - src = e.target.result; - }; - - reader.readAsDataURL(file); - }; -</script> - -{#if need2fa} - <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> -{/if} - -<div class="pt-4"> - <div class="w-[243px] mx-auto"> - <a href="/"> - <Icon icon="logo" /> - </a> - </div> - - <div class="flex justify-center items-center"> - <div - class="shadow-xl rounded-3xl p-4 pt-0 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" - > - <input - type="file" - class="hidden" - bind:this={avatarInput} - on:change={(e) => handleFile(e, "profile")} - /> - - <div class="relative"> - <button - class="absolute w-8 h-12 left-12 bg-white rounded top-12" - on:click={decr} - > - <Icon icon="chevron-left" style="w-8 " /> - </button> - <button - class="block relative w-32 mx-auto" - on:click={selectAvatar} - > - <button - class="w-32 h-32 rounded-full border-4 border-white overflow-hidden flex mx-auto relative" - > - <img - {src} - class="w-full h-full object-cover object-center overflow-hidden" - alt={username} - /> - </button> - <button - class="absolute bg-white rounded-full p-2 mx-auto right-0 bottom-0 z-10 bg-opacity-80" - > - <Icon icon="upload" style="w-8" /> - </button> - </button> - <button - class="absolute w-8 h-12 right-12 bg-white rounded top-12" - on:click={incr} - > - <Icon icon="chevron-left" style="w-8 rotate-180" /> - </button> - </div> - - {#if form?.error} - <div class="text-red-600 text-center" in:fly> - {form.error} - </div> - {/if} - - <form - class="space-y-5" - on:submit|preventDefault={handleSubmit} - method="POST" - > - <input - type="hidden" - name="loginRedirect" - value={$loginRedirect || $page.url.searchParams.get("redirect")} - /> - <input type="hidden" name="token" value={token} /> - - <div class="relative"> - <label for="username" class="font-semibold" - >{$t("login.username")}</label - > - <input - use:focus - name="username" - type="text" - required - class="bg-primary" - bind:value={username} - on:focus={clear} - autocapitalize="none" - /> - <button - tabindex="-1" - type="button" - on:click={refresh} - class="absolute right-0 top-4" - > - <Icon icon="random" style="w-10 m-4" /> - </button> - </div> - - <div class="relative"> - <label for="password" class="block font-semibold" - >{$t("login.password")}</label - > - {#if revealPassword} - <input - name="password" - type="text" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {:else} - <input - name="password" - type="password" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - on:focus={clear} - /> - {/if} - <button - type="button" - tabindex="-1" - on:click={() => (revealPassword = !revealPassword)} - class="absolute right-0 top-4" - > - <Icon icon={revealPassword ? "eye" : "eye-off"} style="m-6" /> - </button> - </div> - - <p class="text-secondary text-sm"> - {$t("login.passwordRecommendation")} - </p> - - <button - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" - disabled={loading} - bind:this={btn} - > - {#if loading} - <Spinner /> - {:else} - {$t("login.register")} - {/if} - </button> - </form> - - <p class="text-secondary text-center font-medium"> - {$t("login.haveAccount")} - <a - href={"/login"} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" - > - {$t("login.signIn")} - </a> - </p> - </div> - </div> -</div> diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte index 780f70c1..d1b6cc23 100644 --- a/src/routes/(app)/send/[...text]/+page.svelte +++ b/src/routes/(app)/send/[...text]/+page.svelte @@ -5,7 +5,6 @@ import { tick } from "svelte"; import { browser } from "$app/environment"; import { t } from "$lib/translations"; - import AppHeader from "$comp/AppHeader.svelte"; import Avatar from "$comp/Avatar.svelte"; import Icon from "$comp/Icon.svelte"; import Spinner from "$comp/Spinner.svelte"; @@ -31,7 +30,6 @@ <svelte:window bind:innerWidth={w} /> -<AppHeader {data} /> <div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> {$t("payments.send")} diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.ts b/src/routes/(app)/send/invoice/[id]/+page.server.ts index ed0198cf..fa7d28dd 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.server.ts +++ b/src/routes/(app)/send/invoice/[id]/+page.server.ts @@ -7,15 +7,15 @@ export async function load({ params: { id }, parent }) { let invoice = await get(`/invoice/${id}`); if (invoice.prompt && invoice.tip === null) - redirect(307, `/${invoice.user.username}/invoice/${id}/tip`); + redirect(307, `/invoice/${id}/tip`); if (invoice.memoPrompt && invoice.memo === null) - redirect(307, `/${invoice.user.username}/invoice/${id}/memo`); + redirect(307, `/invoice/${id}/memo`); if (invoice.user.username === user?.username) error(500, { message: "Cannot send to self" }); - if (!user) redirect(307, `/${invoice.user.username}/invoice/${id}`); + if (!user) redirect(307, `/invoice/${id}`); return { invoice, rates, user }; } diff --git a/src/routes/(app)/send/invoice/[id]/+page.svelte b/src/routes/(app)/send/invoice/[id]/+page.svelte index 81a2c521..75e4e75a 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.svelte +++ b/src/routes/(app)/send/invoice/[id]/+page.svelte @@ -52,7 +52,7 @@ let toggle = () => (submitting = !submitting); let external = async () => { - let { id } = await post(`/${recipient.username}/invoice`, { + let { id } = await post(`/invoice`, { invoice: { ...invoice, type: "lightning", @@ -62,7 +62,7 @@ user: { username: recipient.username }, }); - goto(`/${recipient.username}/invoice/${id}?options=true`, { + goto(`/invoice/${id}?options=true`, { invalidateAll: true, }); }; diff --git a/src/routes/(app)/sent/+page.svelte b/src/routes/(app)/sent/+page.svelte index 136bd395..12e13c41 100644 --- a/src/routes/(app)/sent/+page.svelte +++ b/src/routes/(app)/sent/+page.svelte @@ -43,7 +43,7 @@ </h3> </div> -<a href={`/${username}/payments`} use:focus> +<a href={`/payments`} use:focus> <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> </a> diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.server.ts b/src/routes/(app)/settings/[...tab]/+page.server.ts index 42639b38..42639b38 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.server.ts +++ b/src/routes/(app)/settings/[...tab]/+page.server.ts diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte b/src/routes/(app)/settings/[...tab]/+page.svelte index 12980291..c495a5cc 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte +++ b/src/routes/(app)/settings/[...tab]/+page.svelte @@ -216,7 +216,7 @@ class="font-bold flex justify-around items-center border-b pb-3 text-secondary" > {#each tabs.filter((t) => t.name !== "shopify") as { name, key }} - <a href={`/${user.username}/settings/${name}`}> + <a href={`/settings/${name}`}> <button type="button" class="hover:opacity-80" diff --git a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte b/src/routes/(app)/settings/[...tab]/_account.svelte index 8e3323c7..8e3323c7 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte +++ b/src/routes/(app)/settings/[...tab]/_account.svelte diff --git a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte b/src/routes/(app)/settings/[...tab]/_pos.svelte index 6a1c92a1..6a1c92a1 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte +++ b/src/routes/(app)/settings/[...tab]/_pos.svelte diff --git a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte b/src/routes/(app)/settings/[...tab]/_security.svelte index 6b44f830..6b44f830 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte +++ b/src/routes/(app)/settings/[...tab]/_security.svelte diff --git a/src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte b/src/routes/(app)/settings/[...tab]/_shopify.svelte index 0266fa9c..0266fa9c 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_shopify.svelte +++ b/src/routes/(app)/settings/[...tab]/_shopify.svelte diff --git a/src/routes/(app)/[username]/verify/[code]/+page.server.ts b/src/routes/(app)/verify/[code]/+page.server.ts index fec1a85c..66ef39ad 100644 --- a/src/routes/(app)/[username]/verify/[code]/+page.server.ts +++ b/src/routes/(app)/verify/[code]/+page.server.ts @@ -10,5 +10,5 @@ export let load = async ({ params: { code } }) => { return { error: "Verification failed" }; } - redirect(307, `/${user.username}/settings/account?verified=true`); + redirect(307, `/settings/account?verified=true`); }; diff --git a/src/routes/(app)/[username]/verify/[code]/+page.svelte b/src/routes/(app)/verify/[code]/+page.svelte index 1e099dae..1e099dae 100644 --- a/src/routes/(app)/[username]/verify/[code]/+page.svelte +++ b/src/routes/(app)/verify/[code]/+page.svelte diff --git a/src/routes/(static)/+layout.svelte b/src/routes/(static)/+layout.svelte index 13073d5a..4b350bd0 100644 --- a/src/routes/(static)/+layout.svelte +++ b/src/routes/(static)/+layout.svelte @@ -9,7 +9,7 @@ <SvelteToast options={{ reversed: true, intro: { y: 192 } }} /> <LandingHeader {user} /> -<main class="container flex px-10 md:px-40 mx-auto min-h-[600px] pb-20"> +<main class="container flex px-4 md:px-40 mx-auto min-h-[600px] py-28"> <slot /> </main> <Footer /> diff --git a/src/routes/(app)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts index fd7fec8c..fd7fec8c 100644 --- a/src/routes/(app)/login/+page.server.ts +++ b/src/routes/(static)/login/+page.server.ts diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte new file mode 100644 index 00000000..84e1ea89 --- /dev/null +++ b/src/routes/(static)/login/+page.svelte @@ -0,0 +1,171 @@ +<script> + import { onMount } from "svelte"; + import { applyAction, deserialize } from "$app/forms"; + import { tick } from "svelte"; + import { fly } from "svelte/transition"; + import { enhance } from "$app/forms"; + import Pin from "$comp/Pin.svelte"; + import Icon from "$comp/Icon.svelte"; + import Spinner from "$comp/Spinner.svelte"; + import { focus, fail } from "$lib/utils"; + import { password, pin, loginRedirect } from "$lib/store"; + import { t } from "$lib/translations"; + import { page } from "$app/stores"; + import { generate } from "$lib/nostr"; + import { invalidateAll } from "$app/navigation"; + + onMount(() => { + $pin = undefined; + localStorage.clear(); + sessionStorage.clear(); + + let lang = $page.url.searchParams.get("lang"); + if (lang) document.cookie = `lang=${lang} ;`; + }); + + export let form; + + let token, formElement; + let code = []; + let redirect; + + $password = undefined; + + $: need2fa = form?.message === "2fa"; + let cancel = () => (need2fa = false); + $: if (form?.message === "2fa" && form.token === token) token = ""; + + let username, email, btn; + + $: update(form); + let update = (form) => form && ({ username, password: $password } = form); + + $: token && token?.length === 6 && tick().then(() => btn.click()); + + let revealPassword = false; + + let loading; + async function handleSubmit(e) { + loading = true; + + let data = new FormData(this); + let user = Object.fromEntries(data); + await generate(user); + + for (let k in user) { + data.set(k, user[k]); + } + + const response = await fetch("/login", { + method: "POST", + body: data, + }); + + const result = deserialize(await response.text()); + + if (result.type === "success") { + await invalidateAll(); + } + + applyAction(result); + loading = false; + } +</script> + +{#if need2fa} + <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> +{/if} + +<div class="mx-auto md:shadow-xl rounded-3xl max-w-xl w-full md:w-[480px] md:p-8"> + <h1 class="text-2xl font-bold text-center">{$t("login.signIn")}</h1> + + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} + + <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <input + type="hidden" + name="loginRedirect" + value={$loginRedirect || $page.url.searchParams.get("redirect")} + /> + <input type="hidden" name="token" value={token} /> + + <div> + <label for="username" class="font-semibold">{$t("login.username")}</label> + <input + name="username" + type="text" + required + class="bg-primary" + bind:value={username} + use:focus + autocapitalize="none" + /> + </div> + + <div class="relative"> + <label for="password" class="block font-semibold" + >{$t("login.password")}</label + > + {#if revealPassword} + <input + name="password" + type="text" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {:else} + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {/if} + <button + type="button" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-5 top-10" + > + <Icon icon={revealPassword ? "eye" : "eye-off"} /> + </button> + </div> + + <div class="flex justify-end items-center"> + <a href="/forgot" class="underline underline-offset-4 text-black" + >{$t("login.forgotUserOrPassword")}</a + > + </div> + + <button + type="submit" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + disabled={loading} + bind:this={btn} + > + {#if loading} + <Spinner /> + {:else} + {$t("login.signIn")} + {/if} + </button> + + + <p class="text-secondary text-center font-medium"> + {$t("login.noAccount")} + <a + href={"/register"} + class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + > + {$t("login.register")} + </a> + </p> + </form> +</div> diff --git a/src/routes/(app)/register/+page.server.ts b/src/routes/(static)/register/+page.server.ts index 731530c4..731530c4 100644 --- a/src/routes/(app)/register/+page.server.ts +++ b/src/routes/(static)/register/+page.server.ts diff --git a/src/routes/(static)/register/+page.svelte b/src/routes/(static)/register/+page.svelte new file mode 100644 index 00000000..b6a4c44e --- /dev/null +++ b/src/routes/(static)/register/+page.svelte @@ -0,0 +1,292 @@ +<script> + import punks from "$lib/punks"; + import { upload } from "$lib/upload"; + import { afterNavigate, invalidateAll } from "$app/navigation"; + import { applyAction, deserialize } from "$app/forms"; + import { tick } from "svelte"; + import { fly } from "svelte/transition"; + import { enhance } from "$app/forms"; + + import Pin from "$comp/Pin.svelte"; + import Icon from "$comp/Icon.svelte"; + import Spinner from "$comp/Spinner.svelte"; + + import { focus, fail } from "$lib/utils"; + import { avatar, password, loginRedirect } from "$lib/store"; + import { t } from "$lib/translations"; + import { page } from "$app/stores"; + import { generate } from "$lib/nostr"; + import { + NumberDictionary, + uniqueNamesGenerator, + colors, + adjectives, + animals, + } from "unique-names-generator"; + + export let form; + export let data; + + $: data && ($avatar = undefined); + let username; + let { index } = data; + + let cleared; + let clear = () => { + if (!cleared) { + cleared = true; + username = ""; + $password = ""; + revealPassword = false; + } + }; + + let refresh = async () => { + username = uniqueNamesGenerator({ + dictionaries: [animals, NumberDictionary.generate({ min: 10, max: 99 })], + length: 2, + separator: "", + }); + + $password = uniqueNamesGenerator({ + dictionaries: [colors, NumberDictionary.generate({ min: 100, max: 999 })], + length: 2, + separator: "", + }); + + revealPassword = true; + }; + + afterNavigate(async () => { + try { + await invalidateAll(); + } catch (e) { + console.log(e); + } + }); + + let token, formElement; + let code = []; + let redirect; + + $: need2fa = form?.message === "2fa"; + let cancel = () => (need2fa = false); + $: if (form?.message === "2fa" && form.token === token) token = ""; + + let email, btn; + + $: update(form); + let update = (form) => form && ({ username, password: $password } = form); + + $: token && token?.length === 6 && tick().then(() => btn.click()); + + let revealPassword; + + let loading; + async function handleSubmit(e) { + loading = true; + + let data = new FormData(this); + let user = Object.fromEntries(data); + await generate(user); + + for (let k in user) { + data.set(k, user[k]); + } + + data.set("profile", punks[index]); + if ($avatar) { + try { + let { hash } = JSON.parse( + await upload($avatar.file, $avatar.type, $avatar.progress, token) + ); + + data.set("profile", hash); + await fetch(`/api/public/${hash}.webp`, { + cache: "reload", + mode: "no-cors", + }); + } catch (e) { + console.log("problem uploading avatar", e); + } + } + + const response = await fetch("/register", { + method: "POST", + body: data, + }); + + const result = deserialize(await response.text()); + + if (result.type === "success") { + await invalidateAll(); + } + + applyAction(result); + loading = false; + } + + let avatarInput; + $: src = `/api/public/${punks[index]}.webp`; + let decr = () => (index = index <= 0 ? 63 : index - 1); + let incr = () => (index = index >= 63 ? 0 : index + 1); + let selectAvatar = () => avatarInput.click(); + + let progress; + let handleFile = async ({ target }) => { + let type = "profile"; + let file = target.files[0]; + if (!file) return; + + if (file.size > 10000000) form.error = "File too large"; + $avatar = { file, type, progress }; + + var reader = new FileReader(); + reader.onload = async (e) => { + src = e.target.result; + }; + + reader.readAsDataURL(file); + }; +</script> + +{#if need2fa} + <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> +{/if} + +<div + class="mx-auto md:shadow-xl rounded-3xl max-w-xl w-full md:w-[480px] md:p-8 space-y-5" +> + <h1 class="text-2xl font-bold text-center">{$t("login.createAccount")}</h1> + <input + type="file" + class="hidden" + bind:this={avatarInput} + on:change={(e) => handleFile(e, "profile")} + /> + + <div class="relative"> + <button + class="absolute w-8 h-12 left-12 bg-white rounded top-12" + on:click={decr} + > + <Icon icon="chevron-left" style="w-8 " /> + </button> + <button class="block relative w-32 mx-auto" on:click={selectAvatar}> + <button + class="w-32 h-32 rounded-full border-4 border-white overflow-hidden flex mx-auto relative" + > + <img + {src} + class="w-full h-full object-cover object-center overflow-hidden" + alt={username} + /> + </button> + <button + class="absolute bg-white rounded-full p-2 mx-auto right-0 bottom-0 z-10 bg-opacity-80" + > + <Icon icon="upload" style="w-8" /> + </button> + </button> + <button + class="absolute w-8 h-12 right-12 bg-white rounded top-12" + on:click={incr} + > + <Icon icon="chevron-left" style="w-8 rotate-180" /> + </button> + </div> + + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} + + <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <input + type="hidden" + name="loginRedirect" + value={$loginRedirect || $page.url.searchParams.get("redirect")} + /> + <input type="hidden" name="token" value={token} /> + + <div class="relative"> + <label for="username" class="font-semibold">{$t("login.username")}</label> + <input + use:focus + name="username" + type="text" + required + class="bg-primary" + bind:value={username} + on:focus={clear} + autocapitalize="none" + /> + <button + tabindex="-1" + type="button" + on:click={refresh} + class="absolute right-0 top-4" + > + <Icon icon="random" style="w-10 m-4" /> + </button> + </div> + + <div class="relative"> + <label for="password" class="block font-semibold" + >{$t("login.password")}</label + > + {#if revealPassword} + <input + name="password" + type="text" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {:else} + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + on:focus={clear} + /> + {/if} + <button + type="button" + tabindex="-1" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-0 top-4" + > + <Icon icon={revealPassword ? "eye" : "eye-off"} style="m-6" /> + </button> + </div> + + <button + type="submit" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + disabled={loading} + bind:this={btn} + > + {#if loading} + <Spinner /> + {:else} + {$t("login.register")} + {/if} + </button> + + <p class="text-secondary text-center font-medium"> + {$t("login.haveAccount")} + <a + href={"/login"} + class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + > + {$t("login.signIn")} + </a> + </p> + </form> +</div> diff --git a/src/routes/(app)/support/+page.svelte b/src/routes/(static)/support/+page.svelte index ad31ad1a..20e41280 100644 --- a/src/routes/(app)/support/+page.svelte +++ b/src/routes/(static)/support/+page.svelte @@ -1,8 +1,8 @@ <script> + import { browser } from "$app/environment"; import { onDestroy } from "svelte"; import { fail, success, post } from "$lib/utils"; import { scale } from "svelte/transition"; - import AppHeader from "$comp/AppHeader.svelte"; import Icon from "$comp/Icon.svelte"; import { t } from "$lib/translations"; @@ -30,6 +30,7 @@ }; onDestroy(() => { + if (!browser) return; const nodeBadge = document.querySelector(".grecaptcha-badge"); if (nodeBadge) { document.body.removeChild(nodeBadge.parentNode); @@ -52,11 +53,9 @@ ></script></svelte:head > -{#if user} - <AppHeader {data} /> -{/if} - -<div class="container px-4 max-w-lg mx-auto mt-20 space-y-8"> +<div + class="container max-w-lg mx-auto mt-20 space-y-8 shadow-xl rounded-3xl p-10" +> {#if sent} <h1 class="text-center text-3xl md:text-4xl font-semibold">Thank you!</h1> <div class="text-center text-lg text-secondary"> @@ -127,12 +126,8 @@ <button type="submit" disabled={!email || !message} - class="g-recaptcha {!email || !message - ? 'opacity-50' - : 'opacity-100'} bg-black text-white font-bold rounded-xl py-3 w-full mx-auto {email && - message - ? 'hover:opacity-80' - : ''}">{$t("user.support.send")}</button + class="g-recaptcha bg-black text-white font-bold rounded-xl py-3 w-full mx-auto hover:opacity-80" + >{$t("user.support.send")}</button > </form> {/if} diff --git a/src/routes/(app)/support/+server.ts b/src/routes/(static)/support/+server.ts index e9a16cfc..e9a16cfc 100644 --- a/src/routes/(app)/support/+server.ts +++ b/src/routes/(static)/support/+server.ts diff --git a/src/routes/(app)/+error.svelte b/src/routes/+error.svelte index 6ce7979c..6ce7979c 100644 --- a/src/routes/(app)/+error.svelte +++ b/src/routes/+error.svelte diff --git a/src/routes/start/+server.ts b/src/routes/start/+server.ts index 44561d40..2a1d88c3 100644 --- a/src/routes/start/+server.ts +++ b/src/routes/start/+server.ts @@ -3,7 +3,7 @@ import { redirect } from "@sveltejs/kit"; export async function GET({ cookies }) { let username = cookies.get("username"); if (username) { - redirect(307, `/${username}/receive`); + redirect(307, `/invoice`); } redirect(307, "/"); |
