import { mountLogo } from "./ds/logo.js"; import { startNavScroll } from "./ds/header.js"; import { mountMobileChrome, base } from "./ds/frame.js"; import { npubFrom, prod } from "./ds/env.js"; import { qrButton, mountModuleQrs } from "./module-qr.js?v=3"; import { freeDefinitions, businessDefinitions, moduleDestination, businessUrl } from './business-destinations.js?v=1'; const app = document.querySelector("#app"), toast = document.querySelector("#toast"); const npub = npubFrom(); const esc = (value) => String(value ?? "").replace( /[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ char ], ); function freeCard([id, name, copy, icon], data) { const url = data.links?.[id] || "#"; const qr = url === '#' ? '' : qrButton(id, name, url, {free: true}); return ``; } function moduleCard( [id, name, copy, audience, icon, configurable, target = id], data, ) { const {state, paymentSetup, disabled, url, qrUrl} = moduleDestination( [id, name, copy, audience, icon, configurable, target], data, npub); const qr = disabled ? '' : qrButton(id, name, qrUrl, {hidden: configurable && !state.enabled}); return `
${icon}${paymentSetup ? "Setup required" : esc(audience)}

${esc(name)}

${paymentSetup ? "Add the merchant’s Lightning address before accepting payments." : esc(copy)}

${qr}
${paymentSetup ? "Change Lightning address" : "Open"} ↗${configurable && !paymentSetup ? `` : paymentSetup ? 'Locked' : 'Operations'}
`; } function render(data) { const merchant = data.merchant, image = data.images[0] || ""; document.title = `${merchant.name} · Just Works Business`; app.innerHTML = `
Just WorksBusinessView nsite ↗

${esc([merchant.category, merchant.area].filter(Boolean).join(" · "))}

${esc(merchant.name)}

Free public presence. Business tools when you need them.
${data.counts.orders}Open orders
${data.counts.payments}Payments
QR in DIN A4 ↗

Free links

Included with Just Works.

Your merchant identity, website and discovery pages stay free.

Business modules

Tools that run the place.

Every module carries this merchant’s npub. Switch it on, share its link, or put it behind a QR code.

${businessDefinitions.map((item) => moduleCard(item, data)).join("")}
`; document .querySelectorAll("[data-module]") .forEach((input) => input.addEventListener("change", save)); document .querySelectorAll("[data-logo]") .forEach((host) => mountLogo(host, { icon: true })); startNavScroll(document.querySelector("[data-topbar]")); mountModuleQrs(app); } async function save() { const input = this; input.disabled = true; const modules = Object.fromEntries( [...document.querySelectorAll("[data-module]")].map((item) => [ item.dataset.module, item.checked, ]), ); try { const response = await fetch("/api/business-config", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ npub, modules }), }); if (!response.ok) throw new Error((await response.json()).error || "Could not save"); const qr = input.closest('.module').querySelector('[data-module-qr]'); if (qr) qr.hidden = !input.checked; toast.textContent = `${input.checked ? "Activated" : "Disabled"} ${input.closest(".module").querySelector("h2").textContent}`; toast.classList.add("show"); setTimeout(() => toast.classList.remove("show"), 1500); } catch (error) { input.checked = !input.checked; toast.textContent = error.message; toast.classList.add("show", "error"); setTimeout(() => toast.classList.remove("show", "error"), 2200); } finally { input.disabled = false; } } function fail(message) { app.innerHTML = `
∩

Business setup

${esc(message)}

Open this page with the merchant’s npub.

`; } if (!npub) fail("Which merchant is this?"); else fetch(`/api/business?npub=${encodeURIComponent(npub)}`, { cache: "no-store" }) .then(async (response) => { const data = await response.json(); if (!response.ok) throw new Error(data.error || "Merchant unavailable"); render(data); mountMobileChrome(app); }) .catch((error) => fail(error.message));