Files
archy/docker/justworks/business/public/assets/business-destinations.js
T

73 lines
3.6 KiB
JavaScript
Raw Normal View History

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;
}