commit 4b37b5c9249263f70fc8c3e204858c4101858c74 parent 00b7f799411f41fc544a0518a304a0cf29d58fa1 Author: Florian Dold <dold@taler.net> Date: Mon, 24 Aug 2026 11:50:40 +0200 merchant-webui: restore Swiss QR mark and onboarding actions Diffstat:
9 files changed, 62 insertions(+), 26 deletions(-)
diff --git a/packages/taler-merchant-webui/src/screens/GuidedSetupScreen.tsx b/packages/taler-merchant-webui/src/screens/GuidedSetupScreen.tsx @@ -371,7 +371,7 @@ export function GuidedSetupScreen({ </SetupStep> </div> - {isVerificationSufficient && !hasOrders && !hasTemplates && ( + {isVerificationSufficient && ( <section class="bg-white border border-gray-200 rounded-xl shadow-2xs p-4 sm:p-5"> <div class="flex items-start gap-3"> <span class="h-7 px-2 rounded-full border border-gray-300 bg-gray-50 text-gray-600 flex items-center justify-center text-2xs font-bold shrink-0"> diff --git a/packages/taler-merchant-webui/src/screens/KycAuthInstructionsScreen.tsx b/packages/taler-merchant-webui/src/screens/KycAuthInstructionsScreen.tsx @@ -643,7 +643,7 @@ export function KycAuthInstructionsScreen({ <div key={`qr-${qIdx}`} class="flex flex-col items-center gap-2"> <TalerQrCode url={q.qrContent} - size={200} + size={360} variant={variant} alt={label} /> diff --git a/packages/taler-merchant-webui/src/screens/screens.test.tsx b/packages/taler-merchant-webui/src/screens/screens.test.tsx @@ -854,7 +854,7 @@ test("GuidedSetupScreen does not claim that a broken configured logo was added", document.body.removeChild(container); }); -test("GuidedSetupScreen offers first-payment choices only after required setup", () => { +test("GuidedSetupScreen keeps next steps after required setup", () => { const container = document.createElement("div"); document.body.appendChild(container); const accounts = [{ @@ -872,10 +872,17 @@ test("GuidedSetupScreen offers first-payment choices only after required setup", assert.match(container.textContent ?? "", /Create a one-off order/); render( - <GuidedSetupScreen businessName="ACME Coffee" accounts={accounts} hasOrders />, + <GuidedSetupScreen + businessName="ACME Coffee" + accounts={accounts} + hasOrders + hasTemplates + />, container, ); - assert.doesNotMatch(container.textContent ?? "", /Take your first payment/); + assert.match(container.textContent ?? "", /Take your first payment/); + assert.match(container.textContent ?? "", /Create a printable payment template/); + assert.match(container.textContent ?? "", /Create a one-off order/); render(null, container); document.body.removeChild(container); }); @@ -7854,6 +7861,27 @@ test("the Taler QR component uses the branded frame proportions and smaller logo document.body.removeChild(container); }); +test("the Swiss QR component uses the proportional SIX recognition mark", () => { + const container = document.createElement("div"); + document.body.appendChild(container); + render( + <TalerQrCode url="SPC\n0200\n1" size={360} variant="swiss" />, + container, + ); + + const frame = container.firstElementChild?.firstElementChild as HTMLElement; + assert.strictEqual(frame.style.width, "100%"); + assert.strictEqual(frame.style.aspectRatio, "1 / 1"); + const cross = frame.querySelector(".swiss-qr-cross") as HTMLElement | null; + assert.ok(cross); + assert.strictEqual(cross.style.width, "15.217%"); + assert.strictEqual(cross.style.height, "15.217%"); + assert.strictEqual(cross.style.zIndex, "2"); + + render(null, container); + document.body.removeChild(container); +}); + /** * How many QR codes the verification screen draws for an instruction. * diff --git a/packages/taler-merchant-webui/src/stories/story-data.tsx b/packages/taler-merchant-webui/src/stories/story-data.tsx @@ -754,6 +754,8 @@ export const STORIES: Story[] = [ businessAddress="Bahnhofstrasse 1, 8001 Zurich" businessLogo={DEMO_BUSINESS_LOGO} accounts={HEALTHY_ACCOUNTS} + hasOrders + hasTemplates /> ), }, diff --git a/packages/taler-merchant-webui/src/ui/TalerQrCode.tsx b/packages/taler-merchant-webui/src/ui/TalerQrCode.tsx @@ -75,12 +75,15 @@ export function TalerQrCode({ }; return ( - <div class="flex flex-col items-center justify-center space-y-4"> + <div + class="flex flex-col items-center justify-center space-y-4" + style={{ width: `${size}px`, maxWidth: "100%" }} + > {/* Container styling based on variant */} <div style={{ - width: `${size}px`, - height: `${size}px`, + width: "100%", + aspectRatio: "1 / 1", padding: variant === "taler" ? undefined : "10px", borderRadius: variant === "taler" ? "8%" : "24px", position: "relative", @@ -172,27 +175,34 @@ export function TalerQrCode({ )} {variant === "swiss" && qrResult.type === "success" && ( - <div + // SIX supplies this exact 7 mm artwork for overlaying a 46 mm Swiss + // QR Code. Keeping the ratio here makes the recognition mark scale + // with responsive on-screen codes as well as with fixed-size ones. + <svg + class="swiss-qr-cross" + viewBox="0 0 19.8 19.8" + aria-hidden="true" style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", - backgroundColor: "#FFFFFF", - padding: "2px", - border: "1px solid #000000", - boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)", - display: "flex", - alignItems: "center", - justifyContent: "center", + width: "15.217%", + height: "15.217%", + zIndex: 2, }} > - {/* Swiss Cross (White Cross on Black background per Swiss QR-bill standard) */} - <svg width="22" height="22" viewBox="0 0 24 24" fill="none"> - <rect width="24" height="24" fill="#000000" /> - <path fill="#FFFFFF" d="M10 5h4v5h5v4h-5v5h-4v-5H5v-4h5V5z" /> - </svg> - </div> + <polygon points="18.3,0.7 1.6,0.7 0.7,0.7 0.7,1.6 0.7,18.3 0.7,19.1 1.6,19.1 18.3,19.1 19.1,19.1 19.1,18.3 19.1,1.6 19.1,0.7" /> + <rect x="8.3" y="4" width="3.3" height="11" fill="#FFFFFF" /> + <rect x="4.4" y="7.9" width="11" height="3.3" fill="#FFFFFF" /> + <polygon + points="0.7,1.6 0.7,18.3 0.7,19.1 1.6,19.1 18.3,19.1 19.1,19.1 19.1,18.3 19.1,1.6 19.1,0.7 18.3,0.7 1.6,0.7 0.7,0.7" + fill="none" + stroke="#FFFFFF" + stroke-width="1.4357" + stroke-miterlimit="10" + /> + </svg> )} </div> diff --git a/packages/taler-merchant-webui/visual/baselines/kyc-instructions-desktop.aria.yml b/packages/taler-merchant-webui/visual/baselines/kyc-instructions-desktop.aria.yml @@ -127,7 +127,6 @@ - role: "StaticText" name: "Point your banking app at this and it fills the transfer in for you." - role: "generic" - - role: "generic" - role: "InlineTextBox" name: "Swiss QR-bill" - role: "InlineTextBox" @@ -202,7 +201,6 @@ name: "Point your banking app at this and it fills the transfer in for you." - role: "image" name: "Swiss QR-bill" - - role: "image" - role: "StaticText" name: "Copy IBAN" - role: "StaticText" diff --git a/packages/taler-merchant-webui/visual/baselines/kyc-instructions-desktop.webp b/packages/taler-merchant-webui/visual/baselines/kyc-instructions-desktop.webp Binary files differ. diff --git a/packages/taler-merchant-webui/visual/baselines/kyc-instructions-mobile.aria.yml b/packages/taler-merchant-webui/visual/baselines/kyc-instructions-mobile.aria.yml @@ -141,7 +141,6 @@ - role: "StaticText" name: "Point your banking app at this and it fills the transfer in for you." - role: "generic" - - role: "generic" - role: "InlineTextBox" name: "Swiss QR-bill" - role: "InlineTextBox" @@ -240,7 +239,6 @@ name: "fills the transfer in for you." - role: "image" name: "Swiss QR-bill" - - role: "image" - role: "StaticText" name: "Copy IBAN" - role: "StaticText" diff --git a/packages/taler-merchant-webui/visual/baselines/kyc-instructions-mobile.webp b/packages/taler-merchant-webui/visual/baselines/kyc-instructions-mobile.webp Binary files differ.