aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/send
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2024-08-18 13:09:41 -0700
committerAdam Soltys <[email protected]>2024-08-18 22:15:05 -0700
commitd66cba2d111bec3a2bd57a56233577f3fd417b18 (patch)
tree5cf0250363d11fb33414d8cae4f583e186247123 /src/routes/(app)/send
parent09d4867fe0ddc8cbc7bfa670911fe5c33a0a4f36 (diff)
downloadcoinos-ui-d66cba2d111bec3a2bd57a56233577f3fd417b18.tar.gz
coinos-ui-d66cba2d111bec3a2bd57a56233577f3fd417b18.zip
ecash
Diffstat (limited to 'src/routes/(app)/send')
-rw-r--r--src/routes/(app)/send/[...text]/+page.server.js91
-rw-r--r--src/routes/(app)/send/[...text]/+page.svelte34
-rw-r--r--src/routes/(app)/send/ecash/+page.server.js19
-rw-r--r--src/routes/(app)/send/ecash/+page.svelte60
4 files changed, 110 insertions, 94 deletions
diff --git a/src/routes/(app)/send/[...text]/+page.server.js b/src/routes/(app)/send/[...text]/+page.server.js
index 3e8623eb..c1ba5945 100644
--- a/src/routes/(app)/send/[...text]/+page.server.js
+++ b/src/routes/(app)/send/[...text]/+page.server.js
@@ -1,98 +1,19 @@
-import { validate } from "bitcoin-address-validation";
-import bip21 from "bip21";
-import { auth, get, isLiquid, post } from "$lib/utils";
+import { auth, get } from "$lib/utils";
import { fail, redirect } from "@sveltejs/kit";
-import { PUBLIC_DOMAIN } from "$env/static/public";
-
-let parse = async (t, host) => {
- if (!t) return;
-
- if (t.startsWith("http")) redirect(307, t);
- if (t.startsWith(host)) redirect(307, `http://${t}`);
-
- let amount, user, id;
-
- t = t.trim();
- t.toLowerCase().startsWith("bitcoin:") &&
- ({
- address: t,
- options: { amount },
- } = bip21.decode(t));
-
- if (t.startsWith("lightning:")) t = t.replace("lightning:", "");
- if (t.endsWith(`@${PUBLIC_DOMAIN}`)) t = t.split("@")[0];
- if (t.includes("@") && t.includes(".")) {
- try {
- t = await get(`/encode?address=${t}`);
- } catch (e) {}
- }
-
- if (t.includes("/fund")) redirect(307, t.substring(t.indexOf("/fund")));
-
- // lightning
- if (t.toLowerCase().startsWith("lightning:"))
- t = t.toLowerCase().replace("lightning:", "");
- if (t.toLowerCase().startsWith("lnurl")) redirect(307, `/ln/${t}`);
- if (t.includes(":")) t = t.split(":")[1];
-
- if (t.toLowerCase().startsWith("ln")) {
- try {
- ({ id } = await get(`/invoice/${t}`));
- } catch (e) {
- redirect(307, `/send/lightning/${t}`);
- }
- }
-
- // bitcoin
- if (validate(t) || isLiquid(t)) {
- try {
- ({ id, user } = await get(`/invoice/${t}`));
- } catch (e) {
- let r = `/send/bitcoin/${t}`;
- if (amount) r += "/" + amount;
- redirect(307, r);
- }
-
- if (user) redirect(307, `/pay/${user.username}`);
- else if (id) redirect(307, `/send/${id}`);
- }
-
- // user
- try {
- user = await get(`/users/${t.split("/")[0]}`);
- if (user.anon) user = null;
- } catch (e) {}
-
- if (user) redirect(307, `/pay/${t}`);
-
- let fund;
- try {
- fund = await get(`/fund/${t}`);
- } catch (e) {}
-
- if (fund) redirect(307, `/send/fund/${t}`);
-
- // invoice
- let invoice;
- try {
- invoice = await get(`/invoice/${t}`);
- } catch (e) {}
-
- if (invoice) redirect(307, `/send/invoice/${invoice.id}`);
-};
+import parse from "$lib/parse";
export async function load({ cookies, params, request, url }) {
let { text } = params;
- await parse(text, url.host);
+ await parse(text, url.host, cookies);
let contacts = await get("/contacts", auth(cookies));
return { contacts };
}
export const actions = {
- default: async ({ request, url }) => {
+ default: async ({ cookies, request, url }) => {
const form = await request.formData();
let t = form.get("text");
- await parse(t, url.host);
- return fail(400, { error: true });
+ let msg = await parse(t, url.host, cookies);
+ return fail(400, { error: msg || "default" });
},
};
diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte
index f9267105..e677760f 100644
--- a/src/routes/(app)/send/[...text]/+page.svelte
+++ b/src/routes/(app)/send/[...text]/+page.svelte
@@ -16,15 +16,17 @@
data.subject = data.user;
let { contacts } = data;
- let w;
- let el, text;
+ let el, text, pasted, w;
let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click());
let paste = async () => {
text = await navigator.clipboard.readText();
+ pasted = true;
};
+
+ $: if (browser && pasted && text) el.click() && (pasted = false);
</script>
<svelte:window bind:innerWidth={w} />
@@ -39,7 +41,9 @@
{#if form?.error}
<div class="mb-5">
<div class="text-red-600">
- {$t("error.unrecognizedInput")}
+ {form.error === "default"
+ ? $t("error.unrecognizedInput")
+ : form.error}
</div>
</div>
{/if}
@@ -52,6 +56,7 @@
on:keypress={keypress}
class="w-full p-4 border rounded-xl h-48 text-xl"
bind:value={text}
+ on:paste={() => (pasted = true)}
autocapitalize="none"
/>
</div>
@@ -60,19 +65,19 @@
<a href="/scan" class="w-full">
<button
type="button"
- class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center"
+ class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center gap-2"
>
- <Icon icon="camera" style="mr-2 w-6 my-auto" />
+ <Icon icon="camera" style="w-8 my-auto" />
<div class="my-auto">{$t("user.send.scan")}</div>
</button>
</a>
<button
type="button"
- class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center"
+ class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center gap-2"
on:click={paste}
>
- <Icon icon="paste" style="mr-2 w-6 my-auto" />
+ <Icon icon="paste" style="w-8 my-auto" />
<div class="my-auto">{$t("user.send.paste")}</div>
</button>
</div>
@@ -80,12 +85,23 @@
<button
bind:this={el}
type="submit"
- class="bg-black text-white border rounded-2xl px-6 py-5 w-full font-bold"
+ class="flex bg-black text-white border rounded-2xl px-6 py-5 w-full font-bold gap-2 justify-center"
>
- {$t("user.send.next")}
+ <Icon icon="send" style="w-8 my-auto invert" />
+ <div class="my-auto">{$t("user.send.next")}</div>
</button>
</form>
+ <a href="/send/ecash">
+ <button
+ type="button"
+ class="flex border rounded-2xl px-6 py-5 w-full font-bold gap-2 justify-center text-xl"
+ >
+ <Icon icon="voucher" style="w-8 my-auto" />
+ <div class="my-auto">{$t("payments.createEcash")}</div>
+ </button>
+ </a>
+
{#if contacts.length}
<div class="space-y-5">
<h1 class="px-3 md:px-0 text-2xl font-semibold mt-10">
diff --git a/src/routes/(app)/send/ecash/+page.server.js b/src/routes/(app)/send/ecash/+page.server.js
new file mode 100644
index 00000000..2fb43a2f
--- /dev/null
+++ b/src/routes/(app)/send/ecash/+page.server.js
@@ -0,0 +1,19 @@
+import { fail, redirect } from "@sveltejs/kit";
+import { auth, post, fd } from "$lib/utils";
+
+export const actions = {
+ default: async ({ cookies, request }) => {
+ let token;
+ try {
+ let body = await fd(request);
+ ({ token } = await post("/mint", body, auth(cookies)));
+ } catch (e) {
+ console.log("problem creating ecash", e);
+ return fail(400, { message: e.message });
+ }
+
+ cookies.set("ecash", token, { path: "/" });
+
+ redirect(307, `/${cookies.get("username")}/ecash`);
+ },
+};
diff --git a/src/routes/(app)/send/ecash/+page.svelte b/src/routes/(app)/send/ecash/+page.svelte
new file mode 100644
index 00000000..d8e2dd46
--- /dev/null
+++ b/src/routes/(app)/send/ecash/+page.svelte
@@ -0,0 +1,60 @@
+<script>
+ import { enhance } from "$app/forms";
+ import { t } from "$lib/translations";
+ import Icon from "$comp/Icon.svelte";
+ import Numpad from "$comp/Numpad.svelte";
+ import { page } from "$app/stores";
+ import { rate } from "$lib/store";
+ import { fail, s } from "$lib/utils";
+
+ export let data;
+
+ let { rates, user } = data;
+ let { balance, currency, username } = user;
+
+ let amount = 0;
+ let submit, fiat;
+
+ $: update(data);
+ let update = () => ($rate = data.rates[currency]);
+
+ let setMax = () => {
+ fiat = false;
+ amount = balance;
+ };
+</script>
+
+<a href="/send">
+ <button type="button" class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80">
+ <Icon icon="arrow-left" style="w-10" />
+ </button>
+</a>
+
+<div class="container px-4 max-w-xl mx-auto space-y-5 text-center">
+ <h1 class="text-3xl md:text-4xl font-semibold mb-2">
+ {$t("payments.createEcash")}
+ </h1>
+
+ <form use:enhance method="POST">
+ <Numpad bind:amount bind:fiat {currency} {submit} bind:rate={$rate} />
+ <input type="hidden" name="amount" bind:value={amount}/>
+
+ <div class="flex justify-center gap-2">
+ <button
+ type="button"
+ class="hover:opacity-80 bg-black text-white rounded-2xl py-3 px-4 mt-2 border font-bold"
+ on:click|preventDefault={setMax}
+ on:keydown={setMax}>Max ⚡️{s(balance)}</button
+ >
+
+ <button
+ use:focus
+ bind:this={submit}
+ type="submit"
+ class="opacity-100 hover:opacity-80 rounded-2xl border py-3 font-bold mt-2 bg-black text-white px-4 w-24"
+ >
+ {$t("payments.next")}
+ </button>
+ </div>
+ </form>
+</div>