aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-05-17 09:21:45 -0700
committerAdam Soltys <[email protected]>2024-05-17 09:21:45 -0700
commit7c8cbe1c0b41d223e20823e2896230575a46bad9 (patch)
tree14cad0877cb99551645e496f562143caa9f304ae /src
parenta8bb93d408f82e79dac8c98b6a11049674cbf3e7 (diff)
downloadcoinos-ui-7c8cbe1c0b41d223e20823e2896230575a46bad9.tar.gz
coinos-ui-7c8cbe1c0b41d223e20823e2896230575a46bad9.zip
updates from master
Diffstat (limited to 'src')
-rw-r--r--src/routes/(app)/[username]/invoice/[id]/+layout.server.js3
-rw-r--r--src/routes/(app)/[username]/invoice/[id]/+page.svelte141
-rw-r--r--src/routes/(app)/[username]/invoice/[id]/memo/+page.server.js13
-rw-r--r--src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte95
-rw-r--r--src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte9
-rw-r--r--src/routes/(app)/send/+layout.svelte4
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.server.js38
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.svelte110
-rw-r--r--src/service-worker.js5
9 files changed, 291 insertions, 127 deletions
diff --git a/src/routes/(app)/[username]/invoice/[id]/+layout.server.js b/src/routes/(app)/[username]/invoice/[id]/+layout.server.js
index 6f9ae4a2..c9920052 100644
--- a/src/routes/(app)/[username]/invoice/[id]/+layout.server.js
+++ b/src/routes/(app)/[username]/invoice/[id]/+layout.server.js
@@ -13,7 +13,7 @@ export async function load({ depends, params, url, parent }) {
if (
user &&
invoice.uid !== user.id &&
- !url.pathname.includes("tip") &&
+ !(url.pathname.includes("tip") || url.pathname.includes("memo")) &&
!options
) {
redirect(307, `/send/invoice/${id}`);
@@ -34,5 +34,6 @@ export async function load({ depends, params, url, parent }) {
}
let src = Qr.drawImg(invoice.text || "", { size: 340 });
+
return { id, invoice, src };
}
diff --git a/src/routes/(app)/[username]/invoice/[id]/+page.svelte b/src/routes/(app)/[username]/invoice/[id]/+page.svelte
index 1457025d..1a569039 100644
--- a/src/routes/(app)/[username]/invoice/[id]/+page.svelte
+++ b/src/routes/(app)/[username]/invoice/[id]/+page.svelte
@@ -1,7 +1,8 @@
<script>
- import { enhance } from "$app/forms";
+ import { enhance } from "$app/forms";
import { send } from "$lib/socket";
import {
+ btc,
post,
back,
copy,
@@ -15,7 +16,7 @@
} from "$lib/utils";
import { tick, onMount, onDestroy } from "svelte";
import { browser } from "$app/environment";
- import { last } from "$lib/store";
+ import { last, showQr } from "$lib/store";
import Avatar from "$comp/Avatar.svelte";
import Icon from "$comp/Icon.svelte";
import Heart from "$comp/Heart.svelte";
@@ -26,6 +27,7 @@
export let data;
let ndef;
+ let showOptions;
let reading = async ({ message, serialNumber }) => {
let name = serialNumber.replace(/:/g, "-");
@@ -41,16 +43,11 @@
hash,
type,
rate,
- received,
- prompt,
text,
tip,
- request_id,
user: { username, currency },
} = invoice;
- let showQr = true;
-
let qr;
let tipPercent = 0;
@@ -61,8 +58,6 @@
hash,
type,
rate,
- received,
- prompt,
text,
tip,
user: { username, currency },
@@ -120,12 +115,12 @@
user: { username, currency },
}));
- goto(`./${id}`, { invalidateAll: true, noScroll: true });
+ goto(`./${id}?options=true`, { invalidateAll: true, noScroll: true });
};
</script>
-<div class="invoice container mx-auto max-w-xl px-4 space-y-5">
- {#if showQr}
+<div class="invoice container mx-auto max-w-xl px-4 space-y-2">
+ {#if $showQr}
<div>
<a
href={[types.bitcoin, types.liquid].includes(invoice.type)
@@ -142,6 +137,21 @@
</div>
{/if}
+ {#each invoice.items as i}
+ <div class="grid grid-cols-12 text-xl">
+ <div class="col-span-1 my-auto">{i.quantity}</div>
+ <div class="mr-auto grow col-span-7 my-auto">
+ {i.name}
+ </div>
+ <div class="col-span-2 font-semibold text-right my-auto">
+ {f(i.price * i.quantity, currency)}
+ </div>
+ <div class="col-span-2 text-secondary text-right text-lg my-auto">
+ {sat(btc(i.price * i.quantity, rate))}
+ </div>
+ </div>
+ {/each}
+
{#if amount > 0}
<div class="text-center font-bold text-2xl">
<div>
@@ -154,7 +164,7 @@
{/if}
</div>
<div>
- <span class="text-secondary font-normal text-lg"
+ <span class="text-secondary font-normal text-xl"
>⚡️{`${s(amount)}`}</span
>
@@ -167,10 +177,57 @@
</div>
{/if}
- <div class="flex justify-center gap-2">
+ <button
+ type="button"
+ class="flex gap-2 text-center break-all rounded-2xl hover:opacity-80 py-5 px-6 w-full mx-auto justify-center border text-xl whitespace-nowrap"
+ on:click={() => copy(txt)}
+ >
+ <Icon icon="copy" style="w-8 my-auto" />
+ <div class="my-auto">
+ {txt.substr(0, 11)}..{txt.substr(-10)}
+ </div>
+ </button>
+
+ <div
+ class="w-full flex justify-center gap-2 flex-wrap text-secondary text-xl"
+ >
+ <a href={link} class="w-full">
+ <button
+ class="w-full flex justify-center rounded-2xl border py-5 px-6 hover:opacity-80"
+ >
+ <Icon icon="mobile" style="mr-1 w-8" />
+ <div class="my-auto">{$t("payments.openLink")}</div>
+ </button>
+ </a>
+
+ <button
+ class="w-full flex justify-center rounded-2xl border py-5 px-6 hover:opacity-80"
+ on:click={() => ($showQr = !$showQr)}
+ >
+ <Icon icon="qr" style="w-8 mr-1 invert my-auto" />
+ <div class="my-auto">
+ {$showQr ? $t("payments.hide") : $t("payments.show")}
+ {$t("payments.qr")}
+ </div></button
+ >
+
+ <!-- <button -->
+ <!-- class="w-full flex justify-center rounded-2xl border py-3 px-5 hover:opacity-80 text-lg" -->
+ <!-- on:click={() => (showOptions = !showOptions)} -->
+ <!-- > -->
+ <!-- <Icon icon="settings" style="w-8 mr-1 my-auto" /> -->
+ <!-- <div class="my-auto"> -->
+ <!-- {showOptions ? $t("payments.hide") : $t("payments.show")} -->
+ <!-- {$t("payments.options")} -->
+ <!-- </div></button -->
+ <!-- > -->
+ </div>
+
+ <div class="flex justify-around text-secondary">
<button
- class="hover:bg-neutral-700 my-auto flex gap-1 p-2"
- class:bg-neutral-700={type === types.bitcoin}
+ class="hover:bg-primary my-auto flex gap-1 sm:gap-2 py-3 px-2 sm:px-5 w-full justify-center"
+ class:bg-primary={type === types.bitcoin}
+ class:text-black={type === types.bitcoin}
on:click={() => setType(types.bitcoin)}
>
<img src="/images/bitcoin.svg" class="w-8" alt="Bitcoin" />
@@ -178,8 +235,9 @@
</button>
<button
- class="hover:bg-neutral-700 my-auto flex gap-1 p-2"
- class:bg-neutral-700={type === types.liquid}
+ class="hover:bg-primary my-auto flex gap-1 sm:gap-2 py-3 px-2 sm:px-5 w-full justify-center"
+ class:bg-primary={type === types.liquid}
+ class:text-black={type === types.liquid}
on:click={() => setType(types.liquid)}
>
<img src="/images/liquid.svg" class="w-8" alt="Liquid" />
@@ -187,11 +245,12 @@
</button>
<button
- class="hover:bg-neutral-700 flex gap-1 p-2"
- class:bg-neutral-700={type === types.lightning}
+ class="hover:bg-primary flex gap-1 sm:gap-2 py-3 px-2 sm:px-5 w-full justify-center"
+ class:bg-primary={type === types.lightning}
+ class:text-black={type === types.lightning}
on:click={() => setType(types.lightning)}
>
- <div class="bg-black rounded-full w-8 h-8 text-center flex">
+ <div class="bg-white rounded-full w-8 h-8 text-center flex">
<div class="m-auto">⚡️</div>
</div>
<div class="my-auto text-lg">Lightning</div>
@@ -200,45 +259,13 @@
{#if type === types.liquid}
<div class="flex justify-center">
- <div class="my-auto text-xl text-center">
- We only support <span class="text-teal-500 font-bold">L-BTC</span>,
- don't deposit any other assets
+ <div class="my-auto text-xl text-center text-secondary">
+ {$t("payments.onlyLbtc")}
+ <span class="text-teal-500 font-bold">L-BTC</span>,
+ {$t("payments.dontDeposit")}
</div>
</div>
{/if}
-
- <button
- type="button"
- class="flex gap-2 text-center break-all rounded-full text-white bg-black border hover:opacity-80 p-4 w-full md:w-80 mx-auto text-xl justify-center"
- on:click={() => copy(txt)}
- >
- <Icon icon="copy" style="w-8 my-auto" />
- <div class="my-auto font-semibold">
- {txt.substr(0, 6)} ... {txt.substr(-10)}
- </div>
- </button>
-
- <div class="w-full flex justify-center gap-2 flex-wrap">
- <a href={link} class="w-full md:w-auto">
- <button
- class="w-full md:w-auto flex justify-center rounded-full border py-3 px-5 hover:opacity-80 font-semibold"
- >
- <Icon icon="mobile" style="mr-1 w-6 invert" />
- <div class="text-secondary">{$t("payments.openLink")}</div>
- </button>
- </a>
-
- <button
- class="w-full md:w-auto flex justify-center rounded-full border py-3 px-5 hover:opacity-80 font-semibold"
- on:click={() => (showQr = !showQr)}
- >
- <Icon icon="qr" style="mr-1" />
- <div class="text-secondary">
- {showQr ? $t("payments.hide") : $t("payments.show")}
- {$t("payments.qr")}
- </div></button
- >
- </div>
</div>
<style>
diff --git a/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.js b/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.js
new file mode 100644
index 00000000..58d56018
--- /dev/null
+++ b/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.js
@@ -0,0 +1,13 @@
+import invoice from "$lib/invoice";
+import { redirect } from "@sveltejs/kit";
+
+export async function load({ parent, params }) {
+ let { invoice } = await parent();
+ if (!invoice.amount) {
+ redirect(307, `/${params.username}/invoice/${invoice.id}`);
+ }
+}
+
+export const actions = {
+ default: invoice,
+};
diff --git a/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte b/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte
new file mode 100644
index 00000000..4d23ff19
--- /dev/null
+++ b/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte
@@ -0,0 +1,95 @@
+<script>
+ import { onMount } from "svelte";
+ import { browser } from "$app/environment";
+ import { invoice as inv, request } from "$lib/store";
+ import {
+ copy,
+ select,
+ f,
+ sat,
+ get,
+ reverseFormat,
+ s,
+ sats,
+ } from "$lib/utils";
+ import Icon from "$comp/Icon.svelte";
+ import { t } from "$lib/translations";
+ import { enhance } from "$app/forms";
+
+ let submitting;
+ let submit;
+
+ export let data;
+ $: refresh(data);
+ let { invoice, id, user, rates } = data;
+ let {
+ amount,
+ hash,
+ items,
+ memoPrompt,
+ type,
+ rate,
+ received,
+ prompt,
+ text,
+ tip,
+ user: { username, currency },
+ } = invoice;
+
+ invoice.memo = user?.username;
+
+ let refresh = (data) => {
+ $inv = null;
+
+ ({ invoice, id } = data);
+ ({
+ amount,
+ hash,
+ items,
+ memoPrompt,
+ type,
+ received,
+ prompt,
+ text,
+ tip,
+ user: { username },
+ } = invoice);
+ };
+</script>
+
+<form
+ method="POST"
+ use:enhance
+ class:invisible={submitting}
+ class="container px-4 max-w-lg mx-auto space-y-5"
+>
+ <input type="hidden" name="amount" value={amount} />
+ <input type="hidden" name="tip" value={tip} />
+ <input type="hidden" name="username" value={username} />
+ <input type="hidden" name="rate" value={invoice.rate} />
+ <input type="hidden" name="memoPrompt" value={invoice.memoPrompt} />
+ <input type="hidden" name="prompt" value={invoice.prompt} />
+ <input type="hidden" name="type" value={type} />
+ <input type="hidden" name="hash" value={hash} />
+ <input type="hidden" name="items" value={JSON.stringify(items)} />
+
+ <h1 class="text-4xl font-semibold text-center">{$t("invoice.addMemo")}</h1>
+ <div class="space-y-2">
+ <input
+ use:select
+ name="memo"
+ class="w-full p-4 border rounded-xl text-xl"
+ bind:value={invoice.memo}
+ autocapitalize="none"
+ />
+ <div class="text-secondary">{invoice.memoPrompt}</div>
+ </div>
+
+ <button
+ type="submit"
+ bind:this={submit}
+ class="bg-black text-white border rounded-2xl px-6 py-5 w-full font-bold"
+ >
+ {$t("payments.next")}
+ </button>
+</form>
diff --git a/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte b/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte
index f253936b..35b24bf1 100644
--- a/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte
+++ b/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte
@@ -61,6 +61,7 @@
let {
amount,
hash,
+ items,
type,
rate,
received,
@@ -82,6 +83,7 @@
({
amount,
hash,
+ items,
type,
received,
prompt,
@@ -116,8 +118,11 @@
<input type="hidden" name="prompt" value="false" />
<input type="hidden" name="type" value={type} />
<input type="hidden" name="hash" value={hash} />
+ <input type="hidden" name="items" value={JSON.stringify(items)} />
- <input type="hidden" name="request_id" value={invoice.request?.id} />
+ {#if invoice.memoPrompt}
+ <input type="hidden" name="memoPrompt" value={invoice.memoPrompt} />
+ {/if}
<h1 class="text-4xl font-semibold my-8">{$t("invoice.addTipq")}</h1>
{#if !showCustomAmount}
@@ -199,6 +204,6 @@
}
.container button[type="button"] {
- @apply w-full mt-2 bg-black text-white border hover:bg-white hover:text-black font-semibold py-5 px-7 rounded-2xl;
+ @apply w-full mt-2 bg-primary text-black hover:bg-black hover:text-white font-semibold py-5 px-7 rounded-2xl;
}
</style>
diff --git a/src/routes/(app)/send/+layout.svelte b/src/routes/(app)/send/+layout.svelte
index 0f412759..9e14fa39 100644
--- a/src/routes/(app)/send/+layout.svelte
+++ b/src/routes/(app)/send/+layout.svelte
@@ -9,8 +9,8 @@
let cancel = () => goto(`/${user.username}`);
</script>
-{#if user.haspin && (!$pin || $pin?.length !== 6)}
+{#if user?.haspin && (!$pin || $pin?.length !== 6)}
<Pin bind:value={$pin} {cancel} />
{/if}
-<slot /> \ No newline at end of file
+<slot />
diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.js b/src/routes/(app)/send/invoice/[id]/+page.server.js
index 88017362..933993a2 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.server.js
+++ b/src/routes/(app)/send/invoice/[id]/+page.server.js
@@ -2,35 +2,22 @@ import { error, fail, redirect } from "@sveltejs/kit";
import { fd, auth, get, post } from "$lib/utils";
export async function load({ params: { id }, parent, url }) {
- let { user } = await parent();
+ let { rates, user } = await parent();
- let {
- amount,
- address,
- currency,
- hash,
- rate,
- prompt,
- tip,
- text,
- user: recipient,
- } = await get(`/invoice/${id}`);
+ let invoice = await get(`/invoice/${id}`);
- if (prompt && tip === null)
- redirect(307, `/${recipient.username}/invoice/${id}/tip`);
- if (recipient.username === user.username)
+ if (invoice.prompt && invoice.tip === null)
+ redirect(307, `/${invoice.user.username}/invoice/${id}/tip`);
+
+ if (invoice.memoPrompt && invoice.memo === null)
+ redirect(307, `/${invoice.user.username}/invoice/${id}/memo`);
+
+ if (invoice.user.username === user?.username)
error(500, { message: "Cannot send to self" });
- return {
- amount,
- address,
- currency,
- hash,
- tip,
- rate,
- payreq: text,
- recipient,
- };
+ if (!user) redirect(307, `/${invoice.user.username}/invoice/${id}`);
+
+ return { invoice, rates, user };
}
export const actions = {
@@ -41,6 +28,7 @@ export const actions = {
await post("/payments", body, auth(cookies));
} catch (e) {
+ console.log("payment failed", id, e);
return fail(400, { message: e.message });
}
diff --git a/src/routes/(app)/send/invoice/[id]/+page.svelte b/src/routes/(app)/send/invoice/[id]/+page.svelte
index c2163a81..de08ac54 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.svelte
+++ b/src/routes/(app)/send/invoice/[id]/+page.svelte
@@ -9,22 +9,34 @@
import Numpad from "$comp/Numpad.svelte";
import Spinner from "$comp/Spinner.svelte";
import { page } from "$app/stores";
- import { post, back, f, fiat as toFiat, s, sats, focus } from "$lib/utils";
+ import {
+ btc,
+ sat,
+ post,
+ back,
+ f,
+ fiat as toFiat,
+ s,
+ sats,
+ focus,
+ } from "$lib/utils";
export let data;
export let form;
- let { address, hash, payreq, recipient, tip, rates, user } = data;
+ let { invoice, rates, user } = data;
+ let { address, hash, payreq, user: recipient, tip } = invoice;
let { currency } = user;
$: reload(data);
let reload = (data) => {
- ({ address, hash, payreq, recipient, tip, rates, user } = data);
+ ({ invoice, rates, user } = data);
+ ({ address, hash, payreq, user: recipient, tip } = invoice);
({ currency } = user);
};
- $: rate = data.rate * (rates[user.currency] / rates[data.currency]);
+ $: rate = invoice.rate * (rates[user.currency] / rates[invoice.currency]);
- let amount = form?.amount || data.amount;
+ let amount = form?.amount || invoice.amount;
let a,
af,
amountFiat = amount * (rate / sats),
@@ -35,13 +47,17 @@
amountFiat = af;
};
- let loading;
- let submit = () => (loading = true);
+ let submitting;
+ let submit = () => (submitting = true);
let external = async () => {
- let invoice = { type: "lightning", amount, currency };
let { id } = await post(`/${recipient.username}/invoice`, {
- invoice,
+ invoice: {
+ ...invoice,
+ type: "lightning",
+ amount,
+ currency,
+ },
user: { username: recipient.username },
});
@@ -52,12 +68,12 @@
$: update(form);
let update = () => {
- if (form?.message.includes("pin")) $pin = undefined;
- loading = false;
+ if (form?.message?.includes("pin")) $pin = undefined;
+ submitting = false;
};
// onMount(async () => {
- // if (browser && window.NDEFReader) {
+ // if (browser && window.NDEFReader && user.nfc) {
// try {
// let ndef = new NDEFReader();
// await ndef.scan();
@@ -86,12 +102,12 @@
</div>
{/if}
-<div class="container px-4 max-w-xl mx-auto">
+<div class="container px-4 max-w-xl mx-auto text-center space-y-5">
{#if amount}
- <div class="text-center mb-8">
- <h1 class="text-xl md:text-2xl text-secondary mb-2">
- {$t("payments.send")}
- </h1>
+ <h1 class="text-4xl font-bold">
+ {$t("payments.send")}
+ </h1>
+ <div>
<h2 class="text-2xl md:text-3xl font-semibold">
{f(toFiat(amount, rate), currency)}
{#if tip}
@@ -100,7 +116,7 @@
</span>
{/if}
</h2>
- <h3 class="text-secondary md:text-lg mb-6 mt-1">
+ <h3 class="text-secondary md:text-lg mt-1">
⚡️{s(amount)}
{#if tip}
@@ -109,26 +125,39 @@
</span>
{/if}
</h3>
+ </div>
- <h1 class="text-xl md:text-2xl text-secondary mb-2">
- {$t("payments.to")}
- </h1>
+ <h1 class="text-xl md:text-2xl text-secondary">
+ {$t("payments.to")}
+ </h1>
- <div class="flex p-1 gap-2 justify-center">
- {#if recipient.username.includes("@classic")}
- <img
- src="/images/classic.png"
- class="w-24 border-4 border-transparent mr-1"
- alt="Bitcoin"
- />
- {:else}
- <Avatar user={recipient} size={"20"} />
- {/if}
- <p class="text-4xl break-words my-auto">
- {recipient.username.replace("@classic", "")}
- </p>
- </div>
+ <div class="flex p-1 gap-2 justify-center">
+ <Avatar user={recipient} size={"20"} />
+ <p class="text-4xl break-words my-auto">
+ {recipient.username}
+ </p>
</div>
+
+ {#if invoice.items.length}
+ <h1 class="text-xl md:text-2xl text-secondary">
+ {$t("payments.for")}
+ </h1>
+
+ {#each invoice.items as i}
+ <div class="grid grid-cols-4 text-xl">
+ <div class="mr-auto grow col-span-2">
+ <span class="mr-2">{i.quantity}</span>
+ {i.name}
+ </div>
+ <div class="font-semibold text-right">
+ {f(i.price * i.quantity, invoice.currency)}
+ </div>
+ <div class="text-secondary text-right text-lg my-auto">
+ {sat(btc(i.price * i.quantity, invoice.rate))}
+ </div>
+ </div>
+ {/each}
+ {/if}
{:else}
<Numpad
bind:amount={a}
@@ -146,14 +175,15 @@
<input name="username" value={recipient.username} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
- <div class="flex w-full">
+ <div class="flex w-full text-xl">
{#if amount}
<button
use:focus
type="submit"
- class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24"
+ class="opacity-100 hover:opacity-80'} rounded-2xl border py-5 font-bold mx-auto mt-2 bg-black text-white px-6 w-40"
+ disabled={submitting}
>
- {#if loading}
+ {#if submitting}
<Spinner />
{:else}
{$t("payments.send")}
@@ -162,7 +192,7 @@
{:else}
<button
type="button"
- class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24"
+ class="opacity-100 hover:opacity-80'} rounded-2xl border py-5 font-bold mx-auto mt-2 bg-black text-white px-6 w-40"
on:click={setAmount}
>
{$t("payments.next")}
@@ -170,7 +200,7 @@
{/if}
</div>
</form>
- <div class="flex my-10">
+ <div class="flex my-10 text-xl">
<button class="mx-auto" on:click={external}
>{$t("payments.moreOptions")}</button
>
diff --git a/src/service-worker.js b/src/service-worker.js
new file mode 100644
index 00000000..51cbd1f8
--- /dev/null
+++ b/src/service-worker.js
@@ -0,0 +1,5 @@
+import { build, files, version } from "$service-worker";
+
+self.addEventListener("install", (event) => {});
+self.addEventListener("activate", (event) => {});
+ self.addEventListener("fetch", (event) => {});