diff options
| author | Adam Soltys <[email protected]> | 2025-07-10 12:36:50 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2025-07-10 12:36:50 -0700 |
| commit | 5b458624745c7ea80d1e63c9a6ef77075763ff5f (patch) | |
| tree | 462e71c86d97ed78eaf5324697350feab8af6a33 /src | |
| parent | ee8e20ce1dbcc0476ec698dd8c9d0ff99e260db7 (diff) | |
| download | coinos-ui-5b458624745c7ea80d1e63c9a6ef77075763ff5f.tar.gz coinos-ui-5b458624745c7ea80d1e63c9a6ef77075763ff5f.zip | |
user onboarding
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/utils.ts | 2 | ||||
| -rw-r--r-- | src/locales/en.json | 7 | ||||
| -rw-r--r-- | src/routes/(app)/+layout.svelte | 45 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 22 | ||||
| -rw-r--r-- | src/routes/(app)/fund/[id]/sweep/+page.server.ts | 10 | ||||
| -rw-r--r-- | src/routes/(app)/fund/[id]/sweep/+page.svelte | 6 | ||||
| -rw-r--r-- | src/routes/(app)/funder/+page.svelte | 55 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/tip/+page.server.ts | 28 | ||||
| -rw-r--r-- | src/routes/(app)/settings/profile/+page.svelte | 16 | ||||
| -rw-r--r-- | src/routes/(app)/settings/security/+page.svelte | 12 |
10 files changed, 153 insertions, 50 deletions
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 31d93fde..28a219e1 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -486,5 +486,5 @@ export const register = async (user, ip, cookies, loginRedirect) => { }); if (error) return svelteFail(400, { error }); - redirect(303, loginRedirect || `/${user.username}`); + redirect(303, loginRedirect || `/${user.username}`); }; diff --git a/src/locales/en.json b/src/locales/en.json index 922d24b3..88de69da 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -350,7 +350,12 @@ "locale": "Language", "username": "Username", "email": "Email", - "newPassword": "Change Password", + "newPassword": "New Password", + "newPasswordDesc": "(Leave blank to keep unchanged)", + "yourUsername": "Your username is", + "yourPassword": "and your password is", + "welcome": "Welcome!", + "clickBelow": "Click below to finish setting up your account", "about": "About", "aboutPlaceholder": "A little something about you or your business address and hours", "emailNotifications": "Email Notifications", diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index af4dbf2c..830e5291 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -46,22 +46,35 @@ checkSocket(); $pin = getCookie("pin"); - if (window.NDEFReader && user.nfc) { - try { - $ndef = new NDEFReader(); - await $ndef.scan(); - - $ndef.addEventListener("readingerror", (e) => { - console.log("nfc error", e); - }); - - $ndef.addEventListener("reading", ({ message, serialNumber }) => { - goto(`/send/${message}`); - }); - } catch (error) { - console.log("Argh! " + error); - } - } + // if (window.NDEFReader) { + // try { + // $ndef = new NDEFReader(); + // await $ndef.scan(); + // + // $ndef.addEventListener("readingerror", (e) => { + // console.log("nfc error", e); + // }); + // + // $ndef.addEventListener("reading", ({ message, serialNumber }) => { + // console.log("MESSAGE", message); + // + // const record = message.records[0]; + // + // if (record.recordType === "url") { + // const textDecoder = new TextDecoder(); + // const url = textDecoder.decode(record.data); + // console.log("URL:", url); + // + // // Navigate to the URL or use it however you want + // goto(`/send/${encodeURIComponent(url)}`); + // } else { + // console.error("Unsupported record type:", record.recordType); + // } + // }); + // } catch (error) { + // console.log("Argh! " + error); + // } + // } } }); diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index d064c3a9..31320197 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -6,7 +6,7 @@ import Account from "$comp/Account.svelte"; import Balance from "$comp/Balance.svelte"; import { t } from "$lib/translations"; - import { installPrompt } from "$lib/store"; + import { installPrompt, password } from "$lib/store"; import { afterNavigate, preloadData } from "$app/navigation"; import { page } from "$app/stores"; @@ -32,6 +32,24 @@ </script> <div class="space-y-2"> + {#if user?.fresh} + <div class="rounded-2xl space-y-2 p-4 shadow-lg"> + <h1 class="text-3xl font-bold">{$t("user.settings.welcome")}</h1> + <div> + {$t("user.settings.yourUsername")} <b>{user?.username}</b> + {#if $password} + {$t("user.settings.yourPassword")} + <b>{$password}</b>{/if} + </div> + + <div>{$t("user.settings.clickBelow")}</div> + + <a href="/settings/profile" class="btn"> + <iconify-icon icon="ph:gear-bold" width="32"></iconify-icon> + Settings</a + > + </div> + {/if} {#if user?.id && user.id === subject.id} <div class="space-y-5" data-sveltekit-preload-data="false"> {#each accounts as account, i} @@ -55,6 +73,8 @@ {/if} </div> +<!-- <a href="/funder" class="btn">Funder</a> --> + <div class="fixed inset-x-0 mx-auto flex bottom-16 px-4"> {#if user?.username !== subject.username && (!subject.anon || subject.lud16)} <a diff --git a/src/routes/(app)/fund/[id]/sweep/+page.server.ts b/src/routes/(app)/fund/[id]/sweep/+page.server.ts index 3e0b8dad..d8415ca4 100644 --- a/src/routes/(app)/fund/[id]/sweep/+page.server.ts +++ b/src/routes/(app)/fund/[id]/sweep/+page.server.ts @@ -10,18 +10,22 @@ export async function load({ cookies, request, params, parent }) { const rates = await getRates(); const rate = rates[user?.currency || "USD"]; + const username = randomName(); + const password = randomPassword(); + if (!amount) redirect(307, `/fund/${id}`); if (!user) { const ip = request.headers.get("cf-connecting-ip"); user = { - username: randomName(), - password: randomPassword(), + username, + password, + fresh: true, }; await register(user, ip, cookies, `/fund/${id}/sweep`); } await post("/take", { amount, id }, auth(cookies)); - return { amount, id, rate, rates }; + return { amount, id, rate, rates, password }; } diff --git a/src/routes/(app)/fund/[id]/sweep/+page.svelte b/src/routes/(app)/fund/[id]/sweep/+page.svelte index 986a84bb..adba77ae 100644 --- a/src/routes/(app)/fund/[id]/sweep/+page.svelte +++ b/src/routes/(app)/fund/[id]/sweep/+page.svelte @@ -1,4 +1,6 @@ <script> + import { onMount } from "svelte"; + import { password } from "$lib/store"; import Amount from "$comp/Amount.svelte"; import Success from "$comp/Success.svelte"; import { scale } from "svelte/transition"; @@ -9,9 +11,11 @@ let { data } = $props(); - let { amount, id, user, rate, rates } = data; + let { amount, id, user, rate, rates, password: pw } = data; let { currency } = user; let locale = $derived(loc(user)); + + onMount(() => ($password = pw)); </script> <div class="container px-4 text-center mx-auto"> diff --git a/src/routes/(app)/funder/+page.svelte b/src/routes/(app)/funder/+page.svelte new file mode 100644 index 00000000..e6549360 --- /dev/null +++ b/src/routes/(app)/funder/+page.svelte @@ -0,0 +1,55 @@ +<script lang="ts"> + import { onMount } from 'svelte'; +let here = false; + let ready = false; + let success = false; + let controller: AbortController | null = null; + let NfcWriter: any; + + async function write() { + NfcWriter = window.Capacitor?.Plugins?.NfcWriter; + ready = true; + console.log(window.Capacitor); + if (!NfcWriter) return; + here = true; + + try { + await NfcWriter.enableExclusiveNfcMode(); + + if (controller) controller.abort(); + controller = new AbortController(); + + ready = true; + + const ndef = new NDEFReader(); + await ndef.write( + { + records: [ + { + recordType: 'url', + data: 'https://coinos.io', + }, + ], + }, + { signal: controller.signal } + ); + + success = true; + } catch (err) { + if (err.name === 'AbortError') { + console.warn('Previous write aborted'); + } else { + console.error('Write failed', err); + alert('❌ Write failed: ' + err.message); + } + } finally { + await NfcWriter.disableExclusiveNfcMode(); + } + } +</script> + +HI +<button class="p-4 btn" on:click={write}>write</button> +{#if here}HERE{/if} +{#if ready}go{/if} +{#if success}done{/if} diff --git a/src/routes/(app)/invoice/[id]/tip/+page.server.ts b/src/routes/(app)/invoice/[id]/tip/+page.server.ts index de24c639..286d7c35 100644 --- a/src/routes/(app)/invoice/[id]/tip/+page.server.ts +++ b/src/routes/(app)/invoice/[id]/tip/+page.server.ts @@ -8,20 +8,22 @@ export async function load({ cookies, parent }) { let { invoice, subject, user } = await parent(); if (!invoice.amount) redirect(307, `/invoice/${invoice.id}`); - const trust = await get("/trust", auth(cookies)); - const trusted = trust.includes(invoice.uid); - if (trusted) { - if (invoice.prompt && invoice.tip === null && user.tip > 0) { - invoice.tip = Math.round(invoice.amount * (user.tip / 100)); - invoice = await post( - "/invoice", - { invoice, user: subject }, - auth(cookies), - ); - } + if (user) { + const trust = await get("/trust", auth(cookies)); + const trusted = trust.includes(invoice.uid); + if (trusted) { + if (invoice.prompt && invoice.tip === null && user.tip > 0) { + invoice.tip = Math.round(invoice.amount * (user.tip / 100)); + invoice = await post( + "/invoice", + { invoice, user: subject }, + auth(cookies), + ); + } - const p = await post("/payments", invoice, auth(cookies)); - redirect(307, `/sent/${p.id}`); + const p = await post("/payments", invoice, auth(cookies)); + redirect(307, `/sent/${p.id}`); + } } const rate = rates[subject?.currency]; diff --git a/src/routes/(app)/settings/profile/+page.svelte b/src/routes/(app)/settings/profile/+page.svelte index bee50d39..ec9855d0 100644 --- a/src/routes/(app)/settings/profile/+page.svelte +++ b/src/routes/(app)/settings/profile/+page.svelte @@ -3,16 +3,18 @@ import { avatar, banner as bannerStore } from "$lib/store"; import { t } from "$lib/translations"; import { page } from "$app/stores"; + import PasswordInput from "$comp/PasswordInput.svelte"; let { data } = $props(); let { user } = $derived(data); let { id } = user; - let { about, banner, picture, display, username } = - $state(user); + let { about, banner, picture, display, username } = $state(user); let avatarFile, avatarInput = $state(), bannerFile, + password = $state(), + revealPassword = $state(), bannerInput = $state(); let selectAvatar = () => avatarInput.click(); @@ -64,6 +66,16 @@ </div> </div> +<input type="hidden" name="confirm" bind:value={password} /> + +<div> + <label for="password" class="block font-bold block mb-1" + >{$t("user.settings.newPassword")}</label + > + + <PasswordInput bind:value={password} placeholder="(Leave blank to keep unchanged)" /> +</div> + <div> <label for="display" class="font-bold mb-1 block" >{$t("user.settings.displayName")}</label diff --git a/src/routes/(app)/settings/security/+page.svelte b/src/routes/(app)/settings/security/+page.svelte index ea1bf1f9..8c38bca1 100644 --- a/src/routes/(app)/settings/security/+page.svelte +++ b/src/routes/(app)/settings/security/+page.svelte @@ -4,7 +4,6 @@ import { t } from "$lib/translations"; import Pin from "$comp/Pin.svelte"; import Qr from "$comp/Qr.svelte"; - import PasswordInput from "$comp/PasswordInput.svelte"; import { copy, post, success, fail } from "$lib/utils"; import { save, pin as current } from "$lib/store"; import { invalidate } from "$app/navigation"; @@ -21,9 +20,7 @@ newNsec = $state(), nsec = $state(), otp = $state(), - password = $state(), pin = $state(""), - revealPassword = $state(), revealSeed, revealNsec = $state(), token = $state(""), @@ -157,15 +154,6 @@ </script> <input type="hidden" name="newpin" value={disablingPin ? "delete" : pin} /> -<input type="hidden" name="confirm" bind:value={password} /> - -<div> - <label for="password" class="block font-bold block mb-1" - >{$t("user.settings.newPassword")}</label - > - - <PasswordInput bind:value={password} /> -</div> <div> <span class="font-bold mb-1" |
