diff options
| author | Adam Soltys <[email protected]> | 2024-02-23 12:19:53 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-02-23 12:19:53 -0800 |
| commit | 4585996d3fcace056993d3f0c6959cd7f31e4438 (patch) | |
| tree | 5f35d3a82df97bbe3744d8346e41ae567cf0c754 | |
| parent | 3ab1bc1fcc96f78bcc3fb7bc6ff9f84fc75c7c41 (diff) | |
| download | coinos-ui-4585996d3fcace056993d3f0c6959cd7f31e4438.tar.gz coinos-ui-4585996d3fcace056993d3f0c6959cd7f31e4438.zip | |
payment memos
18 files changed, 134 insertions, 184 deletions
diff --git a/src/lib/invoice.js b/src/lib/invoice.js index d2f70146..98f6f2ca 100644 --- a/src/lib/invoice.js +++ b/src/lib/invoice.js @@ -6,17 +6,16 @@ export default async ({ cookies, request, url }) => { let rates = await get("/rates"); let amount = parseInt(form.get("amount")); - let request_id = form.get("request_id"); - if (request_id === "undefined") request_id = undefined; let invoice = { amount, items: JSON.parse(form.get("items")), + memo: form.get("memo"), + memoPrompt: form.get("memoPrompt"), tip: parseInt(form.get("tip")) || 0, type: form.get("type"), prompt: form.get("prompt") === "true", rate: parseFloat(form.get("rate")) || rates[form.get("currency")], - request_id, }; let user = { username: form.get("username"), currency: form.get("currency") }; @@ -24,14 +23,12 @@ export default async ({ cookies, request, url }) => { invoice = await post("/invoice", { invoice, user }, auth(cookies)); let { id } = invoice; - if (request_id) { - if (url.pathname.endsWith("tip")) { - redirect(307, `/send/invoice/${id}`); - } + if (invoice.prompt && invoice.tip === null) + redirect(307, `/${user.username}/invoice/${id}/tip`); - redirect(307, `/${user.username}/request/${request_id}`); + if (invoice.memoPrompt && !invoice.memo) { + redirect(307, `/${user.username}/invoice/${id}/memo`); } - if (invoice.prompt) redirect(307, `/${user.username}/invoice/${id}/tip`); else redirect(307, `/${user.username}/invoice/${id}`); }; diff --git a/src/lib/utils.js b/src/lib/utils.js index 8e3ff004..0b76365c 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -227,6 +227,9 @@ export let back = () => export let focus = (el) => browser && screen.width > 1280 && setTimeout(() => el.focus(), 1); +export let select = (el) => + browser && screen.width > 1280 && setTimeout(() => el.select(), 1); + export let sleep = (n) => new Promise((r) => setTimeout(r, n)); export let wait = async (f, n = 100, s = 300) => { let i = 0; diff --git a/src/locales/en.json b/src/locales/en.json index 76fe4b13..4b18bd64 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -81,6 +81,7 @@ "invoice": { "addTip": "Add a tip", "addTipq": "Add a tip?", + "addMemo": "Add memo", "done": "Done", "paymentSuccessful": "Payment received!", "invoice": "Invoice", @@ -204,6 +205,8 @@ "placeholder": "Enter an address, invoice or username" }, "settings": { + "memoPrompt": "Checkout instructions", + "memoPromptPlaceholder": "e.g. Please enter your name for the order", "rememberFor": "Remember for", "import": "Import key", "destination": "Autowithdrawal address", diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index 0fbe90ab..e681c214 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -78,6 +78,7 @@ currency, items: items.filter((i) => i.quantity > 0), prompt: subject.prompt, + memoPrompt: subject.memoPrompt, rate, }; @@ -86,9 +87,7 @@ user: { username: subject.username }, }); - goto(`/${subject.username}/invoice/${id}`, { - invalidateAll: true, - }); + goto(`/send/invoice/${id}`, { invalidateAll: true }); }; let reset = () => @@ -167,7 +166,7 @@ {#each items as i (i.id)} <button type="button" - class="w-full text-center cursor-pointer hover:opacity-80" + class="w-full text-center cursor-pointer hover:opacity-80 mb-auto" on:click={() => i.quantity++} > <div class="relative w-full h-64 overflow-hidden rounded-xl"> diff --git a/src/routes/(app)/[username]/(profile)/request/+page.server.js b/src/routes/(app)/[username]/(profile)/request/+page.server.js deleted file mode 100644 index f22dcbb7..00000000 --- a/src/routes/(app)/[username]/(profile)/request/+page.server.js +++ /dev/null @@ -1,15 +0,0 @@ -import { redirect } from "@sveltejs/kit"; -import { fd, auth, post } from "$lib/utils"; - -export const actions = { - create: async ({ cookies, params, request, url }) => { - let form = await fd(request); - let { id, requester } = await post("/requests", form, auth(cookies)); - redirect(307, `/${params.username}/request/${id}`); - }, - - delete: async ({ cookies, request }) => { - let form = await fd(request); - let r = await post("/requests/delete", form, auth(cookies)); - }, -}; diff --git a/src/routes/(app)/[username]/(profile)/request/+page.svelte b/src/routes/(app)/[username]/(profile)/request/+page.svelte deleted file mode 100644 index a07ee914..00000000 --- a/src/routes/(app)/[username]/(profile)/request/+page.svelte +++ /dev/null @@ -1,35 +0,0 @@ -<script> - import { t } from "$lib/translations"; - import { enhance } from "$app/forms"; - import Icon from "$comp/Icon.svelte"; - - export let data; - - let { subject, user } = data; -</script> - -<div class="container max-w-lg px-4 mx-auto mt-10 space-y-5"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> - {$t("payments.requestAnInvoice")} - </h1> - - <form action="?/create" method="POST" use:enhance class="space-y-5"> - <input type="hidden" name="requester_id" value={user.id} /> - <input type="hidden" name="recipient" value={subject.username} /> - - <textarea - name="memo" - placeholder={$t("payments.describeOrder")} - class="w-full p-4 border rounded-xl h-48" - /> - - <div class="w-full flex"> - <button - type="submit" - class="bg-black text-white border rounded-full px-6 py-2 font-bold mx-auto" - > - {$t("payments.submit")} - </button> - </div> - </form> -</div> diff --git a/src/routes/(app)/[username]/(profile)/request/sent/+page.svelte b/src/routes/(app)/[username]/(profile)/request/sent/+page.svelte deleted file mode 100644 index ce5eb276..00000000 --- a/src/routes/(app)/[username]/(profile)/request/sent/+page.svelte +++ /dev/null @@ -1,21 +0,0 @@ -<script> - import { scale } from "svelte/transition"; - import Icon from "$comp/Icon.svelte"; - - export let data; - let { subject } = data; -</script> - -<div class="container px-4 text-center mx-auto"> - <div - class="flex w-full py-20 max-w-[200px] mx-auto" - in:scale={{ start: 0.5 }} - > - <Icon icon="check" style="mx-auto" /> - </div> - <h1 class="text-3xl md:text-4xl font-bold mb-6">Request sent</h1> -</div> - -<a href={`/${subject.username}`}> - <div class="opacity-0 w-screen h-screen fixed top-24 left-0 z-50" /> -</a> diff --git a/src/routes/(app)/[username]/invoice/[id]/+layout.server.js b/src/routes/(app)/[username]/invoice/[id]/+layout.server.js index 6f9ae4a2..0df10cca 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}`); diff --git a/src/routes/(app)/[username]/invoice/[id]/+page.svelte b/src/routes/(app)/[username]/invoice/[id]/+page.svelte index 56feced6..a7ffbff3 100644 --- a/src/routes/(app)/[username]/invoice/[id]/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[id]/+page.svelte @@ -42,12 +42,12 @@ amount, hash, type, + memoPrompt, rate, received, prompt, text, tip, - request_id, user: { username, currency }, } = invoice; @@ -144,15 +144,15 @@ {/if} {#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> + <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="font-semibold text-right"> + <div class="col-span-2 font-semibold text-right my-auto"> {f(i.price * i.quantity, currency)} </div> - <div class="text-secondary text-right text-lg my-auto"> + <div class="col-span-2 text-secondary text-right text-lg my-auto"> {sat(btc(i.price * i.quantity, rate))} </div> </div> 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..b81e2364 --- /dev/null +++ b/src/routes/(app)/[username]/invoice/[id]/memo/+page.server.js @@ -0,0 +1,12 @@ +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..a64ed453 --- /dev/null +++ b/src/routes/(app)/[username]/invoice/[id]/memo/+page.svelte @@ -0,0 +1,88 @@ +<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 { goto } from "$app/navigation"; + import { t } from "$lib/translations"; + import { enhance } from "$app/forms"; + import { tick } from "svelte"; + + 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 e9472118..ec35c3fb 100644 --- a/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte +++ b/src/routes/(app)/[username]/invoice/[id]/tip/+page.svelte @@ -115,13 +115,12 @@ <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="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} /> - <h1 class="text-4xl font-semibold my-8">{$t("invoice.addTipq")}</h1> {#if !showCustomAmount} <div class="my-2 text-xl">{Math.round(tipPercent)}%</div> diff --git a/src/routes/(app)/[username]/receive/[...param]/+page.svelte b/src/routes/(app)/[username]/receive/[...param]/+page.svelte index 7a27bd67..d643d181 100644 --- a/src/routes/(app)/[username]/receive/[...param]/+page.svelte +++ b/src/routes/(app)/[username]/receive/[...param]/+page.svelte @@ -36,11 +36,6 @@ <input type="hidden" name="username" value={username} /> <input type="hidden" name="type" value={type} /> <input type="hidden" name="rate" value={rate} /> - - {#if request} - <input type="hidden" name="request_id" value={request.id} /> - {/if} - <input type="hidden" name="prompt" value={prompt} /> <div class="space-y-3 w-[300px] mx-auto"> diff --git a/src/routes/(app)/[username]/request/[id]/+page.server.js b/src/routes/(app)/[username]/request/[id]/+page.server.js deleted file mode 100644 index 2712c7ca..00000000 --- a/src/routes/(app)/[username]/request/[id]/+page.server.js +++ /dev/null @@ -1,26 +0,0 @@ -import { auth, get } from "$lib/utils"; -import { redirect } from "@sveltejs/kit"; - -export let load = async ({ cookies, depends, params, parent }) => { - depends("app:invoice"); - - let { user } = await parent(); - if (!user) redirect(307, "/login"); - - let { request } = await get(`/request/${params.id}`, auth(cookies)); - let { invoice } = request; - - if (invoice) { - let { amount, received, id } = invoice; - if ( - request.recipient.username === user.username && - ((received && !amount) || received >= amount) - ) - redirect(307, `/${user.username}/invoice/${id}/paid`); - - if (request.requester.username === user.username) - redirect(307, `/send/${id}`); - } - - return { request }; -}; diff --git a/src/routes/(app)/[username]/request/[id]/+page.svelte b/src/routes/(app)/[username]/request/[id]/+page.svelte deleted file mode 100644 index ff33c02c..00000000 --- a/src/routes/(app)/[username]/request/[id]/+page.svelte +++ /dev/null @@ -1,58 +0,0 @@ -<script> - import { scale } from "svelte/transition"; - import { t } from "$lib/translations"; - import Avatar from "$comp/Avatar.svelte"; - import Icon from "$comp/Icon.svelte"; - import { f, sat, sats } from "$lib/utils"; - import { request as req, requestRedirect } from "$lib/store"; - import { onMount } from "svelte"; - - export let data; - let { request, user } = data; - - let amount, currency, rate, fiat; - if (request.invoice) { - ({ amount, rate, currency } = request.invoice); - fiat = (amount * rate) / sats; - } - - onMount(() => req.set()); -</script> - -<div class="container px-4 max-w-xl mx-auto space-y-8"> - <div class="text-center mb-8 space-y-5"> - {#if request.recipient_id === user.id} - <p class="text-4xl break-words"> - <span class="text-xl md:text-2xl">{$t("payments.sentInvoiceTo")}</span> - </p> - <div class="flex p-1 gap-2 justify-center"> - <Avatar user={request.requester} size={20} /> - <p class="text-4xl break-words my-auto">{request.requester.username}</p> - </div> - <div> - <h2 class="text-2xl md:text-3xl font-semibold"> - {f(fiat, currency)} - </h2> - <h3 class="text-secondary md:text-lg mb-6 mt-1">{sat(amount)}</h3> - </div> - {:else} - <div - class="flex w-full max-w-[200px] mx-auto py-20" - in:scale={{ start: 0.5 }} - > - <Icon icon="check" style="mx-auto" /> - </div> - <p class="text-3xl"> - {$t("payments.sentRequestTo")} - </p> - {/if} - </div> -</div> - -<a href={$requestRedirect || `/${user.username}`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> -</a> - -<div class="fixed bottom-10 left-0 text-center w-full"> - {$t("payments.tapAnywhere")} -</div> diff --git a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte index d36cbd1b..f307c6df 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte @@ -63,6 +63,13 @@ </div> <div> + <label for="memoPrompt" class="font-bold mb-1 block" + >{$t("user.settings.memoPrompt")}</label + > + <textarea name="memoPrompt" placeholder={$t("user.settings.memoPromptPlaceholder")} bind:value={user.memoPrompt}></textarea> +</div> + +<div> <div class="flex justify-between items-center"> <span class="font-bold">{$t("user.settings.notifications")}</span> <Toggle id="notify" bind:value={user.notify} /> diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index 1f0e0308..3e40d984 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -39,8 +39,6 @@ currency, } = p); - console.log("FEE", fee); - if (amount > 0) [txid, vout] = ref.split(":"); else txid = hash; diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.js b/src/routes/(app)/send/invoice/[id]/+page.server.js index dcf188b2..2cb19b80 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.server.js +++ b/src/routes/(app)/send/invoice/[id]/+page.server.js @@ -8,6 +8,10 @@ export async function load({ params: { id }, parent, url }) { 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" }); |
