diff options
| author | Adam Soltys <[email protected]> | 2024-11-09 11:28:04 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-11-09 11:28:04 -0800 |
| commit | 542c24b17643bc1a743c6d5eca3e3a29947c72b5 (patch) | |
| tree | 300ecabce7e1b85c1aad64780e8404c3542dfad7 /src | |
| parent | d47895ec4d54feef1114029ba11188362fa1222d (diff) | |
| download | coinos-ui-542c24b17643bc1a743c6d5eca3e3a29947c72b5.tar.gz coinos-ui-542c24b17643bc1a743c6d5eca3e3a29947c72b5.zip | |
fix 2fa
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Balance.svelte | 20 | ||||
| -rw-r--r-- | src/components/Pinpad.svelte | 13 | ||||
| -rw-r--r-- | src/lib/utils.ts | 20 | ||||
| -rw-r--r-- | src/routes/(app)/payments/[...page]/+page.svelte | 46 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.server.ts | 8 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.svelte | 81 |
6 files changed, 109 insertions, 79 deletions
diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte index e5f62d19..f92cd5ef 100644 --- a/src/components/Balance.svelte +++ b/src/components/Balance.svelte @@ -1,9 +1,6 @@ <script> - import { preventDefault } from "svelte/legacy"; - - import Icon from "$comp/Icon.svelte"; import Pin from "$comp/Pin.svelte"; - import { f, s, sat, sats } from "$lib/utils"; + import { f, s, si, sat, sats } from "$lib/utils"; import { pin } from "$lib/store"; import { t } from "$lib/translations"; @@ -23,20 +20,21 @@ <div> {#if user.haspin && !$pin} <button onclick={toggleShow} class="flex gap-2 text-xl"> - <Icon icon="eye-off" style="w-8 my-auto" /> + <iconify-icon icon="ph:eye-slash-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.showBalance")}</div> </button> {:else} - <div class="text-4xl font-bold tabular-nums"> + <div class="text-4xl font-bold flex items-center"> + <iconify-icon icon="ph:lightning-fill" width="32" class="text-yellow-300"></iconify-icon> + {s(balance)} + </div> + + <div class="text-secondary text-xl"> {#if isNaN(rate)} <div class="text-gray-200">—</div> {:else} - {f((balance * rate) / sats, user.currency)} + {si(((balance * rate) / sats).toFixed(2))} {user.currency} {/if} </div> - - <div class="text-secondary text-xl"> - ⚡️{s(balance)} - </div> {/if} </div> diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte index 93f31d08..72aaac81 100644 --- a/src/components/Pinpad.svelte +++ b/src/components/Pinpad.svelte @@ -1,5 +1,5 @@ <script> - import { preventDefault, stopPropagation } from 'svelte/legacy'; + import { preventDefault, stopPropagation } from "svelte/legacy"; import Left from "$comp/Left.svelte"; import Icon from "$comp/Icon.svelte"; @@ -64,7 +64,7 @@ width="32" onclick={stopPropagation(preventDefault(() => (hide = !hide)))} class="cursor-pointer" -></iconify-icon> + ></iconify-icon> </label> <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> @@ -73,7 +73,9 @@ <button type="button" class="btn" - onclick={stopPropagation(preventDefault(() => handleInput(value)))} + onclick={((e) => e.preventDefault(), + e.stopPropagation(), + handleInput(value))} > <Left /> </button> @@ -81,8 +83,9 @@ <button type="button" class="btn" - onclick={stopPropagation(preventDefault(() => handleInput(value)))} - >{value}</button + onclick={((e) => e.preventDefault(), + e.stopPropagation(), + handleInput(value))}>{value}</button > {/if} {/each} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b27ce5f1..2779e34a 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -216,19 +216,21 @@ export const f = (s: number, currency: string): string => { export const s = (s: number): string => new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(s); -export const sat = (s: number): string => `⚡️${si(Math.abs(s)).toString()}`; - -export const si = (s: number) => { - if (s < 1000) return s.toString(); // Return the original number if it's less than 1000 +export const sat = (s: number): string => `${si(Math.abs(s)).toString()}`; +export const si = (n: number, minimumFractionDigits = 1, maximumFractionDigits = 2) => { const units = ["", "K", "M", "G", "T", "P", "E", "Z"]; - const d = Math.floor(Math.log10(s) / 3); // Calculate the unit index - const scaled = s / 1000 ** d; // Scale the number to the correct unit + + let s = n; + let d = 0; + if (s >= 1000) { + d = Math.floor(Math.log10(s) / 3); // Calculate the unit index + s = n / 1000 ** d; // Scale the number to the correct unit + } return ( - new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 }).format( - scaled, - ) + units[d] + new Intl.NumberFormat("en-US", { minimumFractionDigits, maximumFractionDigits }).format(s) + + units[d] ); }; diff --git a/src/routes/(app)/payments/[...page]/+page.svelte b/src/routes/(app)/payments/[...page]/+page.svelte index 2735491c..41433757 100644 --- a/src/routes/(app)/payments/[...page]/+page.svelte +++ b/src/routes/(app)/payments/[...page]/+page.svelte @@ -1,12 +1,12 @@ <script> - import { run } from 'svelte/legacy'; + import { run } from "svelte/legacy"; import Avatar from "$comp/Avatar.svelte"; import { onMount } from "svelte"; import { format } from "date-fns"; import { newPayment } from "$lib/store"; import { t } from "$lib/translations"; - import { get, f, s, sat, sats, types } from "$lib/utils"; + import { get, f, s, si, sat, sats, types } from "$lib/utils"; import { page } from "$app/stores"; import { differenceInDays, getUnixTime, sub } from "date-fns"; import { goto, invalidate } from "$app/navigation"; @@ -46,11 +46,14 @@ }, ]); - let selection = $derived(start - ? presets.findIndex( - (p) => Math.abs(differenceInDays(new Date(start * 1000), p.start)) < 1, - ) - : 0); + let selection = $derived( + start + ? presets.findIndex( + (p) => + Math.abs(differenceInDays(new Date(start * 1000), p.start)) < 1, + ) + : 0, + ); let p = $state(), incoming = $state(), @@ -68,9 +71,11 @@ $newPayment && invalidate(`/users/${user.username}`); }); - let path = $derived($page.params.page - ? $page.url.pathname.substring(0, $page.url.pathname.lastIndexOf("/")) - : $page.url.pathname); + let path = $derived( + $page.params.page + ? $page.url.pathname.substring(0, $page.url.pathname.lastIndexOf("/")) + : $page.url.pathname, + ); let csv = async () => { let url = `/payments`; @@ -206,8 +211,17 @@ class:border-b-0={i === payments.length - 1} > <div class="whitespace-nowrap my-auto col-span-3"> - <div class="font-bold" class:text-red-800={p.amount < 0}> - {f(Math.abs(p.amount) * (p.rate / sats), p.currency)} + <div + class="font-bold flex items-center" + class:text-red-800={p.amount < 0} + > + <iconify-icon + icon="ph:lightning-fill" + width="24" + class="text-yellow-300" + ></iconify-icon> + {si(Math.abs(p.amount) + (p.tip || 0), 0, 1)} + {#if p.tip} <span class="text-sm text-secondary"> +{Math.round((p.tip / Math.abs(p.amount)) * 100)}% @@ -215,8 +229,9 @@ {/if} </div> - <div class="text-secondary"> - {sat(Math.abs(p.amount) + (p.tip || 0))} + <div class="text-secondary flex items-center"> + {si(Math.abs(p.amount) * (p.rate / sats), 2)} + {p.currency} </div> </div> @@ -249,7 +264,8 @@ {:else if p.type === types.ecash} <img src="/images/cash.png" class="w-12" /> {:else if p.type === types.reconcile} - <iconify-icon icon="ph:scales-bold" width="32"></iconify-icon> + <iconify-icon icon="ph:scales-bold" width="32" + ></iconify-icon> {:else if p.type === types.bitcoin} <div class="my-auto"> <img diff --git a/src/routes/(static)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts index f9108c50..d06c4895 100644 --- a/src/routes/(static)/login/+page.server.ts +++ b/src/routes/(static)/login/+page.server.ts @@ -12,14 +12,16 @@ export const actions = { let { username, password, token, loginRedirect } = form; const user = { username, password, token }; - console.log("LOGIN", user); + console.log("LOGIN", user, form); if (loginRedirect === "undefined") loginRedirect = undefined; try { await login(user, cookies, request.headers.get("cf-connecting-ip")); - } catch (e: any) { - return fail(400, { error: "Login failed", message: e.message, ...form }); + } catch (e) { + const { message } = e as Error; + console.log("message", message); + return fail(400, { error: "Login failed", message, ...form }); } redirect(307, loginRedirect || `/${user.username}`); diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte index d50e0cdc..17b69f5e 100644 --- a/src/routes/(static)/login/+page.svelte +++ b/src/routes/(static)/login/+page.svelte @@ -1,14 +1,13 @@ <script> - import { run, preventDefault } from 'svelte/legacy'; + import { run, preventDefault } from "svelte/legacy"; + import handler from "$lib/handler"; 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 Pinpad from "$comp/Pinpad.svelte"; import { focus, fail } from "$lib/utils"; import { password, pin, loginRedirect } from "$lib/store"; import { t } from "$lib/translations"; @@ -27,7 +26,7 @@ let { form } = $props(); - let token = $state(), formElement; + let token = $state(""); let code = []; let redirect; @@ -35,16 +34,20 @@ let cancel = () => (need2fa = false); - let username = $state(), email, btn = $state(); - - let update = (form) => form && ({ username, password: $password } = form); + let username = $state(), + email, + btn = $state(); + $effect(() => form && ({ username, password: $password } = form)); + let need2fa = $derived(form?.message === "2fa"); + $effect(() => { + if (need2fa && form.token === token) token = ""; + }); let revealPassword = $state(false); - let loading = $state(); async function handleSubmit(e) { - loading = true; + console.log("SUBMITTING"); let data = new FormData(this); let user = Object.fromEntries(data); @@ -65,39 +68,29 @@ } applyAction(result); - loading = false; } - let need2fa; - run(() => { - need2fa = form?.message === "2fa"; - }); - run(() => { - if (form?.message === "2fa" && form.token === token) token = ""; - }); - run(() => { - update(form); - }); - run(() => { - token && token?.length === 6 && tick().then(() => btn.click()); + + $effect(() => { + console.log("TOKEN", token); + token?.length === 6 && + tick().then(() => { + btn.click(); + }); }); </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 mb-20" > <h1 class="text-2xl font-bold text-center">{$t("login.signIn")}</h1> - {#if form?.error} + {#if form?.error && !form?.message.includes("2fa")} <div class="text-red-600 text-center" in:fly> {form.error} </div> {/if} - <form class="space-y-5" onsubmit={preventDefault(handleSubmit)} method="POST"> + <form use:enhance class="space-y-5" onsubmit={handleSubmit} method="POST"> <input type="hidden" name="loginRedirect" @@ -145,7 +138,7 @@ onclick={() => (revealPassword = !revealPassword)} icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} width="32" -></iconify-icon> + ></iconify-icon> </label> <div class="flex justify-end items-center"> @@ -154,12 +147,8 @@ > </div> - <button type="submit" class="btn" disabled={loading} bind:this={btn}> - {#if loading} - <Spinner /> - {:else} - {$t("login.signIn")} - {/if} + <button type="submit" class="btn" bind:this={btn}> + {$t("login.signIn")} </button> <p class="text-secondary text-center font-medium"> @@ -173,3 +162,23 @@ </p> </form> </div> + +{#if need2fa && token.length < 6} + <div + class="fixed bg-base-100 bg-opacity-90 inset-0 h-full w-full z-50 cursor-default" + onclick={(e) => e.stopPropagation()} + > + <div + class="mx-auto p-5 border shadow-lg rounded-md bg-base-100 space-y-5 max-w-lg" + > + <h1 class="text-center text-2xl font-semibold">2FA</h1> + <Pinpad bind:v={token} {cancel} /> + + <div class="w-full flex"> + <button class="btn" onclick={cancel}> + <div class="my-auto">Cancel</div> + </button> + </div> + </div> + </div> +{/if} |
