aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2023-02-25 06:52:08 -0800
committerAdam Soltys <[email protected]>2023-02-25 06:52:08 -0800
commit1ac4c9f8dafc12cc247ce301d76f45fddeac477f (patch)
tree200a01737e649722bcf93ad208c18365bc1f1201 /src
parent0b9e3e5edf9f37e3cd692f2db801fa2bd5720314 (diff)
parent0dd7eab893bb4aad5853ea92cdb8e70e421dc1b8 (diff)
downloadcoinos-ui-1ac4c9f8dafc12cc247ce301d76f45fddeac477f.tar.gz
coinos-ui-1ac4c9f8dafc12cc247ce301d76f45fddeac477f.zip
Merge branch 'master' into hashme
Diffstat (limited to 'src')
-rw-r--r--src/components/Lnurlp.svelte2
-rw-r--r--src/components/Numpad.svelte55
-rw-r--r--src/components/Slider.svelte56
-rw-r--r--src/components/index.js1
-rw-r--r--src/hooks.server.js32
-rw-r--r--src/lib/parse.js0
-rw-r--r--src/lib/utils.js6
-rw-r--r--src/locales/es.json259
-rw-r--r--src/locales/fr.json84
-rw-r--r--src/routes/(app)/[username]/(profile)/+page.server.js2
-rw-r--r--src/routes/(app)/[username]/(profile)/request/+page.server.js6
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte29
-rw-r--r--src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte57
-rw-r--r--src/routes/(app)/[username]/settings/[...tab]/+page.server.js4
-rw-r--r--src/routes/(app)/ln/[lnurl]/+page.server.js12
-rw-r--r--src/routes/(app)/login/+page.server.js4
-rw-r--r--src/routes/(app)/payment/[id]/+page.svelte20
-rw-r--r--src/routes/(app)/pot/[name]/withdraw/+page.server.js5
-rw-r--r--src/routes/(app)/register/+page.server.js4
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.server.js22
-rw-r--r--src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte106
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.server.js9
-rw-r--r--src/routes/(app)/send/invoice/[id]/+page.svelte1
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.server.js14
-rw-r--r--src/routes/(app)/send/lightning/[payreq]/+page.svelte4
-rw-r--r--src/routes/(app)/send/pot/[name]/[...amount]/+page.server.js2
-rw-r--r--src/routes/(app)/send/pot/[name]/[...amount]/+page.svelte2
-rw-r--r--src/routes/(app)/send/user/[username]/[...amount]/+page.server.js10
-rw-r--r--src/routes/(app)/send/user/[username]/[...amount]/+page.svelte6
-rw-r--r--src/routes/(app)/sent/+page.svelte26
-rw-r--r--src/routes/(app)/support/+page.server.js5
31 files changed, 491 insertions, 354 deletions
diff --git a/src/components/Lnurlp.svelte b/src/components/Lnurlp.svelte
index 22364fcf..ab0c50ce 100644
--- a/src/components/Lnurlp.svelte
+++ b/src/components/Lnurlp.svelte
@@ -8,7 +8,7 @@
let { currency } = data.user;
let { minSendable, maxSendable, callback, metadata } = data;
- let amount = minSendable,
+ let amount = Math.round(minSendable / 1000),
loading;
let submit = () => (loading = true);
</script>
diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte
index 5ffaa2ea..47bd9375 100644
--- a/src/components/Numpad.svelte
+++ b/src/components/Numpad.svelte
@@ -9,11 +9,18 @@
fiat = !amount,
submit = undefined;
- export let amountFiat = amount ? amount * ($selectedRate / sats) : 0;
-
+ let amountFiat = 0;
let arrow = '<';
- let amountSats = amount;
+ $: update(amount, amountFiat);
+ let update = (a, f) => {
+ if (fiat) {
+ amount = Math.round(f / ($selectedRate / sats));
+ } else {
+ amountFiat = ((a * $selectedRate) / sats).toFixed(2);
+ }
+ };
+
let loading = false;
let symbol =
@@ -33,14 +40,6 @@
KRW: '₩'
}[currency] || '';
- $: amount = parseInt(fiat ? Math.round(amountFiat / ($selectedRate / sats)) : amountSats);
-
- $: amountSatsFormatted = s(amountSats);
-
- $: amountFiatConverted = f(amountSats * ($selectedRate / sats), currency);
-
- $: amountSatsConverted = sat(amountFiat / ($selectedRate / sats));
-
const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<'];
const handleInput = (value) => {
@@ -58,7 +57,7 @@
amountFiat = amountFiat.slice(0, amountFiat.length - 1);
if (amountFiat.length === 0) {
amountFiat = 0;
- amountSats = 0;
+ amount = 0;
}
}
} else if (value !== '.' && value !== '<' && parseInt(amountFiat + value) > $selectedRate) {
@@ -71,25 +70,27 @@
} else {
if (value === '.') {
return;
- } else if (!amountSats && value !== '<' && value !== '0') {
- amountSats = parseInt(value);
+ } else if (!amount && value !== '<' && value !== '0') {
+ amount = parseInt(value);
} else if (value === '<') {
- if (amountSats !== 0) {
- amountSats = Math.floor(amountSats / 10);
- if (amountSats.length === 0) {
- amountSats = 0;
+ if (amount !== 0) {
+ amount = Math.floor(amount / 10);
+ if (amount.length === 0) {
+ amount = 0;
amountFiat = 0;
}
}
- } else if (value !== '<' && parseInt(amountSats + value) > sats) {
+ } else if (value !== '<' && parseInt(amount + value) > sats) {
warning($t('user.receive.lessThan1BTCWarning'));
} else {
- amountSats = parseInt(amountSats + value);
+ console.log('CLICK', amount.toString(), value);
+ amount = parseInt(amount.toString() + value);
+ console.log('AMOUNT', amount);
}
}
};
- $: html = fiat ? amountFiat : s(amountSats);
+ $: html = fiat ? amountFiat : s(amount);
let prev = '';
@@ -124,10 +125,10 @@
if (fiat) {
amountFiat = html;
} else {
- amountSats = parseInt(html.replace(/,/g, ''));
+ amount = parseInt(html.replace(/,/g, ''));
}
- if (!amountSats) amountSats = null;
+ if (!amount) amount = null;
setTimeout(() => {
if (!fiat) {
@@ -178,16 +179,16 @@
/>
</div>
<div class="mt-2">
- <span class="text-secondary mr-1">{fiat ? amountSatsConverted : amountFiatConverted}</span>
+ <span class="text-secondary mr-1">{fiat ? sat(amount) : f(amountFiat, currency)}</span>
<button
type="button"
on:click={() => {
if (fiat) {
- amountSats = parseInt((amountFiat / ($selectedRate / sats)).toFixed(0));
+ amount = parseInt((amountFiat / ($selectedRate / sats)).toFixed(0));
} else {
amountFiat =
- (amountSats * ($selectedRate / sats)).toFixed(2) > 0.0
- ? (amountSats * ($selectedRate / sats)).toFixed(2)
+ (amount * ($selectedRate / sats)).toFixed(2) > 0.0
+ ? (amount * ($selectedRate / sats)).toFixed(2)
: 0;
}
fiat = !fiat;
diff --git a/src/components/Slider.svelte b/src/components/Slider.svelte
new file mode 100644
index 00000000..3c94d127
--- /dev/null
+++ b/src/components/Slider.svelte
@@ -0,0 +1,56 @@
+<script>
+ export let value,
+ handle,
+ min = 0,
+ max = 100;
+</script>
+
+<input
+ id="slider"
+ type="range"
+ {min}
+ {max}
+ bind:value
+ class="px-0 py-0 my-5"
+ style="--bgPercent: {((value - min) * 100) / (max - min)}%;"
+ on:input={handle}
+/>
+
+<style>
+ #slider {
+ -webkit-appearance: none;
+ width: 100%;
+ height: 6px;
+ border-radius: 5px;
+ background: linear-gradient(
+ to right,
+ black 0%,
+ black var(--bgPercent),
+ #f5f7fa var(--bgPercent),
+ #f5f7fa 100%
+ );
+ outline: none;
+ }
+
+ #slider:active {
+ background-color: black;
+ }
+
+ #slider::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: black;
+ cursor: pointer;
+ }
+
+ #slider::-moz-range-thumb {
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: black;
+ cursor: pointer;
+ }
+</style>
diff --git a/src/components/index.js b/src/components/index.js
index ab54e09f..0d1d8d1d 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,3 +1,4 @@
+export { default as Slider } from './Slider.svelte';
export { default as Pinpad } from './Pinpad.svelte';
export { default as Balance } from './Balance.svelte';
export { default as Lnurlp } from './Lnurlp.svelte';
diff --git a/src/hooks.server.js b/src/hooks.server.js
new file mode 100644
index 00000000..4107ec86
--- /dev/null
+++ b/src/hooks.server.js
@@ -0,0 +1,32 @@
+import { auth, get, protectedRoutes } from '$lib/utils';
+
+export async function handle({ event, resolve }) {
+ let token = event.cookies.get('token');
+ let {
+ params,
+ request,
+ url: { pathname, origin }
+ } = event;
+
+ let user;
+ if (token && pathname !== '/logout') {
+ try {
+ user = await get('/me', auth(event.cookies));
+ event.locals.user = user;
+
+ if (['/', '/login', '/register'].includes(pathname) && request.method === 'GET')
+ return Response.redirect(origin + `/${user.username}/dashboard`, 307);
+ } catch (e) {
+ return Response.redirect(origin + '/logout', 307);
+ }
+ }
+
+ if (protectedRoutes.find((p) => pathname.match(p))) {
+ if (!user || user.username !== params.username)
+ return Response.redirect(origin + '/login', 307);
+ }
+
+ const response = await resolve(event);
+
+ return response;
+}
diff --git a/src/lib/parse.js b/src/lib/parse.js
deleted file mode 100644
index e69de29b..00000000
--- a/src/lib/parse.js
+++ /dev/null
diff --git a/src/lib/utils.js b/src/lib/utils.js
index 86f722b9..7b10c638 100644
--- a/src/lib/utils.js
+++ b/src/lib/utils.js
@@ -148,6 +148,12 @@ export const login = async (user, cookies) => {
export const auth = (cookies) => ({ authorization: `Bearer ${cookies.get('token')}` });
export const fiat = (amount, rate) => (amount * rate) / sats;
+export const fd = async (req) => {
+ let obj = Object.fromEntries(await req.formData());
+ for (let k in obj)
+ (obj[k] === 'undefined' && (obj[k] = undefined)) || (obj[k] === 'false' && (obj[k] = false));
+ return obj;
+};
export const f = (s, currency) =>
new Intl.NumberFormat('en-US', {
diff --git a/src/locales/es.json b/src/locales/es.json
index e151ec1a..8e68a5f3 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -1,275 +1,282 @@
{
"404": {
"404": "404",
- "pageNotFound": "La página no existe."
+ "pageNotFound": "Pagina no encontrada."
},
"about": {
- "header": "Sobre",
- "p1": "coinos es una aplicación de código abierto para pagos con bitcoin. Su desarrollo comezó en Vancouver allá por Septiembre de 2012 como una solución para que comerciantes locales puedan aceptar pagos con bitcoin.",
- "p3": "Si lo desea, puede descargar el código fuente de Coinos para ejecutar su propia instancia y tenerla conectada a sus propios nodos bitcoin y lightning. Estaremos encantados de ayudarle a en un proveedor de pagos y en un custodio benevolente para su comunidad.",
- "p4": "Las transferencias entre cuentas de usuario en nuestro servidor son realizadas off-chain, esto hace que sean instantáneas, ilimitadas, y gratuitas.",
+ "header": "Sobre Nosotros",
+ "p1": "Coinos es una aplicación de pagos en bitcoin de código abierto. Este desarrollo comenzó en septiembre de 2012 en Vancouver como una forma de proporcionar a los comerciantes locales una forma conveniente de aceptar pagos con bitcoin.",
+ "p2": "Descarga el código fuente para ejecutar una instancia y conectarla a tu propio nodo bitcoin y lightning. Te ayudaremos a convertirte en un excelente custodio y proveedor de pagos para tu comunidad.",
+ "p3": "Las transferencias de bitcoin entre usuarios en nuestro servidor se realizan off-chain, por lo que son completamente gratuitas, instantáneas e ilimitadas.",
"team": {
- "header": "El Equipo",
+ "header": "Nuestro Equipo",
"adam": {
"name": "Adam Soltys",
- "position": "Director (CTO)",
- "bio": "Adam es desarrollador web y entusiasta de bitcoin, cree que el dinero sólido es clave para aumentar la prosperidad global. Vive en Vancouver junto a su esposa Chelsea y sus dos hijos."
+ "position": "Director de Tecnología",
+ "bio": "Adam es un desarrollador web y un entusiasta de bitcoin que cree que el dinero sólido es clave para aumentar la prosperidad global. Vive en la ciudad de North Vancouver con su esposa Chelsea y sus dos hijos."
},
"secondl1ght": {
"name": "secondl1ght",
- "position": "Desarrollador web",
- "bio": "Es un desarrollador web autodidacta, que se zambulló de cabeza en la madriguera del conejo de bitcoin al dejar su trabajo pagado en fiat para concentrarse en el desarrollo de bitcoin a tiempo completo. Contribuyente en proyectos de código abierto, defensor de la privacidad y amante de la libertad."
+ "position": "Desarrollador Web",
+ "bio": "Desarrollador web autodidacta, se sumergió de cabeza en con el bitcoin y dejó su trabajo fiduciario para concentrarse en el desarrollo de bitcoin a tiempo completo. Contribuye en proyectos de código abierto, es un defensor de la privacidad y un amante de la libertad."
},
"karnage": {
"name": "Karnage",
"position": "Diseñador de Producto",
- "bio": "¨Mi misión es ayudar a los fundadores de startups a tener éxito. Creo productos para lograr este objetivo. Diseño de producto con píxeles perfectos. Recibe lo que buscas.¨"
+ "bio": "Mi misión es ayudar a los fundadores de startups a tener éxito. Creo productos para lograr estos objetivos. Diseño de producto con píxeles perfectos. Haz que te lo envíen."
},
"shauna": {
"name": "Shauna",
- "position": "Marketing & Operaciones",
- "bio": "Gestión Estratégica y de Proyectos. Ella es una todóloga. Siempre encuentra tiempo para reunirse a tomar un café."
+ "position": "Operaciones y Mercadeo",
+ "bio": "Gestión Estratégica y de Proyectos. Sé un poco de todo. Siempre habrá tiempo para compartir un buen café."
},
"cole": {
"name": "Cole",
- "position": "Profesional en Bitcoin",
- "bio": "Como profesional certificado de Bitcoin, Cole es una persona motivada y apasionada por la libertad. Encontró bitcoin en el año 2016 bitcoin y se dedicó a estudiarlo en profundidad. Ahora quiere presentar Lightning Network a tantos usuarios como sea posible."
+ "position": "Profesional de Bitcoin",
+ "bio": "Como profesional certificado de Bitcoin, Cole es una persona motivada y apasionada por la libertad. Conoció el bitcoin en 2016 y lo estudió en profundidad. Ahora quiere presentarle la Red Lightning a tantos usuarios como sea posible."
},
"john": {
"name": "John Barratt",
- "position": "Desarrollador web Full Stack",
- "bio": "Cuando no está programando, John puede ser encontrado en el bosque recorriendo todos los grandes senderos que Colombia Británica tiene para ofrecer."
+ "position": "Desarrollador Web Full Stack",
+ "bio": "Cuando no está programando, podemos encontrar a John en el bosque recorriendo todos los grandes senderos que British Columbia tiene para ofrecer."
}
},
"locations": {
- "header": "Locales",
- "description": "Estos son comercios que aceptan bitcoin con coinos. Si estás utilizando nuestra aplicación, por favor \"<a href=\"mailto:[email protected]\" class=\"underline underline-offset-4 hover:opacity-80\">cuéntenos!</a>"
+ "header": "Locaciones",
+ "description": "Aquí algunas empresas que aceptan bitcoin con Coinos. ¡Esperamos que el tuyo sea el próximo!"
}
},
"error": {
"header": "Error",
- "message": "Por favor inténtelo nuevamente o contacte a nuestro soporte.",
+ "message": "Vuelva a intentarlo o póngase en contacto con el soporte.",
"signIn": "Por favor inicie sesión para continuar."
},
"faq": {
- "header": "PMF",
+ "header": "Preguntas frecuentes",
"cost": {
- "question": "Cuanto cuesta?",
- "answer": "Coinos es gratis. No hay costos de registro ni mantenimiento. Puede enviar y recibir pagos de forma ilimitada por medio de Lightning Network sin costo alguno. Sin embargo, si quieres tus fondos hacia una dirección de bitcoin on-chain existe una tarifa del 0,1%."
+ "question": "¿Cuánto cuesta?",
+ "answer": "Registrar una cuenta y recibir pagos a través de Red Lightning es gratis. Cobramos una tarifa del 0,1% por convertir de lightning a bitcoin."
},
"compatibility": {
- "question": "Necesito un dispositivo o software especial?",
- "answer": "No. Al estar basado en web, Coinos está disponible en cualquier dispositivo con conexión a internet. Puede usarlo directamente desde un celular o una tableta."
+ "question": "¿Necesito algún dispositivo o software especial?",
+ "answer": "No. Coinos es una aplicación web, por lo que siempre que tenga conexión a Internet, podrá usarlo desde cualquier dispositivo. Las tiendas minoristas pueden usarlo desde un teléfono o una tableta."
},
"safety": {
- "question": "Qué puedo hacer con el bitcoin que recibo?",
- "answer": "Usarlo para pagar personal y proveedores, apoyar otras empresas y comerciantes que acepten bitcoin. O puede mantenerlo durante algunos años y ver crecer su poder adquisitivo."
+ "question": "¿Cuándo se liquidan mis fondos?",
+ "answer": "Los pagos en Red Lightning se liquidan al instante. Puede retirar su saldo a otra billetera o exchange inmediatamente después de recibir el pago."
}
},
"footer": {
"company": "Empresa",
- "followUs": "Síganos",
+ "followUs": "Síguenos",
"github": "GitHub",
- "jobs": "Empleos",
+ "jobs": "Trabaje con nosotros",
"support": "Soporte",
"telegram": "Telegram",
"twitter": "Twitter",
"news": "Noticias"
},
"howItWorks": {
- "header": "¿Cómo funciona?",
+ "header": "Cómo funciona",
"step1": {
- "header": "1. Abra una cuenta",
- "description": "Para empezar, solo debe elegir un nombre de usuario y crear una contraseña."
+ "header": "1. Crea tu cuenta",
+ "description": "Un nombre de usuario y una contraseña es todo lo que necesita para comenzar."
},
"step2": {
- "header": "2. Solicitar pagos",
- "description": "Lo mismo que hace normalmente, ¡pero con bitcoin!"
+ "header": "2. Cobra tus pagos",
+ "description": "Lo mismo que harías normalmente, pero con bitcoin."
},
"step3": {
- "header": "3. ¡y listo!",
- "description": "Ahora puede disponer libremente de su bitcoin como guste."
+ "header": "3. ¡Eso es todo!",
+ "description": "Haz pagos con otros comerciantes o guarda tu bitcoin para días difíciles, la elección es tuya."
}
},
"invoice": {
- "addTip": "Agregar propina",
- "addTipq": "Agregar propina?",
- "done": "Listo",
- "paymentSuccessful": "Pago exitoso!",
+ "addTip": "Añadir propina",
+ "addTipq": "Añadir propina?",
+ "done": "Hecho",
+ "paymentSuccessful": "¡Pago recibido!",
"invoice": "Factura",
"total": "Total",
"tip": "Propina"
},
"jobs": {
- "header": "Empleos",
- "subheader": "Puestos disponibles",
- "pitch1": "coinos se encuentra buscando a desarrolladores que quieran unirse a nuestro equipo de trabajo en crecimiento (tiempo medio o tiempo completo, APROBAMOS el trabajo remoto).",
- "pitch2": "Emocionado por trabajar en un proyecto de código abierto con bitcoin? Entonces mira nuestros repositorios en",
+ "header": "Trabaje con nosotros",
+ "subheader": "Ofertas de Trabajo",
+ "pitch1": "Coinos está activamente buscando desarrolladores para unirse a nuestro equipo en crecimiento (tiempo completo o medio tiempo, trabajo remoto OK).",
+ "pitch2": "¿Emocionado por trabajar en bitcoin de código abierto? Entonces eche un vistazo a nuestros repositorios en",
"github": "GitHub",
- "pitch3": "Nos encantaría saber de usted si cree que tiene algo impactante para mostrar. Envíenos su CV a"
+ "pitch3": "Si crees que puedes generar impacto, nos encantaría saber de ti. Envíanos tu currículum a"
},
"landing": {
- "header_before_icon": "La manera",
- "header_with_icon": "más simple",
- "header_after_icon": "de aceptar bitcoin en su negocio.",
- "subheader": "Aumente sus posibilidades de ingreso agregando bitcoin como forma de pago mediante una aplicación web muy fácil de usar. No se requiere ningún software o hardware adicional.",
+ "header_before_icon": "La",
+ "header_with_icon": "manera",
+ "header_after_icon": "más fácil de aceptar bitcoins en tu tienda.",
+ "subheader": "Aumenta tu número de clientes e ingresos al aceptar bitcoin con una aplicación web fácil de usar. No requiere software ni hardware.",
"info1": {
- "title": "Pagos instantáneos con Lightning",
- "description": "Cuando su cliente envíe un pago, el mismo estará disponible en forma inmediata. Liquidación instantánea en segundos. Diga adiós al 3% de interés que le cobran por tarifas de procesamiento de tarjetas de crédito."
+ "title": "Pagos instantáneos a través de Lightning",
+ "description": "El momento en que su cliente envía un pago, este llega inmediatamente. Sin esperar liquidaciones bancarias ni preocuparse por cargos extras. Liquidación instantánea, en segundos. Diga adiós a los cargos del 3% de las tarifas en tarjetas de crédito."
},
"info2": {
"title": "Fácil de usar",
- "description1": "Ingrese un monto en su moneda local, comparta el QR y listo.",
- "description2": "Coinos le ofrece acceso gratuito para usar los nodos bitcoin y lightning alojados, sin que deba comprender cómo funcionan bitcoin o lightning. Hacemos todo el trabajo pesado para que pueda concentrarse en su negocio.",
- "description3": "Usted siempre tendrá la opción de retirar sus fondos para retomar su custodia de forma inmediata."
+ "description1": "Solo ingrese una cantidad en su moneda local, comparta el código QR y listo.",
+ "description2": "Hacemos todo el trabajo pesado para que pueda concentrarse en su negocio.",
+ "description3": "Siempre tiene la opción de tomar la custodia de sus fondos al retirarlos instantáneamente en cualquier momento."
},
"info3": {
- "title": "Personalícelo!",
- "description": "Puede personalizar la apariencia y el estilo de su punto de venta o mantenerlo por defecto. Depende de usted."
+ "title": "Maneja tu marca a tu manera!",
+ "description": "Personalice la apariencia y el estilo del punto de venta de tu negocio a tu gusto: depende totalmente de ti."
}
},
"login": {
"optional": "Opcional",
"token": "Token 2FA",
- "username": "Nombre de usuario",
+ "username": "Usuario",
"password": "Contraseña",
- "email": "Email",
- "passwordRecommendation": "Recomendamos utilizar un administrador de contraseñas para generar una clave larga y aleatoria.",
- "forgotUserOrPassword": "Olvidó su nombre de usuario o su contraseña?",
- "haveAccount": "Ya tiene una cuenta?",
- "noAccount": "No tiene una cuenta?",
- "register": "Registrarse",
- "signIn": "Iniciar sesión",
- "failed": "Inicio de sesión fallido"
+ "email": "Correo",
+ "passwordRecommendation": "Recomendamos una contraseña larga y aleatoria generada con un administrador de contraseñas.",
+ "forgotUserOrPassword": "¿Olvidaste tu nombre de usuario o contraseña?",
+ "haveAccount": "¿Ya tienes una cuenta?",
+ "noAccount": "¿No tienes una cuenta?",
+ "register": "Registro",
+ "signIn": "Registrarse",
+ "failed": "Fallo en Inicio"
},
"nav": {
"profile": "Perfil",
- "startInSeconds": "Comience de inmediato",
+ "startInSeconds": "Comience en segundos",
"account": "Cuenta",
- "signIn": "Iniciar sesión",
- "signOut": "Cerrar sesión",
+ "signIn": "Registrarse",
+ "signOut": "Desconectar",
"dashboard": "Panel",
"settings": "Ajustes",
"support": "Soporte"
},
+ "newSiteHeader": "Acompañanos en nuestra <a href=\"/launch\" class=\"underline underline-offset-4 text-black hover:opacity-80\">launch party</a> en Vancouver el 26 de Octubre! Buscando la version anterior de coinos? Visita <a href=\"https://classic.coinos.io\" class=\"underline underline-offset-4 text-black hover:opacity-80\">classic.coinos.io</a>",
"news": {
"header": "Noticias",
- "subheader": "Últimas novedades",
+ "subheader": "Últimas Actualizaciones",
"update1": ""
},
"user": {
"bitcoin": "Bitcoin",
- "lightning": "Relámpago",
+ "lightning": "Lightning",
"invoice": "Factura",
"unfollow": "Dejar de seguir",
"following": "Siguiendo",
"follow": "Seguir",
"remove": "Eliminar",
- "scanToPayBTC": "Escanea para pagar en bitcoin",
+ "scanToPayBTC": "Escanear para pagar con bitcoin",
"this": "Esta",
- "lightningAddress": "dirección relámpago",
- "likeAnEmail": "es como un correo electrónico para bitcoin. Puede publicarlo en su sitio web o tarjetas de presentación y usarlo varias veces.",
+ "lightningAddress": "dirección lightning",
+ "likeAnEmail": "es como un correo electrónico para bitcoin. Puede publicarlo en su sitio web o tarjetas de presentación y usarlo múltiples veces.",
"dashboard": {
- "dashboard": "Tablero",
- "accountBalance": "Saldo",
- "bitcoinPrice": "Precio de bitcoin:",
- "conversionFeeWarning": "Cobraremos una tarifa de retiro del 1% sobre el monto",
+ "go": "Ir",
+ "dashboard": "Panel",
+ "accountBalance": "Saldo de la cuenta",
+ "bitcoinPrice": "Precio de Bitcoin:",
+ "conversionFeeWarning": "Se le cobrará una tarifa de retiro del 1% sobre el monto.",
"dataFromBinance": "Datos de <span class=\"text-black\">Binance</span>.",
- "fetchingRate": "Tasa...",
+ "fetchingRate": "calculando tasa...",
"optionalNote": "Nota (Opcional)",
"send": "Enviar",
- "receive": "Recibir un pago",
+ "receive": "Recibir",
"withdraw": "Retirar",
- "deposit": "Depósito",
- "voucher": "Vale"
+ "deposit": "Depositar",
+ "voucher": "Comprobante"
},
"receive": {
- "lessThan1BTCWarning": "Ingrese una cantidad menor a 1 bitcoin.",
- "showQR": "Ver QR"
+ "lessThan1BTCWarning": "Introduzca una cantidad inferior a 1 bitcoin.",
+ "showQR": "Mostrar código QR"
},
"send": {
"contacts": "Contactos",
"scan": "Escanear",
"paste": "Pegar",
- "next": "Próxima",
- "placeholder": "Pegue una dirección de bitcoin, una factura relámpago o un nombre de usuario de coinos"
+ "next": "Siguiente",
+ "placeholder": "Asigne una dirección de bitcoin, una factura lightning o un usuario de coinos"
},
"settings": {
- "bannerImage": "Imagen de portada",
+ "bannerImage": "Imagen del Banner",
"profileImage": "Imagen de perfil",
"oneTimeCode": "Ingrese el código de un solo uso",
- "accountId": "",
+ "accountId": "Id Cuenta",
"header": "Ajustes",
"ACCOUNT": "CUENTA",
"POINT_OF_SALE": "PUNTO DE VENTA",
"SECURITY": "SEGURIDAD",
- "locale": "Languaje",
- "username": "Nombre de usuario",
- "email": "Email",
+ "locale": "Idioma",
+ "username": "Usuario",
+ "email": "Correo",
"newPassword": "Nueva contraseña",
- "businessAddress": "Dirección comercial",
- "emailNotifications": "Notificar por email",
- "emailNotificationsDescription": "Recibe notificaciones cuando alguien le envíe un pago o cuando ocurra algún cambio en su cuenta.",
- "smsNotifications": "Notificar pr SMS",
- "smsNotificationsDescription": "coinos le enviará notificaciones por mensaje de texto cuando esté habilitado.",
- "theme": "Tema de color",
- "themeDescription": "Elija el tema de color predeterminado.",
- "localCurrency": "Moneda local",
- "btcUnit": "Mostrar bitcoin en:",
- "bitcoin": "Bitcoin",
+ "businessAddress": "Dirección Negocio",
+ "emailNotifications": "Notificaciones de Correo Electrónico",
+ "emailNotificationsDescription": "Reciba notificaciones por correo electrónico cuando se produzca un cambio en su cuenta o cuando las personas le envíen pagos.",
+ "smsNotifications": "Notificaciones SMS",
+ "smsNotificationsDescription": "Coinos enviará notificaciones de texto cuando esto esté habilitado.",
+ "theme": "Color Tema",
+ "themeDescription": "Seleccione entre los temas de color predeterminados.",
+ "localCurrency": "Moneda Local",
+ "btcUnit": "Ver bitcoin en:",
+ "bitcoin": "bitcoin",
"satoshis": "Satoshis",
- "securityPIN": "PIN de seguridad",
- "securityPINDescription": "Ingrese un pin de seguridad y úselo para desbloquear coinos o enviar pagos.",
- "setPIN": "Crear PIN",
- "autoLock": "Tiempo de auto bloqueo",
- "autoLockDescription": "Se le pedirá el pin para reanudar la sesión luego de el tiempo especificado:",
+ "securityPIN": "PIN de Seguridad",
+ "securityPINDescription": "Establezca un pin de seguridad para desbloquear la configuración y enviar pagos.",
+ "setPIN": "Establecer PIN",
+ "autoLock": "Temporizador de bloqueo automático",
+ "autoLockDescription": "Su cuenta entrará en modo seguro automáticamente después del tiempo especificado:",
"twofa": "Autenticación de 2 factores",
- "twofaDescription": "Agregue un nivel extra de seguridad a su cuenta con la autenticación de 2 factores (2FA).",
+ "twofaDescription": "Agregue una capa extra de seguridad a su dispositivo habilitando la autenticación de 2 factores.",
"twofaSetup": "Configurar 2FA",
- "twofaDisable": "Desactivar 2FA",
- "select": "Seleccione",
+ "twofaDisable": "Deshabilitar 2FA",
+ "select": "Seleccionar",
"verifyPIN": "Verificar PIN",
"enablePIN": "Habilitar PIN",
"disablePIN": "Deshabilitar PIN"
},
"support": {
"header": "Soporte",
- "email": "Correo electrónico",
- "accountName": "Nombre de cuenta",
+ "email": "Correo",
+ "accountName": "Nombre Cuenta",
"message": "Mensaje",
"send": "Enviar"
}
},
- "payments": {
- "header": "Historial de transacciones",
- "AMOUNT": "MONTO",
+ "transactions": {
+ "header": "Transacciones",
+ "AMOUNT": "CANTIDAD",
"TYPE": "TIPO",
"TIME": "HORA",
- "sent": "Enviada",
- "received": "Recibida",
- "empty": "No hay transacciones.",
- "send": "Enviar",
- "next": "Próxima",
- "sendersChoice": "Elección del remitente",
+ "sent": "Enviado",
+ "received": "Recibido",
+ "empty": "Aún no hay transacciones.",
+ "send": "Enviado",
+ "next": "Siguiente",
+ "sendersChoice": "Sender's choice",
"sendTo": "Enviar a",
- "to": "a",
+ "to": "para",
"pay": "Pagar",
"requesting": "está solicitando",
- "sentInvoiceTo": "Factura enviada a",
- "sentRequestTo": "Solicitud enviada a",
+ "sentInvoiceTo": "Enviar factura a",
+ "sentRequestTo": "Enviar solicitud a",
"pleasePay": "Por favor pague",
- "day": "Dia",
+ "day": "Día",
"week": "Semana",
"month": "Mes",
"all": "Todo",
"export": "Exportar",
"invoice": "Factura",
"readyToPay": "está listo para pagar",
- "describeOrder": "Utilice este campo para describir su pedido",
- "requestAnInvoice": "Solicitar una factura",
+ "describeOrder": "Utilice este campo para describir su orden",
+ "requestAnInvoice": "Solicitar factura",
"submit": "Enviar",
"isRequesting": "está solicitando",
- "awaiting": "Esperando"
+ "awaiting": "Esperando",
+ "tapAnywhere": "Toca en cualquier lugar",
+ "from": "de",
+ "redeem": "Redimir",
+ "redeemed": "Redimido",
+ "redeemedBy": "Redimido por"
}
}
diff --git a/src/locales/fr.json b/src/locales/fr.json
index bc9c9d66..5fcb95ab 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -6,8 +6,8 @@
"about": {
"header": "À Propos",
"p1": "<strong>coinos</strong> est un portefeuille, point de vente, marché d'e-commerce et plateforme d'échange de bitcoin <strong>open source</strong>. Development a commencé en Vancouver le septembre de 2012 pour donner aux marchands du coin un façon pratique d'accepter des paiements en bitcoin.",
- "p2": "Il a eu plus de fonctions au fil des ans pour satisfaire une grande variété de cas d'utilisation avec le but de rendre commencer utiliser bitcoin rapidement, à bas prix, et en sécurité aussi façile que possible pour n'importe qui.",
- "p3": "Tout le monde peux télécharger le code source et héberger leur propre instance de la plateforme soutenu par leur propres nœuds de bitcoin, liquid ou lightning, ou contactez-nous et nous l'installalons pour vous avec plaisir.",
+ "p2": "Il a eu plus de fonctions au fil des ans pour satisfaire une grande variété de cas d'utilisation dans le but de pouvoir utiliser bitcoin rapidement, à bas prix, et en sécurité aussi façile que possible pour n'importe qui.",
+ "p3": "Tout le monde peux télécharger le code source et héberger leur propre instance de la plateforme soutenue par leur propres nœuds de bitcoin, liquid ou lightning, ou contactez-nous et nous l'installerons pour vous avec plaisir.",
"locations": {
"header": "Établissements",
"description": "Il y a des entreprises qui acceptent bitcoin utilisant le point de vente coinos. Si vous utilisez notre appli, s'il vous plait <a href=\"mailto:[email protected]\" class=\"underline underline-offset-4\">fais-le-nous savoir!</a>"
@@ -17,12 +17,12 @@
"adam": {
"name": "Adam Soltys",
"position": "Officier Technique Principal",
- "bio": "Adam est programmeur de web et passionné de bitcoin. Il croit que l'argent sûr est clé à augmenter la prospérité planétaire. Il habite en Vancouver de Nord avec sa femme Chelsea et deux enfants."
+ "bio": "Adam est développeur web et passionné de bitcoin. Il croit que l'argent sûr est la clé pour augmenter la prospérité planétaire. Il habite en Vancouver de Nord avec sa femme Chelsea et deux enfants."
},
"secondl1ght": {
"name": "secondl1ght",
- "position": "Programmeur de Web",
- "bio": "Secondl1ght est un programmeur de web autodidacte. Il a découvert bitcoin et quitté son job de monnaie fiduciaire pour développer bitcoin à temps plein. Il contribue aux projets open source, est défenseur d'intimité, et il aime la liberté."
+ "position": "Développeur Web",
+ "bio": "Secondl1ght est un développeur web autodidacte. Il a découvert bitcoin et quitté son job de monnaie fiduciaire pour développer bitcoin à temps plein. Il contribue aux projets open source, est défenseur de la vie privée, et il aime la liberté."
},
"karnage": {
"name": "Karnage",
@@ -32,7 +32,7 @@
"shauna": {
"name": "Shauna",
"position": "Gestion & Marketing",
- "bio": "Gestion de projets et strategie. Touche-à-tout. Peux toujours trouver le temps pour racontrer pour café."
+ "bio": "Gestion de projets et strategie. Touche-à-tout. Peut toujours trouver le temps pour racontrer pour café."
},
"cole": {
"name": "Cole Goodwin",
@@ -41,8 +41,8 @@
},
"john": {
"name": "John Barratt",
- "position": "Programmeur de Web Full-Stack",
- "bio": "Quand il ne programme pas, vous pouvez trouver John au forêt randonnant au bonnes sentiers de Colombie-Britannique."
+ "position": "Développeur Web Full-Stack",
+ "bio": "Quand il ne programme pas, vous pouvez trouver John en forêt randonnant sur les sentiers de Colombie-Britannique."
}
}
},
@@ -54,16 +54,16 @@
"faq": {
"header": "FAQ",
"cost": {
- "question": "Qu'est-ce que c'est le coût?",
- "answer": "coinos est gratuit à utiliser. Vous seulment payez un prix 1% quand vous convertez vos fonds entre bitcoin, Liquid et Lightning. Comparez-ça à les frais de dossir typiques 3% des cartes credit."
+ "question": "Quel est le coût?",
+ "answer": "coinos est gratuit à utiliser. Vous payez seulment 1% quand vous convertissez vos fonds entre bitcoin, Liquid et Lightning. Comparez-ça aux frais typiques 3% des cartes de crédit."
},
"compatibility": {
- "question": "Est-ce que j'ai besoin du logiciel ou appareil special?",
- "answer": "Non. coinos est un site Web, alors vous pouvez l'utiliser sur n'importe quelle appareil tant que vous aves un connexion d'Internet. La plupart des marchands l'utilise sur un téléphone ou une tablette."
+ "question": "Est-ce que j'ai besoin de logiciel ou d'appareil special ?",
+ "answer": "Non. coinos est un site Web, vous pouvez donc l'utiliser sur n'importe quel appareil tant que vous aves un connexion d'Internet. La plupart des marchands l'utilise sur un téléphone ou une tablette."
},
"safety": {
- "question": "Sont mes fonds saufs?",
- "answer": "Vos fonds sont entreposés en notre serveur sécurisé, mais nous recommendons que vous les retirez à votre propre entreposage pour les sauvegarder à long terme."
+ "question": "Sont mes fonds saufs ?",
+ "answer": "Vos fonds sont entreposés sur notre serveur sécurisé, mais nous recommandons que vous les retiriez vers votre propre entreposage pour les sauvegarder à long terme."
}
},
"footer": {
@@ -77,10 +77,10 @@
"news": "Nouvelles"
},
"howItWorks": {
- "header": "Comment Elle Fonctionne",
+ "header": "Comment cela Fonctionne",
"step1": {
- "header": "1. Crée votre compte",
- "description": "Un nom d'utilateur et mot de passe est tout qui est besoin pour commencer."
+ "header": "1. Créez votre compte",
+ "description": "Un nom d'utilateur et mot de passe est tout ce dont vous avez besoin pour commencer."
},
"step2": {
"header": "2. Demande pour des paiements",
@@ -88,46 +88,46 @@
},
"step3": {
"header": "3. C'est tout!",
- "description": "Vous pouvez convertir au monnaie local n'importe quand."
+ "description": "Vous pouvez convertir en monnaie local n'importe quand."
}
},
"landing": {
"header_before_icon": "Le",
"header_with_icon": "façon",
- "header_after_icon": "le plus façile d'accepter bitcoin en votre magasin.",
- "subheader": "Aggrandir votre clientèle et chiffre d'affaires par accepter bitcoin avec un point de vente façile à utiliser et dirigé. Logiciel et matériel informatique non obligatoire.",
+ "header_after_icon": "le plus façile d'accepter bitcoin dans votre magasin.",
+ "subheader": "Agrandir votre clientèle et chiffre d'affaires en acceptant bitcoin avec un point de vente façile à utiliser et géré. Logiciel et matériel informatique non obligatoire.",
"info1": {
- "title": "Paiements instants avec Lightning",
- "description": "Le moment que votre client envoie un paiment, c'est la. Vous ne devez pas attendre pour les décisions de banques ou vous inquieter pour des rejets de débit. Décisions instant, en secondes. Dis au revoir aux frais de dossir 3% des cartes de crédit."
+ "title": "Paiements instantanés avec Lightning",
+ "description": "Le moment où votre client envoie un paiment, c'est là. Vous ne devez pas attendre les décisions des banques ou vous inquiéter pour des rejets de débit. Décisions instantanées, en secondes. Dites au revoir aux frais de transactions de 3% des cartes de crédit."
},
"info2": {
"title": "Simple à utiliser, en garde par défaut",
"description1": "Juste entrer une quantité, partager le code QR et c'est tout!",
- "description2": "Tes contes sont en garde par défaut, qui élimine le nécessité de comprendre comment bitcoin/lightning fonctionnent. Nous réalisons le plus gros du travail pour que vous pouvez vous concentrer sur votre entreprise.",
- "description3": "Vous toujours avez l'option de <span class=\"underline undeline-offset-4\">prendre garde</span> de vos clés."
+ "description2": "Tes comptes sont en garde par défaut, qui élimine le nécessité de comprendre comment bitcoin/lightning fonctionnent. Nous réalisons le plus gros du travail pour que vous puissiez vous concentrer sur votre entreprise.",
+ "description3": "Vous avez toujours l'option de <span class=\"underline undeline-offset-4\">gérer</span> vos clés."
},
"info3": {
- "title": "Personalise-le comment vous voulez",
- "description": "Personalisez votre point de vente, ou rettenez-le au défaut - c'est votre chois."
+ "title": "Personalisez-le comme vous voulez",
+ "description": "Personalisez votre point de vente, ou utilisez les réglages par défaut - c'est votre chois."
}
},
"login": {
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"email": "Courriel",
- "passwordRecommendation": "Nous recommendons un mot de passe long et au hazard, généré par un gestionnaire de mots de passe.",
- "forgotUserOrPassword": "Oublié ton nom d'utilisateur ou mot de passe?",
- "haveAccount": "Avez-vous déjà une conte?",
- "noAccount": "N'avez-vous pas un conte?",
+ "passwordRecommendation": "Nous recommendons un mot de passe long et aléatoire, généré par un gestionnaire de mots de passe.",
+ "forgotUserOrPassword": "Oublié votre nom d'utilisateur ou mot de passe ?",
+ "haveAccount": "Avez-vous déjà un compte ?",
+ "noAccount": "Pas encore de compte ?",
"register": "Enregistrer",
"signIn": "Connexion",
- "failed": "Connexion failli",
+ "failed": "Echec de Connexion",
"optional": "Optionnel",
- "token": "Jeton A2F"
+ "token": "Jeton 2FA"
},
"nav": {
"startInSeconds": "Commence en Secondes",
- "account": "Conte",
+ "account": "Compte",
"signIn": "Connexion",
"signOut": "Déconnexion",
"dashboard": "Tableau de bord",
@@ -135,7 +135,7 @@
"support": "Assistance",
"profile": "Profil"
},
- "newSiteHeader": "Bienvenue à la <a href=\"/news\" class=\"underline underline-offset-4 text-black hover:opacity-80\">coinos nouvelle et amélioré</a>, concentré au marchants! Cherchez pour le dernier coinos? Visitez <a href=\"https://classic.coinos.io\" class=\"underline underline-offset-4 text-black hover:opacity-80\">classic.coinos.io</a>.",
+ "newSiteHeader": "Bienvenue sur <a href=\"/news\" class=\"underline underline-offset-4 text-black hover:opacity-80\">coinos nouveau et amélioré</a>, focalisé sur les marchants! Vous cherchez l'ancien coinos? Visitez <a href=\"https://classic.coinos.io\" class=\"underline underline-offset-4 text-black hover:opacity-80\">classic.coinos.io</a>.",
"invoice": {
"addTip": "Ajoutez un pourboire",
"addTipq": "Ajouter un pourboire?",
@@ -161,7 +161,7 @@
"dashboard": "Tableau de bord",
"accountBalance": "Solde",
"bitcoinPrice": "Prix de bitcoin:",
- "conversionFeeWarning": "Il y a un prix de 1% pour convertir entre bitcoin, Liquid et Lightning.",
+ "conversionFeeWarning": "Il y a des frais de 1% pour convertir entre bitcoin, Liquid et Lightning.",
"dataFromBinance": "Données de <span class=\"text-black\">Binance</span>.",
"fetchingRate": "cherchant taut de change...",
"optionalNote": "Note (optionel)",
@@ -174,21 +174,21 @@
},
"receive": {
"lessThan1BTCWarning": "S'il vous plaît utilisez moins d'un bitcoin.",
- "showQR": "Voire QR"
+ "showQR": "Voire le QR code"
},
"settings": {
"header": "Préférences",
- "ACCOUNT": "CONTE",
+ "ACCOUNT": "COMPTE",
"POINT_OF_SALE": "POINT DE VENTE",
"SECURITY": "SÉCURITÉ",
"locale": "Langue",
"username": "Nom d'Utilisateur",
"email": "Courriel",
- "newPassword": "Mot de Passe Nouveau",
+ "newPassword": "Nouveau Mot de Passe",
"emailNotifications": "Notifications par Courriel",
- "emailNotificationsDescription": "Nous pouvons vous notifier par courriel quand votre conte change ou quand vous recevez des paiements",
+ "emailNotificationsDescription": "Nous pouvons vous notifier par courriel quand votre compte change ou quand vous recevez des paiements",
"smsNotifications": "Notifications par SMS",
- "smsNotificationsDescription": "Nous vous envoyons des notifications par texte quand ceci est activé",
+ "smsNotificationsDescription": "Nous vous envoyons des notifications par texte quand c'est activé",
"theme": "Thème",
"themeDescription": "Sélectionnez des thèmes dèfauts.",
"localCurrency": "Monnaie Local",
@@ -263,13 +263,13 @@
"export": "Exportez",
"invoice": "Facture",
"readyToPay": "est prêt à payer",
- "describeOrder": "Utilizer ce champ pour décrire votre commande",
+ "describeOrder": "Utiliser ce champ pour décrire votre commande",
"requestAnInvoice": "Demandez une facture",
"submit": "Soumettre",
"isRequesting": "demande",
"invoiceFrom": "Facture de",
"awaiting": "Attendez pour",
- "tapAnywhere": "Tapez partout",
+ "tapAnywhere": "Tapez n'importe où",
"from": "de",
"redeem": "Échangez",
"redeemed": "Déjà échangé",
diff --git a/src/routes/(app)/[username]/(profile)/+page.server.js b/src/routes/(app)/[username]/(profile)/+page.server.js
index 085271fd..d6cf3984 100644
--- a/src/routes/(app)/[username]/(profile)/+page.server.js
+++ b/src/routes/(app)/[username]/(profile)/+page.server.js
@@ -5,7 +5,7 @@ export async function load({ cookies, params, parent, url }) {
let { pubkey } = subject;
let { since = 0 } = params;
- let messages, invoices, sent, received;
+ let messages, invoices, sent, received;
messages = invoices = sent = received = [];
if (user) {
diff --git a/src/routes/(app)/[username]/(profile)/request/+page.server.js b/src/routes/(app)/[username]/(profile)/request/+page.server.js
index 2c1d6bde..e7ad6a8f 100644
--- a/src/routes/(app)/[username]/(profile)/request/+page.server.js
+++ b/src/routes/(app)/[username]/(profile)/request/+page.server.js
@@ -1,15 +1,15 @@
import { redirect } from '@sveltejs/kit';
-import { auth, post } from '$lib/utils';
+import { fd, auth, post } from '$lib/utils';
export const actions = {
create: async ({ cookies, params, request, url }) => {
- let form = Object.fromEntries(await request.formData());
+ let form = await fd(request);
let { id, requester } = await post('/requests', form, auth(cookies));
throw redirect(307, `/${params.username}/request/${id}`);
},
delete: async ({ cookies, request }) => {
- let form = Object.fromEntries(await request.formData());
+ let form = await fd(request);
let r = await post('/requests/delete', form, auth(cookies));
}
};
diff --git a/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte
index 432b137a..3a281728 100644
--- a/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte
+++ b/src/routes/(app)/[username]/invoice/[hash]/paid/+page.svelte
@@ -4,7 +4,7 @@
import { toast } from '@zerodevx/svelte-toast';
import { browser } from '$app/environment';
import { t } from '$lib/translations';
- import { f, s, sat, sats } from '$lib/utils';
+ import { fiat, f, s, sat, sats } from '$lib/utils';
import { goto } from '$app/navigation';
export let data;
@@ -12,10 +12,6 @@
$: data && ({ amount, currency, rate, received, pending, tip, user, id } = data.invoice);
toast.pop(0);
-
- $: amountFiat = parseFloat((((received - tip) * rate) / sats).toFixed(2));
- $: pendingFiat = parseFloat((((pending - tip) * rate) / sats).toFixed(2));
- $: tipFiat = parseFloat(((tip * rate) / sats).toFixed(2));
</script>
<div class="container px-4 text-center mx-auto">
@@ -25,15 +21,20 @@
{#if received}
<h1 class="text-3xl md:text-4xl font-bold mb-6">{$t('invoice.paymentSuccessful')}</h1>
<h2 class="text-2xl md:text-3xl font-semibold">
- {f(amountFiat, currency)}
+ {f(fiat(received - tip, rate), currency)}
{#if tip}
- + {f(tipFiat, currency)}
+ <span class="text-lg">
+ + {f(fiat(tip, rate), currency)}
+ </span>
{/if}
</h2>
<h3 class="text-secondary md:text-lg mb-6 mt-1">
- {sat(received - tip)}
+ ⚡️{s(received - tip)}
+
{#if tip}
- +{sat(tip)}
+ <span class="text-lg">
+ + ⚡️{s(tip)}
+ </span>
{/if}
</h3>
{/if}
@@ -41,15 +42,17 @@
{#if pending}
<h1 class="text-3xl md:text-4xl font-bold mb-6">Payment detected</h1>
<h2 class="text-2xl md:text-3xl font-semibold">
- {f(pendingFiat, currency)}
+ {f(fiat(pending, rate), currency)}
{#if tip}
- + {f(tipFiat, currency)}
+ + {f(fiat(tip, rate), currency)}
{/if}
</h2>
<h3 class="text-secondary md:text-lg mb-6 mt-1">
- {sat(pending - tip)}
+ ⚡️{s(pending - tip)}
{#if tip}
- +{sat(tip)}
+ <span class="text-lg">
+ + ⚡️{s(tip)}
+ </span>
{/if}
</h3>
{/if}
diff --git a/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte b/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte
index d033c413..296ef9c6 100644
--- a/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte
+++ b/src/routes/(app)/[username]/invoice/[hash]/tip/+page.svelte
@@ -3,7 +3,7 @@
import { browser } from '$app/environment';
import { invoice as inv, request } from '$lib/store';
import { copy, focus, f, sat, get, reverseFormat, s, sats } from '$lib/utils';
- import { Icon } from '$comp';
+ import { Icon, Slider } from '$comp';
import { goto } from '$app/navigation';
import { t } from '$lib/translations';
import { enhance } from '$app/forms';
@@ -37,9 +37,6 @@
customInput.value = '';
}
tipPercent = e.target.value;
-
- clearTimeout(timeout);
- timeout = setTimeout(update, 800);
};
let submitting;
@@ -56,10 +53,6 @@
};
let submit;
- let update = async () => {
- await tick();
- //submit.click();
- };
export let data;
$: refresh(data);
@@ -123,16 +116,7 @@
{#if !showCustomAmount}
<div class="my-2 text-xl">{Math.round(tipPercent)}%</div>
- <input
- id="slider"
- type="range"
- min="0"
- max="100"
- value={tipPercent}
- class="px-0 py-0 my-5"
- style="--bgPercent: {tipPercent}%;"
- on:input={handleSlide}
- />
+ <Slider handle={handleSlide} bind:value={tipPercent} />
<div class="flex mb-8 text-lg">
<div>
@@ -201,43 +185,6 @@
</div>
<style>
- #slider {
- -webkit-appearance: none;
- width: 100%;
- height: 6px;
- border-radius: 5px;
- background: linear-gradient(
- to right,
- black 0%,
- black var(--bgPercent),
- #f5f7fa var(--bgPercent),
- #f5f7fa 100%
- );
- outline: none;
- }
-
- #slider:active {
- background-color: black;
- }
-
- #slider::-webkit-slider-thumb {
- -webkit-appearance: none;
- appearance: none;
- width: 30px;
- height: 30px;
- border-radius: 50%;
- background: black;
- cursor: pointer;
- }
-
- #slider::-moz-range-thumb {
- width: 30px;
- height: 30px;
- border-radius: 50%;
- background: black;
- cursor: pointer;
- }
-
.active {
@apply !bg-black !text-white;
}
diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.server.js b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js
index e833a102..4e80a5ad 100644
--- a/src/routes/(app)/[username]/settings/[...tab]/+page.server.js
+++ b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js
@@ -1,5 +1,5 @@
import { fail, redirect } from '@sveltejs/kit';
-import { auth, get, post } from '$lib/utils';
+import { fd, auth, get, post } from '$lib/utils';
export function load({ params, url }) {
if (url.pathname.endsWith('settings')) throw redirect(307, url.pathname + '/account');
@@ -8,7 +8,7 @@ export function load({ params, url }) {
export const actions = {
default: async ({ cookies, request }) => {
- let form = Object.fromEntries(await request.formData());
+ let form = await fd(request);
form.prompt = form.prompt === 'on';
let user = { ...(await get('/me', auth(cookies))), ...form };
diff --git a/src/routes/(app)/ln/[lnurl]/+page.server.js b/src/routes/(app)/ln/[lnurl]/+page.server.js
index a12b063c..ddd714bf 100644
--- a/src/routes/(app)/ln/[lnurl]/+page.server.js
+++ b/src/routes/(app)/ln/[lnurl]/+page.server.js
@@ -1,4 +1,4 @@
-import { auth, get, post } from '$lib/utils';
+import { fd, auth, get, post } from '$lib/utils';
import { error, fail, redirect } from '@sveltejs/kit';
export async function load({ params, parent }) {
@@ -24,10 +24,7 @@ export const actions = {
pay: async ({ cookies, fetch, request }) => {
let error;
- let { callback, amount, minSendable, maxSendable } = Object.fromEntries(
- await request.formData()
- );
-
+ let { callback, amount, minSendable, maxSendable } = await fd(request);
minSendable = Math.round(minSendable / 1000);
maxSendable = Math.round(maxSendable / 1000);
@@ -42,8 +39,9 @@ export const actions = {
withdraw: async ({ cookies, fetch, request }) => {
let error;
- let { callback, amount, username, currency, minWithdrawable, maxWithdrawable, k1 } =
- Object.fromEntries(await request.formData());
+ let { callback, amount, username, currency, minWithdrawable, maxWithdrawable, k1 } = await fd(
+ request
+ );
minWithdrawable = Math.round(minWithdrawable / 1000);
maxWithdrawable = Math.round(maxWithdrawable / 1000);
diff --git a/src/routes/(app)/login/+page.server.js b/src/routes/(app)/login/+page.server.js
index a6a7120a..67f686e0 100644
--- a/src/routes/(app)/login/+page.server.js
+++ b/src/routes/(app)/login/+page.server.js
@@ -1,5 +1,5 @@
import { fail, redirect } from '@sveltejs/kit';
-import { login } from '$lib/utils';
+import { login, fd } from '$lib/utils';
export const load = async ({ parent }) => {
let { user } = await parent();
@@ -8,7 +8,7 @@ export const load = async ({ parent }) => {
export const actions = {
default: async ({ cookies, request }) => {
- let form = Object.fromEntries(await request.formData());
+ let form = await fd(request);
let { username, password, token, loginRedirect } = form;
let user = { username, password, token };
diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte
index 2988ddb5..b8a23605 100644
--- a/src/routes/(app)/payment/[id]/+page.svelte
+++ b/src/routes/(app)/payment/[id]/+page.svelte
@@ -8,7 +8,7 @@
export let data;
let { user, payment: p } = data;
let { username } = user;
- let { id, amount, created, rate, type, ref, ourfee, fee, currency } = p;
+ let { id, amount, created, rate, type, ref, tip, ourfee, fee, currency } = p;
let a = Math.abs(amount);
fee = fee || 0;
@@ -26,12 +26,14 @@
{#if p.with}
<div>
<span class="text-lg text-secondary my-auto mr-2">{amount > 0 ? 'From' : 'To'}</span>
+ <a href={`/${p.with.username}`}>
<div class="flex">
<div class="my-auto">
<Avatar user={p.with} size={20} />
</div>
- <div class="my-auto ml-1 text-secondary">{p.with.username}</div>
+ <div class="my-auto ml-1">{p.with.username}</div>
</div>
+ </a>
</div>
{/if}
@@ -39,7 +41,19 @@
<span class="text-lg text-secondary">Amount</span>
<div>
{f(fiat(a, rate), currency)}
- <span class="text-secondary">⚡️{`${s(a)}`}</span>
+ {#if tip}
+ <span class="text-lg">
+ + {f(fiat(tip, rate), currency)}
+ </span>
+ {/if}
+ <span class="text-secondary">⚡️{`${s(a)}`}
+
+ {#if tip}
+ <span class="text-lg">
+ + ⚡️{s(tip)}
+ </span>
+ {/if}
+ </span>
</div>
</div>
diff --git a/src/routes/(app)/pot/[name]/withdraw/+page.server.js b/src/routes/(app)/pot/[name]/withdraw/+page.server.js
index ab56867d..ac33e940 100644
--- a/src/routes/(app)/pot/[name]/withdraw/+page.server.js
+++ b/src/routes/(app)/pot/[name]/withdraw/+page.server.js
@@ -1,5 +1,5 @@
import { fail, redirect } from '@sveltejs/kit';
-import { auth, post } from '$lib/utils';
+import { fd, auth, post } from '$lib/utils';
export async function load({ parent }) {
let { user } = await parent();
@@ -8,8 +8,7 @@ export async function load({ parent }) {
export const actions = {
default: async ({ cookies, request }) => {
- let body = Object.fromEntries(await request.formData());
-
+ let body = await fd(request);
try {
await post('/take', body, auth(cookies));
} catch (e) {
diff --git a/src/routes/(app)/register/+page.server.js b/src/routes/(app)/register/+page.server.js
index 7799d5ae..e71b2a60 100644
--- a/src/routes/(app)/register/+page.server.js
+++ b/src/routes/(app)/register/+page.server.js
@@ -1,5 +1,5 @@
import { fail, redirect } from '@sveltejs/kit';
-import { post, login } from '$lib/utils';
+import { fd, post, login } from '$lib/utils';
export const load = async ({ parent }) => {
let { user } = await parent();
@@ -8,7 +8,7 @@ export const load = async ({ parent }) => {
export const actions = {
default: async ({ cookies, request }) => {
- let form = Object.fromEntries(await request.formData());
+ let form = await fd(request);
let { username, password, cipher, salt, pubkey, loginRedirect } = form;
let user = { username, password, cipher, salt, pubkey };
let error;
diff --git a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.server.js b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.server.js
index 59e9326d..92a754ae 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.server.js
+++ b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.server.js
@@ -1,23 +1,29 @@
import { fail, redirect } from '@sveltejs/kit';
-import { auth, post } from '$lib/utils';
+import { auth, post, fd } from '$lib/utils';
let seen = {};
export const actions = {
default: async ({ cookies, request }) => {
try {
- let feeRate, subtract;
- let { address, amount, pin, ts } = Object.fromEntries(await request.formData());
-
+ let { address, amount, confirmed, feeRate, subtract, pin, stale, ts } = await await fd(
+ request
+ );
if (seen[ts]) return fail(400, { message: 'Duplicate form submission' });
- seen[ts] = 1;
- setTimeout(() => delete seen[ts], 30000);
- let { tx } = await post(
+ let estimate = await post(
'/bitcoin/fee',
{ address, amount, feeRate, subtract },
auth(cookies)
);
- await post('/bitcoin/send', { pin, tx }, auth(cookies));
+
+ let { tx } = estimate;
+
+ if (stale || !confirmed) return fail(400, estimate);
+
+ seen[ts] = 1;
+ setTimeout(() => delete seen[ts], 30000);
+
+ await post('/bitcoin/send', { pin, subtract, tx }, auth(cookies));
} catch (e) {
return fail(400, { message: e.message });
}
diff --git a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte
index 6b216cb3..b3a944f4 100644
--- a/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/bitcoin/[address]/[...amount]/+page.svelte
@@ -1,24 +1,48 @@
<script>
+ import { tick } from 'svelte';
import { t } from '$lib/translations';
import { enhance } from '$app/forms';
- import { Icon, Numpad, Spinner } from '$comp';
+ import { Toggle, Slider, Icon, Numpad, Spinner } from '$comp';
import { page } from '$app/stores';
- import { back } from '$lib/utils';
- import { pin } from '$lib/store';
+ import { fiat as toFiat, f, back, s, sat } from '$lib/utils';
+ import { pin, selectedRate } from '$lib/store';
export let data;
export let form;
let { address, amount } = $page.params;
- let { currency } = data.user;
- let loading, submit;
+ let { balance, currency } = data.user;
+ let loading, submit, fiat, confirmed, feeRate, min, max, fee, ourfee, stale, subtract, adjusting;
let toggle = () => (loading = true);
+ let toggleAdjusting = () => (adjusting = !adjusting);
$: update(form);
let update = () => {
- if (form?.message.includes('pin')) $pin = undefined;
loading = false;
+ if (form?.message?.includes('pin')) $pin = undefined;
+ if (form) ({ min, max, feeRate, fee, ourfee, subtract } = form);
+ if (!ourfee) ourfee = 0;
+ if (feeRate) confirmed = true;
+ stale = false;
+ };
+
+ let setMax = () => {
+ fiat = false;
+ amount = balance;
+ subtract = true;
+ };
+
+ $: if (amount + fee > balance) subtract = true;
+
+ let timeout;
+ let handle = (e) => {
+ stale = true;
+ feeRate = e.target.value;
+ clearTimeout(timeout);
+ timeout = setTimeout(() => {
+ tick().then(() => submit.click());
+ }, 200);
};
</script>
@@ -32,30 +56,78 @@
</div>
{/if}
-<div class="container px-4 mt-20 max-w-xl mx-auto">
- <div class="text-center mb-8">
- <h1 class="text-3xl md:text-4xl font-semibold mb-2">{$t('payments.sendTo')}</h1>
- <p class="text-lg text-secondary">{address}</p>
- </div>
- <Numpad bind:amount {currency} {submit} />
+<div class="container px-4 mt-20 max-w-xl mx-auto space-y-5 text-center">
+ <h1 class="text-3xl md:text-4xl font-semibold mb-2">{$t('payments.send')}</h1>
+
+ <div class="text-lg text-secondary break-all">{address}</div>
+
+ {#if confirmed}
+ <div class="text-center">
+ <h2 class="text-2xl md:text-3xl font-semibold">
+ {f(toFiat(amount, $selectedRate), currency)}
+ </h2>
+ <h3 class="text-secondary md:text-lg mb-6 mt-1">⚡️{s(amount)}</h3>
+ </div>
+
+ <div class="text-center">
+ <h2 class="text-secondary mb-5 text-lg">with fee</h2>
+
+ <div class="relative">
+ <h2 class="text-xl font-semibold">
+ {f(toFiat(fee + ourfee, $selectedRate), currency)}
+ </h2>
+ <h3 class="text-secondary mb-6 mt-1">⚡️{s(fee + ourfee)}</h3>
+ <button class="absolute right-1/4 top-0 text-secondary p-4" on:click={toggleAdjusting}><Icon icon="settings" style="opacity-30" /></button>
+ </div>
+ </div>
+ {:else}
+ <Numpad bind:amount bind:fiat {currency} {submit} />
+ {/if}
<form method="POST" use:enhance on:submit={toggle}>
<input name="ts" value={Date.now()} type="hidden" />
<input name="address" value={address} type="hidden" />
<input name="amount" value={amount} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
+ <input name="confirmed" value={confirmed} type="hidden" />
+ <input name="feeRate" value={feeRate} type="hidden" />
+ <input name="stale" value={stale} type="hidden" />
+ <input name="subtract" value={subtract} type="hidden" />
+
+ {#if confirmed && adjusting}
+ <div class="relative mt-10 mb-20">
+ <div class="absolute top-5 left-0 text-secondary">Slower (~40 blocks)</div>
+ <div class="absolute top-5 right-0 text-secondary">Faster (~1 block)</div>
+ <Slider bind:value={feeRate} {handle} {min} {max} />
+ </div>
+ <div class="flex justify-center gap-2 mb-10">
+ <div class="my-auto">
+ <Toggle id="subtract" checked={subtract} bind:value={subtract} />
+ </div>
+ <label for="subtract" class="text-secondary text-lg my-auto mb-2">Take fee from amount</label>
+ </div>
+ {/if}
+
+ <div class="flex justify-center gap-2">
+ {#if !confirmed}
+ <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
+ >
+ {/if}
- <div class="flex w-full">
<button
bind:this={submit}
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-3 font-bold mt-2 bg-black text-white px-4 w-24"
disabled={loading}
>
- {#if loading}
- <Spinner />
- {:else}
+ {#if confirmed}
{$t('payments.send')}
+ {:else}
+ {$t('payments.next')}
{/if}
</button>
</div>
diff --git a/src/routes/(app)/send/invoice/[id]/+page.server.js b/src/routes/(app)/send/invoice/[id]/+page.server.js
index 2df19985..dc0d3a3d 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.server.js
+++ b/src/routes/(app)/send/invoice/[id]/+page.server.js
@@ -1,5 +1,5 @@
import { error, fail, redirect } from '@sveltejs/kit';
-import { btc as asset, auth, get, post } from '$lib/utils';
+import { fd, btc as asset, auth, get, post } from '$lib/utils';
export async function load({ params: { id }, parent }) {
let { user } = await parent();
@@ -13,15 +13,10 @@ export async function load({ params: { id }, parent }) {
export const actions = {
default: async ({ cookies, params: { hash }, request }) => {
try {
- let body = Object.fromEntries(await request.formData());
- let { confirmed } = body;
+ let body = await fd(request);
body.amount = parseInt(body.amount);
body.hash = hash;
- if (!confirmed) {
- return fail(400, { amount, confirm: true });
- }
-
await post('/payments', body, auth(cookies));
} catch (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 27837bca..7570a61a 100644
--- a/src/routes/(app)/send/invoice/[id]/+page.svelte
+++ b/src/routes/(app)/send/invoice/[id]/+page.svelte
@@ -69,7 +69,6 @@
<input name="amount" value={amount} type="hidden" />
<input name="payreq" value={payreq} type="hidden" />
<input name="username" value={recipient.username} type="hidden" />
- <input name="confirmed" value={form?.confirm} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
<div class="flex w-full">
diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.server.js b/src/routes/(app)/send/lightning/[payreq]/+page.server.js
index 90e6c0cc..02511a8f 100644
--- a/src/routes/(app)/send/lightning/[payreq]/+page.server.js
+++ b/src/routes/(app)/send/lightning/[payreq]/+page.server.js
@@ -1,23 +1,17 @@
import { fail, redirect } from '@sveltejs/kit';
-import { btc as asset, auth, post } from '$lib/utils';
+import { fd, btc as asset, auth, post } from '$lib/utils';
export async function load({ params }) {
return post('/parse', params);
}
export const actions = {
- setAmount: async ({ cookies, request }) => {
- return Object.fromEntries(await request.formData());
- },
+ setAmount: async ({ cookies, request }) => fd(request),
send: async ({ cookies, request }) => {
try {
- let body = Object.fromEntries(await request.formData());
- let { amount, confirmed } = body;
-
- if (!confirmed) {
- return fail(400, { amount, confirm: true });
- }
+ let body = await fd(request);
+ let { amount } = body;
await post('/payments', body, auth(cookies));
} catch (e) {
diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
index e9502636..af07a565 100644
--- a/src/routes/(app)/send/lightning/[payreq]/+page.svelte
+++ b/src/routes/(app)/send/lightning/[payreq]/+page.svelte
@@ -13,10 +13,11 @@
let { alias } = data;
let { currency } = data.user;
- let amount = form?.amount || data.amount;
let a;
let maxfee = 100;
+ $: amount = form?.amount || data.amount;
+
let loading;
let submit = () => (loading = true);
$: update(form);
@@ -53,7 +54,6 @@
<form method="POST" use:enhance on:submit={submit} action="?/send" class="space-y-5">
<input name="payreq" value={payreq} type="hidden" />
<input name="amount" value={amount} type="hidden" />
- <input name="confirmed" value={form?.confirm} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
<input name="maxfee" value={maxfee} type="hidden" />
diff --git a/src/routes/(app)/send/pot/[name]/[...amount]/+page.server.js b/src/routes/(app)/send/pot/[name]/[...amount]/+page.server.js
index 0e1b7f5b..6c11811c 100644
--- a/src/routes/(app)/send/pot/[name]/[...amount]/+page.server.js
+++ b/src/routes/(app)/send/pot/[name]/[...amount]/+page.server.js
@@ -3,7 +3,7 @@ import { auth, post } from '$lib/utils';
export const actions = {
default: async ({ cookies, request }) => {
- let body = Object.fromEntries(await request.formData());
+ let body = await fd(request);
let p;
try {
diff --git a/src/routes/(app)/send/pot/[name]/[...amount]/+page.svelte b/src/routes/(app)/send/pot/[name]/[...amount]/+page.svelte
index bb11ddde..da761cc2 100644
--- a/src/routes/(app)/send/pot/[name]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/pot/[name]/[...amount]/+page.svelte
@@ -16,7 +16,7 @@
let submit = () => (loading = true);
$: update(form);
let update = () => {
- if (form?.message.includes('pin')) $pin = undefined;
+ if (form?.message?.includes('pin')) $pin = undefined;
loading = false;
};
</script>
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 42b47c8f..ad0219e0 100644
--- a/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js
+++ b/src/routes/(app)/send/user/[username]/[...amount]/+page.server.js
@@ -1,5 +1,5 @@
import { error, fail, redirect } from '@sveltejs/kit';
-import { btc as asset, auth, get, post } from '$lib/utils';
+import { fd, btc as asset, auth, get, post } from '$lib/utils';
export async function load({ params, parent }) {
let { user } = await parent();
@@ -12,14 +12,10 @@ export async function load({ params, parent }) {
export const actions = {
default: async ({ cookies, request }) => {
try {
- let body = Object.fromEntries(await request.formData());
- let { amount, confirmed } = body;
+ let body = await fd(request);
+ let { amount } = body;
amount = parseInt(amount);
- if (!confirmed) {
- return fail(400, { amount, confirm: true });
- }
-
await post('/payments', body, auth(cookies));
} catch (e) {
console.log(e);
diff --git a/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte b/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte
index 9704e3c6..74da1fa8 100644
--- a/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte
+++ b/src/routes/(app)/send/user/[username]/[...amount]/+page.svelte
@@ -16,10 +16,11 @@
let amount = form?.amount || data.amount;
let a,
af,
- amountFiat = amount * ($selectedRate / sats),
fiat = !amount,
hash;
+ $: amountFiat = amount * ($selectedRate / sats);
+
let setAmount = async () => {
amount = a;
amountFiat = af;
@@ -39,7 +40,7 @@
$: update(form);
let update = () => {
- if (form?.message.includes('pin')) $pin = undefined;
+ if (form?.message?.includes('pin')) $pin = undefined;
loading = false;
};
</script>
@@ -68,7 +69,6 @@
<form method="POST" use:enhance on:submit={submit}>
<input name="amount" value={amount} type="hidden" />
<input name="username" value={subject.username} type="hidden" />
- <input name="confirmed" value={form?.confirm} type="hidden" />
<input name="pin" value={$pin} type="hidden" />
<input name="hash" value={hash} type="hidden" />
diff --git a/src/routes/(app)/sent/+page.svelte b/src/routes/(app)/sent/+page.svelte
index 79a0aa6e..72511487 100644
--- a/src/routes/(app)/sent/+page.svelte
+++ b/src/routes/(app)/sent/+page.svelte
@@ -1,5 +1,5 @@
<script>
- import { f, s, sat, sats } from '$lib/utils';
+ import { fiat, f, s, sat, sats } from '$lib/utils';
import { scale } from 'svelte/transition';
import { Icon } from '$comp';
import { toast } from '@zerodevx/svelte-toast';
@@ -7,13 +7,12 @@
export let data;
let { payments, user } = data;
+ let { currency, username } = user;
let payment = payments[0];
- let { amount, rate } = payment;
+ let { amount, rate, tip } = payment;
amount = Math.abs(amount);
- let fiat = (amount * rate) / sats;
-
toast.pop(0);
</script>
@@ -23,12 +22,25 @@
</div>
<h1 class="text-3xl md:text-4xl font-bold mb-6">Sent!</h1>
<h2 class="text-2xl md:text-3xl font-semibold">
- {f(fiat, user.currency)}
+ {f(fiat(amount, rate), currency)}
+ {#if tip}
+ <span class="text-lg">
+ + {f(fiat(tip, rate), currency)}
+ </span>
+ {/if}
</h2>
- <h3 class="text-secondary md:text-lg mb-6 mt-1">{sat(amount)}</h3>
+ <h3 class="text-secondary md:text-lg mb-6 mt-1">
+ ⚡️{s(amount)}
+
+ {#if tip}
+ <span class="text-lg">
+ + ⚡️{s(tip)}
+ </span>
+ {/if}
+ </h3>
</div>
-<a href={`/${user.username}/payments`}>
+<a href={`/${username}/payments`}>
<div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" />
</a>
diff --git a/src/routes/(app)/support/+page.server.js b/src/routes/(app)/support/+page.server.js
index 5d3bf988..6d0af616 100644
--- a/src/routes/(app)/support/+page.server.js
+++ b/src/routes/(app)/support/+page.server.js
@@ -1,10 +1,9 @@
-import { post } from '$lib/utils';
+import { fd, post } from '$lib/utils';
import { fail } from '@sveltejs/kit';
export const actions = {
default: async ({ cookies, request }) => {
- let form = Object.fromEntries(await request.formData());
-
+ let form = await fd(request);
try {
await post('/email', form);
} catch (e) {