aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-11-26 21:45:00 -0800
committerAdam Soltys <[email protected]>2024-11-26 21:45:00 -0800
commitf4eb6547d0db5edd0137fdefe461433500515040 (patch)
tree86a24ca7f263f80f322d59b2e5def5fc6b062719
parent872aa0b3b0b9a847b8afcdee7f1ad53c524ce4f0 (diff)
downloadcoinos-ui-f4eb6547d0db5edd0137fdefe461433500515040.tar.gz
coinos-ui-f4eb6547d0db5edd0137fdefe461433500515040.zip
warnings
-rw-r--r--src/components/DeleteItem.svelte49
-rw-r--r--src/components/Event.svelte88
-rw-r--r--src/components/Items.svelte254
-rw-r--r--src/components/Password.svelte55
-rw-r--r--src/components/PasswordInput.svelte4
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte60
-rw-r--r--src/routes/(app)/invoice/[id]/paid/+page.svelte37
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">&nbsp;{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}&mdash;{/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>