aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/AppHeader.svelte4
-rw-r--r--src/components/Avatar.svelte4
-rw-r--r--src/components/ItemForm.svelte108
-rw-r--r--src/lib/nostr.js2
-rw-r--r--src/lib/store.js1
-rw-r--r--src/lib/utils.js1
-rw-r--r--src/locales/en.json9
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte176
-rw-r--r--src/routes/(app)/[username]/items/[id]/+page.server.js6
-rw-r--r--src/routes/(app)/[username]/items/[id]/+page.svelte7
-rw-r--r--src/routes/(app)/[username]/items/create/+page.svelte14
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/_account.svelte25
-rw-r--r--src/routes/(app)/payment/[id]/bump/+server.js2
-rw-r--r--src/routes/(app)/send/user/[username]/[...amount]/+page.server.js7
14 files changed, 301 insertions, 65 deletions
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte
index a2103cf5..72f10d26 100644
--- a/src/components/AppHeader.svelte
+++ b/src/components/AppHeader.svelte
@@ -1,6 +1,6 @@
<script>
import OutClick from "svelte-outclick";
- import { banner, newPayment, colorTheme } from "$lib/store";
+ import { banner, newPayment } from "$lib/store";
import { goto } from "$app/navigation";
import Avatar from "$comp/Avatar.svelte";
import Icon from "$comp/Icon.svelte";
@@ -42,7 +42,7 @@
{#if !$loading}
<header
- class="bg-gradient-to-r {$colorTheme} h-[175px] w-full relative bg-cover mb-20"
+ class="bg-gradient-to-r from-primary to-gradient h-[175px] w-full relative bg-cover mb-20"
style:background-image={bg}
>
<nav class="flex justify-end items-center space-x-4 p-5">
diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte
index f13404bd..227200d7 100644
--- a/src/components/Avatar.svelte
+++ b/src/components/Avatar.svelte
@@ -1,5 +1,5 @@
<script>
- import { avatar, banner, colorTheme } from "$lib/store";
+ import { avatar, banner } from "$lib/store";
import Icon from "$comp/Icon.svelte";
import { punk } from "$lib/utils";
@@ -20,7 +20,7 @@
<a href={link} class:pointer-events-none={disabled}>
<div
- class="w-{s} h-{s} rounded-full border-4 border-white overflow-hidden bg-gradient-to-r {$colorTheme} flex justify-center items-center"
+ class="w-{s} h-{s} rounded-full border-4 border-white overflow-hidden bg-gradient-to-r from-primary to-gradient flex justify-center items-center"
>
<img
{src}
diff --git a/src/components/ItemForm.svelte b/src/components/ItemForm.svelte
new file mode 100644
index 00000000..044020b7
--- /dev/null
+++ b/src/components/ItemForm.svelte
@@ -0,0 +1,108 @@
+<script>
+ import { t } from "$lib/translations";
+ import { upload } from "$lib/upload";
+ export let item, token;
+
+ let fileInput, formElement, file;
+ let select = () => fileInput.click();
+ let src;
+
+ let tooLarge = {};
+ let handleFile = async ({ target }, type) => {
+ tooLarge[type] = false;
+ file = target.files[0];
+ if (!file) return;
+
+ if (file.size > 10000000) return (tooLarge[type] = true);
+
+ var reader = new FileReader();
+ reader.onload = async (e) => {
+ src = e.target.result;
+ };
+
+ reader.readAsDataURL(file);
+ };
+
+ async function handleSubmit() {
+ try {
+ submitting = true;
+ let data = new FormData(formElement);
+
+ if (src) {
+ try {
+ let { hash } = JSON.parse(
+ await upload(file, "item", progress, token)
+ );
+
+ data.set("image", hash);
+
+ await fetch(`/api/public/${hash}.webp`, {
+ cache: "reload",
+ mode: "no-cors",
+ });
+ } catch (e) {
+ console.log("problem upsubmitting avatar", e);
+ }
+ }
+
+ const response = await fetch(formElement.action, {
+ method: "POST",
+ body: data,
+ });
+
+ const result = deserialize(await response.text());
+
+ applyAction(result);
+ } catch (e) {
+ console.log(e);
+ fail("Something went wrong");
+ }
+
+ submitting = false;
+ }
+</script>
+
+<form
+ method="POST"
+ class="space-y-5"
+ on:submit|preventDefault={handleSubmit}
+ bind:this={formElement}
+>
+ <div>
+ <label for="name" class="font-bold mb-1 block">{$t("items.name")}</label>
+ <input name="name" bind:value={item.name} />
+ </div>
+ <div>
+ <label for="img" class="font-bold mb-1 block">{$t("items.image")}</label>
+ <div class="relative w-full h-64">
+ {#if item.hash}
+ <img
+ src={`/api/public/${item.hash}.webp`}
+ alt={item.name}
+ class="mx-auto object-cover h-full w-full"
+ />
+ {:else if src}
+ <img {src} alt={item.name} class="mx-auto object-cover h-full w-full" />
+ {:else}
+ <div
+ class="bg-gradient-to-r from-primary to-gradient w-full h-48 mb-4 cursor-pointer hover:opacity-80"
+ on:click={select}
+ on:keydown={select}
+ alt="Banner"
+ />
+ {/if}
+ <input
+ type="file"
+ class="hidden"
+ bind:this={fileInput}
+ on:change={(e) => handleFile(e, "item")}
+ />
+ </div>
+ </div>
+
+ <button
+ class="rounded-full py-5 px-6 font-bold hover:opacity-80 flex bg-black text-white text-2xl"
+ >
+ {$t("items.submit")}
+ </button>
+</form>
diff --git a/src/lib/nostr.js b/src/lib/nostr.js
index 5de08199..5209418a 100644
--- a/src/lib/nostr.js
+++ b/src/lib/nostr.js
@@ -90,7 +90,7 @@ export let getPrivateKey = async (user) => {
if (browser) {
k = localStorage.getItem("nsec");
if (k) {
- return nip19.decode(k).data;
+ return nip19.decode(k).data;
}
}
diff --git a/src/lib/store.js b/src/lib/store.js
index ee60058c..c27e7f6c 100644
--- a/src/lib/store.js
+++ b/src/lib/store.js
@@ -40,7 +40,6 @@ const persistLocal = (key, defaultValue) => {
export const avatar = writable();
export const banner = writable();
-export const colorTheme = writable("from-primary to-gradient");
export const event = writable();
export const events = writable({});
export const invoice = writable();
diff --git a/src/lib/utils.js b/src/lib/utils.js
index d1096cd4..53437f56 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -172,6 +172,7 @@ export let auth = (cookies) => ({
authorization: `Bearer ${cookies.get("token")}`,
});
+export let btc = (fiat, rate) => Math.round((fiat * sats) / rate);
export let fiat = (amount, rate) => (amount * rate) / sats;
export let fd = async (req) => {
let obj = Object.fromEntries(await req.formData());
diff --git a/src/locales/en.json b/src/locales/en.json
index 4fad56d6..24433202 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -178,6 +178,7 @@
"this": "This",
"lightningAddress": "Lightning address",
"dashboard": {
+ "checkout": "Checkout",
"go": "Go",
"dashboard": "Dashboard",
"accountBalance": "Account Balance",
@@ -349,5 +350,11 @@
"print": "Print",
"onlyLbtc": "We only support",
"dontDeposit": "don't deposit other assets yet"
- }
+ },
+ "items": {
+ "add": "Add item",
+ "name": "Name",
+ "submit": "Submit",
+ "image": "Image"
+ }
}
diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte
index 420cc5fa..bb98ddfe 100644
--- a/src/routes/(app)/[username]/(profile)/+page.svelte
+++ b/src/routes/(app)/[username]/(profile)/+page.svelte
@@ -1,4 +1,5 @@
<script>
+ import { btc, f } from "$lib/utils";
import { onMount } from "svelte";
import Icon from "$comp/Icon.svelte";
import Balance from "$comp/Balance.svelte";
@@ -8,46 +9,161 @@
let { subject, user, rates } = data;
$: refresh(data);
let refresh = (d) => ({ subject, user, rates } = d);
+
+ let items = [
+ {
+ id: 1,
+ name: "Full Pour",
+ price: 9,
+ quantity: 0,
+ hash: "fa3a9d22eb24b33ae2dee8d7566c1ce25d1c76e18b46d54437621d3e34a3fbc9",
+ },
+ {
+ id: 2,
+ name: "Half Pour",
+ price: 6,
+ quantity: 0,
+ hash: "a79c7b921a0dde39076201ae5f24505d5faa5f12f0cfd3b9d86cbc9c77ab0bd1",
+ },
+ {
+ id: 3,
+ name: "Taster",
+ price: 3,
+ quantity: 0,
+ hash: "9d8fe68d068f7271cf08d4cb9b033966984549c1bcd827f7516e66e5b537f502",
+ },
+ {
+ id: 4,
+ name: "4-packs",
+ price: 18,
+ quantity: 0,
+ hash: "13cf773ae51607e670c2a7c640aa5a1dc8b288554026de08370ed3da44e59493",
+ },
+ ];
+
+ $: total = items.reduce((a, b) => a + b.price * b.quantity, 0);
+ let del = () => {};
</script>
<div class="space-y-5">
{#if user?.id === subject.id}
- <div class="space-y-5">
- <div class="flex justify-center lg:justify-start">
- <Balance {user} rate={rates[user.currency]} />
+ <div class="flex justify-center lg:justify-start">
+ <Balance {user} rate={rates[user.currency]} />
+ </div>
+
+ {#if !user.balance}
+ <div class="mb-8">
+ <p class="text-secondary text-lg">
+ {$t("user.welcome")}
+ </p>
</div>
+ {/if}
- {#if !user.balance}
- <div class="mb-8">
- <p class="text-secondary text-lg">
- {$t("user.welcome")}
- </p>
- </div>
- {/if}
+ <div
+ class="flex flex-wrap sm:flex-nowrap gap-3 justify-center w-full text-xl"
+ >
+ <a href={`/send`} class="w-full">
+ <button
+ class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-primary"
+ >
+ <div class="mx-auto flex">
+ <Icon icon="send" style="my-auto h-6 mr-2" />
+ <div class="my-auto">{$t("user.dashboard.send")}</div>
+ </div>
+ </button>
+ </a>
- <div class="flex flex-wrap sm:flex-nowrap gap-3 justify-center w-full text-xl">
- <a href={`/send`} class="w-full">
- <button
- class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-primary"
- >
- <div class="mx-auto flex">
- <Icon icon="send" style="my-auto h-6 mr-2" />
- <div class="my-auto">{$t("user.dashboard.send")}</div>
- </div>
- </button>
- </a>
+ <a href={`/${user.username}/receive`} class="w-full">
+ <button
+ class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-primary"
+ >
+ <div class="mx-auto flex">
+ <Icon icon="numpad" style="my-auto h-6 mr-2" />
+ <div class="my-auto">{$t("user.dashboard.receive")}</div>
+ </div>
+ </button>
+ </a>
+ </div>
+ {/if}
- <a href={`/${user.username}/receive`} class="w-full">
- <button
- class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-primary"
- >
- <div class="mx-auto flex">
- <Icon icon="numpad" style="my-auto h-6 mr-2" />
- <div class="my-auto">{$t("user.dashboard.receive")}</div>
+ <div class="grid grid-cols-2 gap-4">
+ {#each items as i}
+ <div
+ class="w-full text-center cursor-pointer hover:opacity-80"
+ on:click={() => i.quantity++}
+ >
+ <div class="relative w-full h-64 overflow-hidden rounded-xl">
+ <img
+ src={`/api/public/${i.hash}.webp`}
+ alt={i.name}
+ class="mx-auto object-cover h-full w-full"
+ />
+ {#if user?.username === subject.username}
+ <div class="flex gap-2 justify-center absolute top-2 right-2">
+ <div
+ on:click|stopPropagation={() => i.quantity > 0 && i.quantity--}
+ >
+ <a href={`/${user.username}/items/${i.id}`}>
+ <button class="bg-white rounded-xl">
+ <Icon icon="edit" style="w-10" />
+ </button>
+ </a>
+ </div>
+ <button class="bg-white rounded-xl">
+ <Icon icon="trash" style="w-10" on:click={() => del(i)} />
+ </button>
</div>
- </button>
- </a>
+ {/if}
+ </div>
+ <div class="bg-white rounded-xl p-2">
+ <div class="text-2xl">
+ {i.name} &mdash; {f(i.price, subject.currency)}
+ </div>
+ <div class="flex gap-2 justify-center">
+ <div
+ on:click|stopPropagation={() => i.quantity > 0 && i.quantity--}
+ >
+ <Icon icon="minus" style="w-10" />
+ </div>
+ <div class="text-2xl my-auto">{i.quantity}</div>
+ <Icon icon="plus" style="w-10" />
+ </div>
+ </div>
</div>
+ {/each}
+ </div>
+ {#if total > 0}
+ <div>
+ <a
+ href={`/send/${subject.username}/${total}/${subject.currency}`}
+ class="w-full"
+ >
+ <button
+ class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-black text-white"
+ >
+ <div class="mx-auto flex">
+ <div class="my-auto text-2xl">
+ {f(total, subject.currency)}
+ {$t("user.dashboard.checkout")}
+ </div>
+ </div>
+ </button>
+ </a>
+ </div>
+ {/if}
+ {#if user?.username === subject.username}
+ <div>
+ <a href={`/${user.username}/items/create`} class="w-full">
+ <button
+ class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-full bg-black text-white"
+ >
+ <div class="mx-auto flex">
+ <div class="my-auto text-2xl">
+ {$t("items.add")}
+ </div>
+ </div>
+ </button>
+ </a>
</div>
{/if}
</div>
diff --git a/src/routes/(app)/[username]/items/[id]/+page.server.js b/src/routes/(app)/[username]/items/[id]/+page.server.js
new file mode 100644
index 00000000..e1fe2efd
--- /dev/null
+++ b/src/routes/(app)/[username]/items/[id]/+page.server.js
@@ -0,0 +1,6 @@
+import { get } from "$lib/utils";
+export let load = async ({ cookies, params: { id } }) => {
+ let item = await get(`/item/${id}`);
+ console.log("item", item)
+ return { item };
+};
diff --git a/src/routes/(app)/[username]/items/[id]/+page.svelte b/src/routes/(app)/[username]/items/[id]/+page.svelte
new file mode 100644
index 00000000..5a19e892
--- /dev/null
+++ b/src/routes/(app)/[username]/items/[id]/+page.svelte
@@ -0,0 +1,7 @@
+<script>
+ import ItemForm from "$comp/ItemForm.svelte";
+ export let data;
+ let { item } = data;
+</script>
+
+<ItemForm {item} />
diff --git a/src/routes/(app)/[username]/items/create/+page.svelte b/src/routes/(app)/[username]/items/create/+page.svelte
new file mode 100644
index 00000000..c9aeae1d
--- /dev/null
+++ b/src/routes/(app)/[username]/items/create/+page.svelte
@@ -0,0 +1,14 @@
+<script>
+ import { t } from "$lib/translations";
+ import ItemForm from "$comp/ItemForm.svelte";
+ export let data;
+ let { token } = data;
+ let item = {};
+</script>
+
+<div class="container max-w-xl mx-auto">
+ <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-10">
+ {$t("items.add")}
+ </h1>
+ <ItemForm {item} {token} />
+</div>
diff --git a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte
index 15ee7b0c..8e3323c7 100644
--- a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte
+++ b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte
@@ -1,6 +1,6 @@
<script>
import { tick } from "svelte";
- import { colorTheme, avatar, banner } from "$lib/store";
+ import { avatar, banner } from "$lib/store";
import Icon from "$comp/Icon.svelte";
import { t } from "$lib/translations";
import { page } from "$app/stores";
@@ -9,27 +9,8 @@
let { id } = user;
- let selectedTheme = 1;
let avatarFile, avatarInput, bannerFile, bannerInput;
- let colorThemes = [
- { theme: 1, color1: "from-[#F5F7FA]", color2: "to-[#C3CFE2]" },
- { theme: 2, color1: "from-[#FDFCFB]", color2: "to-[#E2D1C3]" },
- { theme: 3, color1: "from-[#E6E9F0]", color2: "to-[#EEF1F5]" },
- { theme: 4, color1: "from-[#D5D4D0]", color2: "to-[#EEEEEC]" },
- { theme: 5, color1: "from-[#F3E7E9]", color2: "to-[#E3EEFF]" },
- {
- theme: 6,
- color1: "from-[#F5F7FA]",
- color2: "via-[#EAF2FF] to-[#DEDFFF]",
- },
- ];
-
- let handleThemeClick = (colors) => {
- selectedTheme = colors.theme;
- $colorTheme = colors.color1 + " " + colors.color2;
- };
-
let selectAvatar = () => avatarInput.click();
let selectBanner = () => bannerInput.click();
@@ -127,7 +108,7 @@
</div>
{:else}
<div
- class="rounded-full border-4 border-white p-4 bg-gradient-to-r {$colorTheme} w-24 my-auto hover:opacity-80 cursor-pointer"
+ class="rounded-full border-4 border-white p-4 bg-gradient-to-r from-primary to-gradient w-24 my-auto hover:opacity-80 cursor-pointer"
on:click={selectAvatar}
on:keydown={selectAvatar}
>
@@ -171,7 +152,7 @@
/>
{:else}
<div
- class="bg-gradient-to-r {$colorTheme} w-full h-48 mb-4 cursor-pointer hover:opacity-80"
+ class="bg-gradient-to-r from-primary to-gradient w-full h-48 mb-4 cursor-pointer hover:opacity-80"
on:click={selectBanner}
on:keydown={selectBanner}
alt="Banner"
diff --git a/src/routes/(app)/payment/[id]/bump/+server.js b/src/routes/(app)/payment/[id]/bump/+server.js
index 766f537f..513198b0 100644
--- a/src/routes/(app)/payment/[id]/bump/+server.js
+++ b/src/routes/(app)/payment/[id]/bump/+server.js
@@ -7,6 +7,6 @@ export async function POST({ cookies, request }) {
let res = await post("/replace", body, auth(cookies));
return json(res);
} catch (e) {
- error(400, e.message);
+ error(400, e.message);
}
}
diff --git a/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js b/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js
index fe004408..884e3eee 100644
--- a/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js
+++ b/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js
@@ -8,16 +8,13 @@ export async function load({ cookies, params, parent }) {
let { username } = params;
let [amount, currency] = params.amount.split("/");
- if (subject.username === user?.username)
- error(500, { message: "Cannot send to self" });
-
let rate;
if (amount) {
rate = rates[currency ? currency.toUpperCase() : subject.currency];
if (!rate) error(500, "Invalid currency symbol");
if (currency) amount = (amount * sats) / rate;
- let { hash } = await post(
+ let { id } = await post(
"/invoice",
{
invoice: {
@@ -32,7 +29,7 @@ export async function load({ cookies, params, parent }) {
auth(cookies)
);
- redirect(307, `/${username}/invoice/${hash}`);
+ redirect(307, `/${username}/invoice/${id}`);
}
return { amount, rate, subject };