From 2fb060f79aaed3f60506c20caa2ff4fc319544f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Fri, 10 Jul 2026 23:05:00 +0200 Subject: [PATCH] landings: clickable blue payload links under every QR (webextension) Show the exact encoded URI (taler:// / https / payto://) as a blue monospace link under each QR so wallet webextensions and desktop can open it. Stop stripping :443 in the bank withdraw QR path. Shop pay and exchange withdraw-exchange included. --- configs/bank-landing/index.html | 65 ++++++++++++++++++++++----- configs/bank-landing/shop-pay.css | 19 ++++++++ configs/bank-landing/shop-pay.js | 19 +++++++- configs/exchange-landing/index.html | 8 +++- configs/merchant-landing/shop-pay.css | 19 ++++++++ configs/merchant-landing/shop-pay.js | 19 +++++++- 6 files changed, 134 insertions(+), 15 deletions(-) diff --git a/configs/bank-landing/index.html b/configs/bank-landing/index.html index 1ebe034..2e4cefc 100644 --- a/configs/bank-landing/index.html +++ b/configs/bank-landing/index.html @@ -363,22 +363,27 @@ text-align: center; max-width: 100%; } + /* Blue payload link under each QR (encoded content) */ a.meta-uri { display: block; - font-size: 0.72rem; - color: #5eead4; + font-size: 0.68rem; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + color: #7eb6ff; word-break: break-all; - margin: 0.35rem 0 0; + margin: 0.4rem auto 0; text-align: center; max-width: 22rem; text-decoration: none; - border-bottom: 1px solid rgba(94, 234, 212, 0.35); + border-bottom: 1px solid rgba(126, 182, 255, 0.4); line-height: 1.35; cursor: pointer; } a.meta-uri:hover { - color: #99f6e4; - border-bottom-color: #5eead4; + color: #b8d6ff; + border-bottom-color: #7eb6ff; + } + .qr-taler-wrap a.meta-uri { + margin-top: 0.45rem; } a.meta-uri.disabled, a.meta-uri[href="#"] { @@ -1250,11 +1255,11 @@ tw balance
Scan in wallet
+ Preparing withdraw… Open in wallet → - Preparing withdraw… @@ -1331,6 +1336,10 @@ tw balance
Username
Password
+
+
payto
+
+

Your account · bank UI login
+ https://bank.hacktivism.ch/webui/ @@ -1350,10 +1360,11 @@ tw balance
Bank UI · open site
+ https://bank.hacktivism.ch/webui/
- Open bank UI → + Open bank UI → @@ -1569,9 +1580,8 @@ tw balance } function setDemoWithdraw(uri, amount) { - uri = String(uri || "") - .replace(/:443\//g, "/") - .replace(/:443\?/g, "?"); + /* Keep host:port (…:443) — required for taler-integration withdraw */ + uri = String(uri || "").trim(); var open = document.getElementById("open-withdraw-demo"); var meta = document.getElementById("withdraw-demo-meta"); if (open) { @@ -1752,8 +1762,33 @@ tw balance if (box) box.hidden = false; var u = document.getElementById("auto-account-user"); var p = document.getElementById("auto-account-pass"); + var payA = document.getElementById("auto-account-payto"); + var webuiA = document.getElementById("auto-account-webui"); if (u) u.textContent = d.username || d.name || d.display_name || "—"; if (p) p.textContent = d.password || "—"; + /* Absolute HTTPS bank UI (never relative under ) */ + var webui = d.webui || d.account_url || WEBUI; + if (!/^https?:\/\//i.test(webui)) { + webui = WEBUI; + } + if (webuiA) { + webuiA.href = webui; + webuiA.setAttribute("target", "_blank"); + webuiA.setAttribute("rel", "noopener noreferrer"); + } + /* payto must include host:port (e.g. bank.hacktivism.ch:443) */ + var payto = d.payto_uri || ""; + if (payA) { + if (payto && payto.indexOf("payto://") === 0) { + payA.href = payto; + payA.textContent = payto; + payA.classList.remove("disabled"); + } else { + payA.href = "#"; + payA.textContent = "—"; + payA.classList.add("disabled"); + } + } if (st) { st.textContent = "Account created for you · " + @@ -1763,12 +1798,18 @@ tw balance /* Fancy QR_Taler: encode bank UI URL (login with credentials above) */ var qrBlock = document.getElementById("auto-account-qr-block"); var qrLabel = document.getElementById("qr-auto-acct-label"); - var webui = d.webui || WEBUI; if (qrBlock) qrBlock.hidden = false; if (qrLabel) { qrLabel.textContent = "QR_Taler · open bank UI · login as " + (d.username || "you"); } + var autoPayload = document.getElementById("qr-auto-acct-payload"); + if (autoPayload) { + autoPayload.href = webui; + autoPayload.textContent = webui; + autoPayload.setAttribute("target", "_blank"); + autoPayload.setAttribute("rel", "noopener noreferrer"); + } makeQr( document.getElementById("qr-auto-acct"), webui, diff --git a/configs/bank-landing/shop-pay.css b/configs/bank-landing/shop-pay.css index b14d7bd..c39a62e 100644 --- a/configs/bank-landing/shop-pay.css +++ b/configs/bank-landing/shop-pay.css @@ -138,6 +138,25 @@ button.shop-item { background: #fff; border-radius: 4px; } +/* Full encoded payload under QR — clickable (wallet / webextension) */ +.goa-pay-payload { + display: block; + margin: 0.45rem 0 0.55rem; + padding: 0 0.25rem; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 0.68rem; + line-height: 1.35; + color: #7eb6ff; + word-break: break-all; + text-align: center; + text-decoration: none; + border-bottom: 1px solid rgba(126, 182, 255, 0.4); + cursor: pointer; +} +.goa-pay-payload:hover { + color: #b8d6ff; + border-bottom-color: #7eb6ff; +} /* Settlement: collapsed by default, expand on click */ .goa-pay-settle { diff --git a/configs/bank-landing/shop-pay.js b/configs/bank-landing/shop-pay.js index 5797dc0..2c0573b 100644 --- a/configs/bank-landing/shop-pay.js +++ b/configs/bank-landing/shop-pay.js @@ -69,6 +69,7 @@ '
' + ' ' + "
" + + ' ' + ' Open payment link →' + '

' + ' taler:// URI' + @@ -90,6 +91,7 @@ '

Settlement only
' + '
' + " " + + ' ' + '

' + ' payto:// URI' + ' ·' + @@ -127,6 +129,11 @@ if (open) { // paint payto QR when first expanded renderQr(document.getElementById("goa-pay-qr-payto"), SHOP_PAYTO, 140); + var pp = document.getElementById("goa-pay-payto-payload"); + if (pp) { + pp.href = SHOP_PAYTO; + pp.textContent = SHOP_PAYTO; + } } }; document.addEventListener("keydown", function (e) { @@ -335,11 +342,17 @@ // Open first so layout exists, then paint wallet QR only m.hidden = false; m.classList.add("open"); + var tpl = payTemplateUri(productId); renderQr( document.getElementById("goa-pay-qr-pay"), - payTemplateUri(productId), + tpl, 220 ); + var payload = document.getElementById("goa-pay-qr-payload"); + if (payload) { + payload.href = tpl; + payload.textContent = tpl; + } createPayUri(productId) .then(function (info) { @@ -355,6 +368,10 @@ uh.textContent = "HTTPS"; // Live unpaid taler://pay (fresh order each open) renderQr(document.getElementById("goa-pay-qr-pay"), pay, 220); + if (payload) { + payload.href = pay; + payload.textContent = pay; + } status.textContent = "Ready — scan in wallet"; }) .catch(function (err) { diff --git a/configs/exchange-landing/index.html b/configs/exchange-landing/index.html index 3322305..368cd28 100644 --- a/configs/exchange-landing/index.html +++ b/configs/exchange-landing/index.html @@ -416,6 +416,9 @@ sudo apt-get install -y taler-wallet-cli

Scan in wallet
+ taler://withdraw-exchange/exchange.hacktivism.ch/
Open in wallet →

taler://withdraw-exchange/exchange.hacktivism.ch/

@@ -565,9 +568,12 @@ sudo apt-get install -y taler-wallet-cli if (foot) foot.innerHTML = 'Stats offline · bank.hacktivism.ch'; }); var el = document.getElementById("qr-exchange"); + var exUri = "taler://withdraw-exchange/exchange.hacktivism.ch/"; + var exPay = document.getElementById("qr-exchange-payload"); + if (exPay) { exPay.href = exUri; exPay.textContent = exUri; } if (el && typeof QRCode !== "undefined") { new QRCode(el, { - text: "taler://withdraw-exchange/exchange.hacktivism.ch/", + text: exUri, width: 220, height: 220, correctLevel: QRCode.CorrectLevel.M }); } diff --git a/configs/merchant-landing/shop-pay.css b/configs/merchant-landing/shop-pay.css index b14d7bd..c39a62e 100644 --- a/configs/merchant-landing/shop-pay.css +++ b/configs/merchant-landing/shop-pay.css @@ -138,6 +138,25 @@ button.shop-item { background: #fff; border-radius: 4px; } +/* Full encoded payload under QR — clickable (wallet / webextension) */ +.goa-pay-payload { + display: block; + margin: 0.45rem 0 0.55rem; + padding: 0 0.25rem; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 0.68rem; + line-height: 1.35; + color: #7eb6ff; + word-break: break-all; + text-align: center; + text-decoration: none; + border-bottom: 1px solid rgba(126, 182, 255, 0.4); + cursor: pointer; +} +.goa-pay-payload:hover { + color: #b8d6ff; + border-bottom-color: #7eb6ff; +} /* Settlement: collapsed by default, expand on click */ .goa-pay-settle { diff --git a/configs/merchant-landing/shop-pay.js b/configs/merchant-landing/shop-pay.js index 5797dc0..2c0573b 100644 --- a/configs/merchant-landing/shop-pay.js +++ b/configs/merchant-landing/shop-pay.js @@ -69,6 +69,7 @@ '
' + ' ' + " " + + ' ' + ' Open payment link →' + '

' + ' taler:// URI' + @@ -90,6 +91,7 @@ '

Settlement only
' + '
' + " " + + ' ' + '

' + ' payto:// URI' + ' ·' + @@ -127,6 +129,11 @@ if (open) { // paint payto QR when first expanded renderQr(document.getElementById("goa-pay-qr-payto"), SHOP_PAYTO, 140); + var pp = document.getElementById("goa-pay-payto-payload"); + if (pp) { + pp.href = SHOP_PAYTO; + pp.textContent = SHOP_PAYTO; + } } }; document.addEventListener("keydown", function (e) { @@ -335,11 +342,17 @@ // Open first so layout exists, then paint wallet QR only m.hidden = false; m.classList.add("open"); + var tpl = payTemplateUri(productId); renderQr( document.getElementById("goa-pay-qr-pay"), - payTemplateUri(productId), + tpl, 220 ); + var payload = document.getElementById("goa-pay-qr-payload"); + if (payload) { + payload.href = tpl; + payload.textContent = tpl; + } createPayUri(productId) .then(function (info) { @@ -355,6 +368,10 @@ uh.textContent = "HTTPS"; // Live unpaid taler://pay (fresh order each open) renderQr(document.getElementById("goa-pay-qr-pay"), pay, 220); + if (payload) { + payload.href = pay; + payload.textContent = pay; + } status.textContent = "Ready — scan in wallet"; }) .catch(function (err) {