Files
archy/docker/justworks/business/public/assets/business-destinations.js
T
yaya 94899e69d3 feat: integrate Just Works app and native business setup
Preserve hosted website UX inside Archipelago, add isolated Business and owner-authorized native wallet setup, and include deployment handoff. Based on main with native signer import already accepted.
2026-10-08 19:39:38 +01:00

73 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { link, base } from './ds/frame.js';
import { prod } from './ds/env.js';
import { moduleQrUrl } from './module-qr.js?v=2';
// The dashboard and the printable master use one destination catalog.
export const freeDefinitions = [
['justworks', 'Just Works page', 'Your public merchant page', 'JW'],
['tip', 'Tip', 'Bitcoin tips and community wall', '⚡'],
['nsite', 'nsite', 'Your site on Nostr', 'NS'],
['nostr', 'Nostr profile', 'Your signed identity', 'NP'],
['maps', 'Maps', 'Find your place on the map', '⌖'],
['gallery', 'Gallery', 'Photos and discovery', '□'],
];
export const businessDefinitions = [
['pos', 'POS', 'Run orders and payments', 'Counter view', '↗', false],
['order', 'Order', 'Order to table', 'Customer', '+', true],
['pay', 'Pay Bill', 'Settle an open order', 'Customer', '€', true],
['payandgo', 'Just Pay', 'Pay a paper receipt', 'Customer', '₿', true],
['booking', 'Bookings', 'Tables now or later', 'Customer', '⌁', true, 'book'],
['screen', 'Screen', 'Merchant media display', '4K display', '▣', true],
['stats', 'Stats', 'Audience, actions and revenue', 'Merchant view', '↗', true, 'business'],
['events', 'Events', 'Merchant Nostr events', 'Coming soon', '◌', true],
];
export function businessUrl(npub, sheet = false) {
const path = sheet ? '/qr-sheet' : prod ? '/' : '/dashboard';
return `${prod ? 'https://business.justworks.cash' : location.origin + base}${path}?npub=${encodeURIComponent(npub)}`;
}
export function moduleDestination(definition, data, npub) {
const [id, , , , , configurable, target = id] = definition;
const state = data.modules?.[id] || {};
const paymentSetup = ['pay', 'payandgo'].includes(id) && !data.payment_ready;
const disabled = id === 'events' || state.status === 'coming-soon' || paymentSetup;
const url = paymentSetup
? `${base}/profile?npub=${encodeURIComponent(npub)}#lightning`
: id === 'stats'
? `${prod ? 'https://business.justworks.cash' : base}/stats?npub=${encodeURIComponent(npub)}`
: prod ? `https://${target}.justworks.cash/?npub=${encodeURIComponent(npub)}` : link(target);
return {state, paymentSetup, disabled, url,
qrUrl: disabled ? '' : moduleQrUrl(url, npub),
available: !disabled && (!configurable || !!state.enabled)};
}
export function sheetDestinations(data, npub) {
return [
{id: 'business', title: 'Business dashboard', url: businessUrl(npub)},
...freeDefinitions.filter(([id]) => data.links?.[id] && data.links[id] !== '#')
.map(([id, title]) => ({id, title, url: data.links[id]})),
...businessDefinitions.flatMap(definition => {
const destination = moduleDestination(definition, data, npub);
return destination.available ? [{id: definition[0], title: definition[1], url: destination.qrUrl}] : [];
}),
];
}
// Verify the Bech32 checksum and the 32-byte public-key payload, without a CDN.
export function validNpub(value) {
if (!/^npub1[023456789acdefghjklmnpqrstuvwxyz]{58}$/.test(value || '')) return false;
const alphabet = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
const words = [...value.slice(5)].map(char => alphabet.indexOf(char));
let checksum = 1;
const expanded = [...'npub'].map(char => char.charCodeAt(0) >> 5)
.concat(0, [...'npub'].map(char => char.charCodeAt(0) & 31), words);
const generators = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
for (const word of expanded) {
const top = checksum >>> 25;
checksum = ((checksum & 0x1ffffff) << 5) ^ word;
for (let bit = 0; bit < 5; bit++) if ((top >>> bit) & 1) checksum ^= generators[bit];
}
return checksum === 1 && (words[51] & 15) === 0;
}