diff options
| author | Adam Soltys <[email protected]> | 2024-11-26 21:45:00 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-11-26 21:45:00 -0800 |
| commit | f4eb6547d0db5edd0137fdefe461433500515040 (patch) | |
| tree | 86a24ca7f263f80f322d59b2e5def5fc6b062719 | |
| parent | 872aa0b3b0b9a847b8afcdee7f1ad53c524ce4f0 (diff) | |
| download | coinos-ui-f4eb6547d0db5edd0137fdefe461433500515040.tar.gz coinos-ui-f4eb6547d0db5edd0137fdefe461433500515040.zip | |
warnings
| -rw-r--r-- | src/components/DeleteItem.svelte | 49 | ||||
| -rw-r--r-- | src/components/Event.svelte | 88 | ||||
| -rw-r--r-- | src/components/Items.svelte | 254 | ||||
| -rw-r--r-- | src/components/Password.svelte | 55 | ||||
| -rw-r--r-- | src/components/PasswordInput.svelte | 4 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 60 | ||||
| -rw-r--r-- | src/routes/(app)/invoice/[id]/paid/+page.svelte | 37 |
7 files changed, 27 insertions, 520 deletions
diff --git a/src/components/DeleteItem.svelte b/src/components/DeleteItem.svelte deleted file mode 100644 index d45f09e6..00000000 --- a/src/components/DeleteItem.svelte +++ /dev/null @@ -1,49 +0,0 @@ -<script> - import { preventDefault } from 'svelte/legacy'; - - import Icon from "$comp/Icon.svelte"; - import { fail, post } from "$lib/utils"; - import { invalidate } from "$app/navigation"; - - let { item = $bindable() } = $props(); - - let cancel = () => (item = null); - - let submit = async () => { - try { - await post("/api/items/delete", { item }); - invalidate("app:items"); - item = null; - } catch (e) { - fail("Failed to delete item"); - } - }; -</script> - -<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-5 border w-96 shadow-lg rounded-md bg-white space-y-5" - > - <h1 class="text-center text-2xl font-semibold">Delete item</h1> - <form onsubmit={preventDefault(submit)}> - <div class="w-full flex"> - <button - type="button" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - onclick={cancel} - onkeydown={cancel} - > - <div class="my-auto">No</div> - </button> - <button - type="submit" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto bg-black text-white" - > - <div class="my-auto">Yes</div> - </button> - </div> - </form> - </div> -</div> diff --git a/src/components/Event.svelte b/src/components/Event.svelte deleted file mode 100644 index 78fdd230..00000000 --- a/src/components/Event.svelte +++ /dev/null @@ -1,88 +0,0 @@ -<script> - import Avatar from "$comp/Avatar.svelte"; - import Icon from "$comp/Icon.svelte"; - let { event } = $props(); - - let { id, user, seen, content } = event; - - let distance = (date) => { - let m = 60; - let h = 60 * m; - let d = 24 * h; - - let diff = Math.round(Date.now() / 1000) - date; - return diff > d - ? Math.round(diff / d) + "d" - : diff > h - ? Math.round(diff / h) + "h" - : diff > m - ? Math.round(diff / m) + "m" - : diff > 2 - ? diff + "s" - : "now"; - }; - - let w = $state(); -</script> - -<svelte:window bind:innerWidth={w} /> - -<div - class="flex text-sm lg:text-base text-secondary hover:bg-gray-100 px-4 py-3" - :key={id} -> - <a href={`/${user.pubkey}`}> - <div class="mb-auto mr-2"> - <div class="md:hidden"> - <Avatar size={12} {user} disabled={true} /> - </div> - <div class="hidden md:block"> - <Avatar size={20} {user} disabled={true} /> - </div> - </div> - </a> - - <div class="grow" style={`max-width: ${w - 100}px`}> - <div class="w-full flex pb-1 text-black pt-1"> - <div> - {user.display_name || ""} - <span class="text-secondary">@{user.username}</span> - </div> - <div class="text-secondary"> {distance(seen)}</div> - </div> - <div class="break-words text-black"> - {content} - </div> - - <div class="flex justify-between text-sm text-secondary pt-3"> - <div class="flex group"> - <Icon - icon="party" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">444</div> - </div> - <div class="flex group"> - <Icon - icon="support" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">1072</div> - </div> - <div class="flex group"> - <Icon - icon="smile" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">26</div> - </div> - <div class="flex group"> - <Icon - icon="bolt" - style="mr-1 h-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">4</div> - </div> - </div> - </div> -</div> diff --git a/src/components/Items.svelte b/src/components/Items.svelte deleted file mode 100644 index a7b4fe1a..00000000 --- a/src/components/Items.svelte +++ /dev/null @@ -1,254 +0,0 @@ -<script> - import { run, stopPropagation } from 'svelte/legacy'; - - import { t } from "$lib/translations"; - import { btc, f, sat, post } from "$lib/utils"; - import { browser } from "$app/environment"; - import { goto, invalidate } from "$app/navigation"; - import { fade } from "svelte/transition"; - import { cubicIn } from "svelte/easing"; - import { flip } from "svelte/animate"; - import { - dndzone, - SHADOW_ITEM_MARKER_PROPERTY_NAME, - SOURCES, - TRIGGERS, - } from "svelte-dnd-action"; - import DeleteItem from "$comp/DeleteItem.svelte"; - import Icon from "$comp/Icon.svelte"; - - let { - subject, - user, - items = $bindable(), - rate, - currency, - total - } = $props(); - - let flipDurationMs = 200; - let dropTargetStyle = {}; - - let dragDisabled = - $state(subject?.id !== user?.id || (browser && window.innerWidth < 768)); - - let deleting = $state(); - let del = (item) => { - deleting = item; - }; - - function handleConsider(e) { - const { - items: newItems, - info: { source, trigger }, - } = e.detail; - items = newItems; - if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) - reset(); - } - - async function handleFinalize(e) { - const { - items: newItems, - info: { source }, - } = e.detail; - items = newItems; - if (source === SOURCES.POINTER) reset(); - - if (subject?.id === user?.id) { - await post("/api/items/sort", { items }); - invalidate("app:items"); - } - } - - function startDrag(e) { - e.preventDefault(); - dragDisabled = false; - } - - function handleKeyDown(e) { - if ((e.key === "Enter" || e.key === " ") && dragDisabled) - dragDisabled = false; - } - - - let checkout = async () => { - let invoice = { - type: "lightning", - amount: btc(total, rate), - currency, - items: items.filter((i) => i.quantity > 0), - prompt: subject.prompt, - memoPrompt: subject.memoPrompt, - rate, - }; - - let { id } = await post(`/invoice`, { - invoice, - user: { username: subject.username }, - }); - - if (invoice.memoPrompt) { - return goto(`/invoice/${id}/memo`); - } - goto(`/invoice/${id}`); - }; - - let reset = () => - (dragDisabled = - user?.username !== subject?.username || window.innerWidth < 768); - run(() => { - if (total > 0 && browser) { - let payButton = document.querySelector("#payButton"); - if (payButton) payButton.addEventListener("click", checkout); - } - }); -</script> - -<svelte:window onresize={reset} /> - -{#if deleting} - <DeleteItem bind:item={deleting} /> -{/if} - -{#if items.length} - <h2 class="text-2xl font-bold">Select items</h2> -{/if} -<div - class="grid sm:grid-cols-2 gap-4 pb-20" - use:dndzone={{ items, flipDurationMs, dropTargetStyle, dragDisabled }} - onconsider={handleConsider} - onfinalize={handleFinalize} -> - {#each items as i (i.id)} - <button - type="button" - class="w-full text-center cursor-pointer hover:opacity-80 mb-auto" - onclick={() => i.quantity++} - > - <div class="relative w-full h-64 overflow-hidden rounded-xl"> - {#if i[SHADOW_ITEM_MARKER_PROPERTY_NAME]} - <div - in:fade={{ duration: 200, easing: cubicIn }} - class="custom-shadow-item" -></div> - {:else if i.image} - <img - src={`/api/public/${i.image}.webp`} - alt={i.name} - class="mx-auto object-cover h-full w-full" - /> - {:else} - <div - class="bg-gradient-to-r from-primary to-gradient mb-4 cursor-pointer hover:opacity-80 w-full h-full" - alt="Banner" -></div> - {/if} - {#if user?.username === subject.username} - <div class="flex gap-2 justify-center absolute top-2 right-2"> - <a href={`/items/${i.id}`}> - <button - class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" - > - <Icon icon="edit" style="w-8 mx-auto invert" /> - </button> - </a> - <button - class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" - onclick={stopPropagation(() => del(i))} - > - <Icon icon="trash" style="w-8 mx-auto invert" /> - </button> - <div - onclick={stopPropagation(() => {})} - class="sm:hidden" - onmousedown={startDrag} - ontouchstart={startDrag} - onkeydown={handleKeyDown} - > - <a href={`/items/${i.id}`}> - <button - class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" - > - <Icon icon="move" style="w-8 mx-auto invert" /> - </button> - </a> - </div> - </div> - {/if} - </div> - <div class="bg-white rounded-xl py-2"> - <div class="flex text-left gap-2"> - <div class="overflow-hidden space-y-1"> - <div class="text-2xl break-words">{i.name}</div> - <div class="flex gap-2"> - <div class="font-semibold text-lg"> - {f(i.price, currency)} - </div> - <div class="text-secondary my-auto"> - {sat(btc(i.price, rate))} - </div> - </div> - </div> - <div class="flex gap-1 ml-auto mb-auto justify-around tabular-nums"> - {#if i.quantity} - <button - type="button" - onclick={stopPropagation(() => i.quantity > 0 && i.quantity--)} - > - <Icon icon="minus" style="w-10 min-w-10" /> - </button> - {/if} - <div class="text-2xl my-auto text-center"> - {#if i.quantity}{i.quantity}{:else}—{/if} - </div> - {#if i.quantity} - <button - type="button" - onclick={stopPropagation(() => i.quantity++)} - > - <Icon icon="plus" style="w-10 min-w-10" /> - </button> - {/if} - </div> - </div> - </div> - </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" - onclick={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/Password.svelte b/src/components/Password.svelte index dc77c0d3..bc32129d 100644 --- a/src/components/Password.svelte +++ b/src/components/Password.svelte @@ -1,25 +1,26 @@ <script lang="ts"> import { t } from "$lib/translations"; - import { preventDefault } from "svelte/legacy"; + import PasswordInput from "$comp/PasswordInput.svelte"; - import Icon from "$comp/Icon.svelte"; import { focus, fail, post } from "$lib/utils"; import { password as pw, passwordPrompt } from "$lib/store"; let { user } = $props(); - let password = $state(); - let { username } = user; - let revealPassword = $state(false); let cancel = () => ($passwordPrompt = false); - let submit = async () => { + let submit = async (e) => { + console.log("submitting"); + e.preventDefault(); try { - await post("/password", { password }); + console.log("res?"); + let res = await post("/password", { password }); + console.log(res); $passwordPrompt = false; $pw = password; } catch (e) { + console.log(e); fail("Invalid password, try again"); } }; @@ -34,47 +35,17 @@ <h1 class="text-center text-2xl font-semibold"> {$t("user.settings.pleaseEnterYourPassword")} </h1> - <form onsubmit={preventDefault(submit)} class="space-y-2"> - <label - for="password" - class="input flex items-center justify-center gap-2 w-full" - > - {#if revealPassword} - <input - class="clean" - name="password" - type="text" - required - bind:value={password} - autocapitalize="none" - use:focus - /> - {:else} - <input - class="clean" - name="password" - type="password" - required - bind:value={password} - autocapitalize="none" - use:focus - /> - {/if} - <iconify-icon - class="cursor-pointer" - onclick={() => (revealPassword = !revealPassword)} - icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} - width="32" - ></iconify-icon> - </label> + <form onsubmit={submit} class="space-y-2"> + <PasswordInput bind:value={password} {focus} /> <div class="w-full flex gap-2"> <button type="button" class="btn !w-auto grow" onclick={cancel} - onkeydown={cancel}>Cancel</button + onkeydown={cancel}>{$t("payments.cancel")}</button > - <button type="submit" class="btn btn-accent !w-auto grow">Submit</button + <button type="submit" class="btn btn-accent !w-auto grow" + >{$t("payments.submit")}</button > </div> </form> diff --git a/src/components/PasswordInput.svelte b/src/components/PasswordInput.svelte index 5885304b..bac00134 100644 --- a/src/components/PasswordInput.svelte +++ b/src/components/PasswordInput.svelte @@ -1,5 +1,5 @@ <script> - let { value = $bindable() } = $props(); + let { value = $bindable(), focus = () => {} } = $props(); let toggle = (e) => (show = !show); let show = $state(false); let icon = $derived(show ? "ph:eye-bold" : "ph:eye-slash-bold"); @@ -12,7 +12,7 @@ {#if show} <input name="password" type="text" bind:value class="clean" /> {:else} - <input name="password" type="password" bind:value class="clean" /> + <input name="password" type="password" bind:value class="clean" use:focus /> {/if} <button type="button" aria-label="Toggle" onclick={toggle} class="contents"> <iconify-icon {icon} width="32"></iconify-icon> diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index b754a886..b2c1970a 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -1,10 +1,8 @@ <script> import { scale } from "svelte/transition"; import { btc, f, sat } from "$lib/utils"; - import Icon from "$comp/Icon.svelte"; import Account from "$comp/Account.svelte"; import Balance from "$comp/Balance.svelte"; - import Items from "$comp/Items.svelte"; import { t } from "$lib/translations"; import { installPrompt } from "$lib/store"; import { afterNavigate, preloadData } from "$app/navigation"; @@ -52,62 +50,4 @@ </button> {/if} {/if} - - <Items {items} {subject} {user} {total} {currency} {rate} /> - - <div - class="fixed inset-x-0 mx-auto flex bottom-16 px-4" - 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" - onclick={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> - {:else if user?.username !== subject.username && (!subject.anon || subject.lud16)} - <a - href={subject.anon - ? `/send/${encodeURIComponent(subject.lud16)}` - : `/pay/${subject.username}`} - class="contents" - > - <button class="btn btn-accent !text-2xl items-center !w-full sm:!max-w-[400px] mx-auto"> - <iconify-icon icon="ph:lightning-fill" class="text-yellow-300" - ></iconify-icon> - <div> - {$t("user.pay")} - {subject.username} - </div> - </button> - </a> - {/if} - </div> </div> - -<style> - .custom-shadow-item { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - visibility: visible; - background: #333; - opacity: 0.5; - margin: 0; - } - - .bottom-half { - @apply bottom-1/2; - } -</style> diff --git a/src/routes/(app)/invoice/[id]/paid/+page.svelte b/src/routes/(app)/invoice/[id]/paid/+page.svelte index b031dd8c..2cd718be 100644 --- a/src/routes/(app)/invoice/[id]/paid/+page.svelte +++ b/src/routes/(app)/invoice/[id]/paid/+page.svelte @@ -1,4 +1,5 @@ <script> + import Amount from "$comp/Amount.svelte"; import Success from "$comp/Success.svelte"; import { t } from "$lib/translations"; @@ -11,35 +12,21 @@ </script> <div class="container px-4 text-center mx-auto"> - <Success - amount={received - tip} - {rate} - {tip} - {currency} - title={$t("invoice.paymentSuccessful")} - /> - {#if pending} - <div class="flex w-full py-5 max-w-[200px] mx-auto"> - <Icon icon="orangeclock" style="mx-auto" /> - </div> + <iconify-icon icon="ph:clock-bold" class="text-warning" width="160" + ></iconify-icon> <h1 class="text-3xl md:text-4xl font-bold mb-6">Payment detected</h1> - <h2 class="text-2xl md:text-3xl font-semibold"> - {f(toFiat(pending - tip, rate), currency)} - {#if tip} - + {f(toFiat(tip, rate), currency)} - {/if} - </h2> - <h3 class="text-secondary md:text-lg mb-6 mt-1"> - ⚡️{s(pending - tip)} - {#if tip} - <span class="text-lg"> - + ⚡️{s(tip)} - </span> - {/if} - </h3> + <Amount amount={pending - tip} {tip} {rate} {currency} /> + {:else} + <Success + amount={received - tip} + {rate} + {tip} + {currency} + title={$t("invoice.paymentSuccessful")} + /> {/if} </div> |
