aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-02-20 19:53:49 -0800
committerAdam Soltys <[email protected]>2024-02-20 19:53:49 -0800
commitfbf3cef47c612b9c334917f10c810c797fc77da6 (patch)
treef10d545fae7305e624c91f5333f513d5dc95d413 /src
parent3fbd2514e38d29ff02cd7765d89476bed6530d37 (diff)
downloadcoinos-ui-fbf3cef47c612b9c334917f10c810c797fc77da6.tar.gz
coinos-ui-fbf3cef47c612b9c334917f10c810c797fc77da6.zip
items
Diffstat (limited to 'src')
-rw-r--r--src/components/DeleteItem.svelte47
-rw-r--r--src/components/ItemForm.svelte86
-rw-r--r--src/lib/upload.js3
-rw-r--r--src/locales/en.json2
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.server.js11
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.svelte141
-rw-r--r--src/routes/(app)/[username]/items/[id]/+page.server.js24
-rw-r--r--src/routes/(app)/[username]/items/[id]/+page.svelte9
-rw-r--r--src/routes/(app)/[username]/items/create/+page.server.js17
-rw-r--r--src/routes/(app)/[username]/items/create/+page.svelte4
10 files changed, 234 insertions, 110 deletions
diff --git a/src/components/DeleteItem.svelte b/src/components/DeleteItem.svelte
new file mode 100644
index 00000000..8f7f97ca
--- /dev/null
+++ b/src/components/DeleteItem.svelte
@@ -0,0 +1,47 @@
+<script>
+ import Icon from "$comp/Icon.svelte";
+ import { fail, post } from "$lib/utils";
+ import { invalidate } from "$app/navigation";
+
+ export let item;
+
+ 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 on:submit|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"
+ on:click={cancel}
+ on:keydown={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/ItemForm.svelte b/src/components/ItemForm.svelte
index 044020b7..71114c29 100644
--- a/src/components/ItemForm.svelte
+++ b/src/components/ItemForm.svelte
@@ -1,9 +1,12 @@
<script>
import { t } from "$lib/translations";
import { upload } from "$lib/upload";
- export let item, token;
+ import { fail } from "$lib/utils";
+ import { applyAction, deserialize } from "$app/forms";
+ import Spinner from "$comp/Spinner.svelte";
+ export let item;
- let fileInput, formElement, file;
+ let fileInput, formElement, file, submitting, progress;
let select = () => fileInput.click();
let src;
@@ -30,14 +33,12 @@
if (src) {
try {
- let { hash } = JSON.parse(
- await upload(file, "item", progress, token)
- );
+ let { hash } = JSON.parse(await upload(file, "item", progress));
data.set("image", hash);
await fetch(`/api/public/${hash}.webp`, {
- cache: "reload",
+ cache: "reload",
mode: "no-cors",
});
} catch (e) {
@@ -68,41 +69,66 @@
on:submit|preventDefault={handleSubmit}
bind:this={formElement}
>
+ <input type="hidden" name="id" bind:value={item.id} />
+ <input type="hidden" name="image" bind:value={item.image} />
+
<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="price" class="font-bold mb-1 block">{$t("items.price")}</label>
+ <input name="price" bind:value={item.price} />
+ </div>
+
+ <div class="w-full">
<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 class="grid grid-cols-2 gap-4">
+ <div class="h-64 rounded-2xl overflow-hidden">
+ {#if src}
+ <img
+ {src}
+ alt={item.name}
+ class="object-cover w-full h-full"
+ on:click={select}
+ on:keydown={select}
+ />
+ {:else if item.image}
+ <img
+ src={`/api/public/${item.image}.webp`}
+ alt={item.name}
+ class="object-cover w-full h-full"
+ on:click={select}
+ on:keydown={select}
+ />
+ {:else}
+ <div
+ class="bg-gradient-to-r from-primary to-gradient mb-4 cursor-pointer hover:opacity-80 w-full h-full"
+ on:click={select}
+ on:keydown={select}
+ alt="Banner"
+ />
+ {/if}
+ </div>
</div>
+
+ <input
+ type="file"
+ class="hidden"
+ bind:this={fileInput}
+ on:change={(e) => handleFile(e, "item")}
+ />
</div>
<button
class="rounded-full py-5 px-6 font-bold hover:opacity-80 flex bg-black text-white text-2xl"
>
- {$t("items.submit")}
+ {#if submitting}
+ <Spinner />
+ {:else}
+ {$t("items.submit")}
+ {/if}
</button>
</form>
diff --git a/src/lib/upload.js b/src/lib/upload.js
index 552e4a7a..31c235c6 100644
--- a/src/lib/upload.js
+++ b/src/lib/upload.js
@@ -1,4 +1,4 @@
-export const upload = async (file, type, progress, token) => {
+export const upload = async (file, type, progress) => {
let url = `/api/upload/${type}`;
let formData = new FormData();
formData.append("file", file);
@@ -13,7 +13,6 @@ export const upload = async (file, type, progress, token) => {
});
ajax.upload.addEventListener("progress", progress, false);
ajax.open("POST", url);
- // ajax.setRequestHeader('Authorization', `Bearer ${token}`);
ajax.send(formData);
});
};
diff --git a/src/locales/en.json b/src/locales/en.json
index 24433202..1ad0c931 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -353,7 +353,9 @@
},
"items": {
"add": "Add item",
+ "edit": "Edit item",
"name": "Name",
+ "price": "Price",
"submit": "Submit",
"image": "Image"
}
diff --git a/src/routes/(app)/[username]/(profile)/+page.server.js b/src/routes/(app)/[username]/(profile)/+page.server.js
new file mode 100644
index 00000000..59eb44d5
--- /dev/null
+++ b/src/routes/(app)/[username]/(profile)/+page.server.js
@@ -0,0 +1,11 @@
+import { auth, get } from "$lib/utils";
+
+export async function load({ cookies, depends, parent }) {
+ depends("app:items");
+
+ let { subject } = await parent();
+ let items = await get(`/${subject.id}/items`, auth(cookies));
+ items.map((i) => (i.quantity = 0));
+
+ return { items };
+}
diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte
index bb98ddfe..93b7355c 100644
--- a/src/routes/(app)/[username]/(profile)/+page.svelte
+++ b/src/routes/(app)/[username]/(profile)/+page.svelte
@@ -1,50 +1,27 @@
<script>
- import { btc, f } from "$lib/utils";
+ import { btc, f, sat } from "$lib/utils";
import { onMount } from "svelte";
import Icon from "$comp/Icon.svelte";
import Balance from "$comp/Balance.svelte";
+ import DeleteItem from "$comp/DeleteItem.svelte";
import { t } from "$lib/translations";
export let data;
- let { subject, user, rates } = data;
+ let { subject, user, items, 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",
- },
- ];
+ let refresh = (d) => ({ items, subject, user, rates } = d);
+ let deleting;
$: total = items.reduce((a, b) => a + b.price * b.quantity, 0);
- let del = () => {};
+ let del = (item) => {
+ deleting = item;
+ };
</script>
+{#if deleting}
+ <DeleteItem bind:item={deleting} />
+{/if}
+
<div class="space-y-5">
{#if user?.id === subject.id}
<div class="flex justify-center lg:justify-start">
@@ -86,6 +63,22 @@
</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 class="grid grid-cols-2 gap-4">
{#each items as i}
<div
@@ -93,42 +86,65 @@
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 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"
+ on:click={select}
+ on:keydown={select}
+ alt="Banner"
+ />
+ {/if}
{#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
+ 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>
</div>
- <button class="bg-white rounded-xl">
- <Icon icon="trash" style="w-10" on:click={() => del(i)} />
+ <button
+ class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100"
+ on:click|stopPropagation={() => del(i)}
+ >
+ <Icon icon="trash" style="w-8 mx-auto invert" />
</button>
</div>
{/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 class="bg-white rounded-xl p-2">
+ <div class="flex">
+ <div class="text-2xl mr-auto">{i.name}</div>
+ <div class="flex gap-2 my-auto">
+ <div class="font-semibold">
+ {f(i.price, subject.currency)}
+ </div>
+ <div class="text-secondary">
+ {sat(btc(i.price, rates[subject.currency]))}
</div>
- <div class="text-2xl my-auto">{i.quantity}</div>
- <Icon icon="plus" style="w-10" />
</div>
</div>
+ <div class="flex gap-2">
+ <div
+ class="ml-auto"
+ 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>
@@ -151,19 +167,4 @@
</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
index e1fe2efd..960f9af4 100644
--- a/src/routes/(app)/[username]/items/[id]/+page.server.js
+++ b/src/routes/(app)/[username]/items/[id]/+page.server.js
@@ -1,6 +1,22 @@
-import { get } from "$lib/utils";
-export let load = async ({ cookies, params: { id } }) => {
- let item = await get(`/item/${id}`);
- console.log("item", item)
+import { fd, auth, get, post } from "$lib/utils";
+import { fail, redirect } from "@sveltejs/kit";
+
+ export let load = async ({ cookies, params: { id } }) => {
+ let item = await get(`/items/${id}`);
return { item };
};
+
+export const actions = {
+ default: async ({ cookies, request, url }) => {
+ let form = await fd(request);
+ try {
+ await post(`/items`, form, auth(cookies));
+ } catch (e) {
+ console.log(e);
+ return fail(400, { message: e.message });
+ }
+
+ let success = `/${url.pathname.split("/")[1]}`;
+ redirect(307, success);
+ },
+};
diff --git a/src/routes/(app)/[username]/items/[id]/+page.svelte b/src/routes/(app)/[username]/items/[id]/+page.svelte
index 5a19e892..ddf4cf1d 100644
--- a/src/routes/(app)/[username]/items/[id]/+page.svelte
+++ b/src/routes/(app)/[username]/items/[id]/+page.svelte
@@ -1,7 +1,14 @@
<script>
+ import { t } from "$lib/translations";
import ItemForm from "$comp/ItemForm.svelte";
export let data;
let { item } = data;
+ console.log(item)
</script>
-<ItemForm {item} />
+<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.edit")}
+ </h1>
+ <ItemForm {item} />
+</div>
diff --git a/src/routes/(app)/[username]/items/create/+page.server.js b/src/routes/(app)/[username]/items/create/+page.server.js
new file mode 100644
index 00000000..ea0571e7
--- /dev/null
+++ b/src/routes/(app)/[username]/items/create/+page.server.js
@@ -0,0 +1,17 @@
+import { fail, redirect } from "@sveltejs/kit";
+import { fd, auth, get, post } from "$lib/utils";
+
+export const actions = {
+ default: async ({ cookies, request, url }) => {
+ let form = await fd(request);
+ try {
+ await post("/items", form, auth(cookies));
+ } catch (e) {
+ console.log(e);
+ return fail(400, { message: e.message });
+ }
+
+ let success = `/${url.pathname.split('/')[1]}`
+ redirect(307, success);
+ },
+};
diff --git a/src/routes/(app)/[username]/items/create/+page.svelte b/src/routes/(app)/[username]/items/create/+page.svelte
index c9aeae1d..46ee8e0c 100644
--- a/src/routes/(app)/[username]/items/create/+page.svelte
+++ b/src/routes/(app)/[username]/items/create/+page.svelte
@@ -1,8 +1,6 @@
<script>
import { t } from "$lib/translations";
import ItemForm from "$comp/ItemForm.svelte";
- export let data;
- let { token } = data;
let item = {};
</script>
@@ -10,5 +8,5 @@
<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} />
+ <ItemForm {item} />
</div>