import {frame} from './ds/frame.js'; import {npubFrom} from './ds/env.js'; const app=document.querySelector('#app'),npub=npubFrom();let merchant,mode='now',delay=0,guests=2,busy=false; const esc=value=>String(value??'').replace(/[&<>"']/g,char=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char])); function timeValue(offsetMinutes){const date=new Date(Date.now()+offsetMinutes*60000);date.setMinutes(Math.ceil(date.getMinutes()/30)*30,0,0);return `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2,'0')}-${String(date.getDate()).padStart(2,'0')}T${String(date.getHours()).padStart(2,'0')}:${String(date.getMinutes()).padStart(2,'0')}`} function error(message){app.innerHTML=`
⌁

Table booking

${esc(message)}

Use book.justworks.cash/?npub=npub1…
`} function render(data){merchant=data.merchant;document.title=`Book ${merchant.name} · Just Works`;frame(app,{label:'Bookings',surface:'book',html:`

Reserve a table

When should we expect you?

Your table at ${esc(merchant.name)}, without the phone call.

⌁
${esc(merchant.name)}Taking bookings
${[['now','Soon'],['later','Later']].map(([value,label])=>``).join('')}

No account · no app · sent directly to ${esc(merchant.name)}

`});document.querySelectorAll('[data-mode]').forEach(button=>button.onclick=()=>setMode(button.dataset.mode));document.querySelector('#less').onclick=()=>setGuests(guests-1);document.querySelector('#more').onclick=()=>setGuests(guests+1);document.querySelector('#form').onsubmit=submit;renderWhen()} function setMode(next){mode=next;document.querySelectorAll('[data-mode]').forEach(button=>button.classList.toggle('active',button.dataset.mode===mode));renderWhen()} function setGuests(next){guests=Math.max(1,Math.min(20,next));document.querySelector('#guestCount').textContent=guests} function renderWhen(){const host=document.querySelector('#when');if(mode==='now'){host.innerHTML=``;host.querySelectorAll('[data-delay]').forEach(button=>button.onclick=()=>{delay=Number(button.dataset.delay);renderWhen()})}else host.innerHTML=``} async function submit(event){event.preventDefault();if(busy)return;busy=true;const button=document.querySelector('#submit');button.disabled=true;button.firstChild.textContent='Sending… ';try{const scheduled=mode==='now'?new Date(Date.now()+delay*60000):new Date(document.querySelector('#date').value);const response=await fetch('/api/bookings',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({npub,name:document.querySelector('#name').value,notes:document.querySelector('#notes').value,guests,mode,scheduled_at:scheduled.toISOString()})});const result=await response.json();if(!response.ok)throw new Error(result.error||'Could not book');confirm(result)}catch(error){button.disabled=false;button.firstChild.textContent='Try again ';alert(error.message)}finally{busy=false}} function confirm(result){const date=new Date(result.scheduled_at);frame(app,{label:'Bookings',surface:'book',html:`
✓

Request sent

Table for ${result.guests} requested.

${esc(merchant.name)} received your booking for ${date.toLocaleDateString([],{weekday:'long',day:'numeric',month:'long'})} at ${date.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'})}.

The merchant still needs to confirm it. Keep this screen open for your reference.
`})} if(!npub)error('Add the merchant npub to book.');else fetch(`/api/order-merchant?npub=${encodeURIComponent(npub)}`,{cache:'no-store'}).then(async response=>{const data=await response.json();if(!response.ok)throw new Error(data.error);render(data)}).catch(reason=>error(reason.message||'Merchant unavailable'));