Fix NewBook write mechanism, bundle push extension, remove vestigial hotel_id
- setBookingCustomFields: use bookings_update's own custom_fields array (confirmed from the real legacy plugin code) instead of instance_custom_fields_set, which was only ever proven for a different, unrelated plugin - online_checkin_complete is now a configurable per-hotel custom field (online_checkin_complete_custom_field_id setting), not a bogus top-level bookings_update field NewBook would silently ignore - Fix field-name mismatches vs a real live NewBook booking response: booking_arrival/departure/length, guest address (street/city/state/ postcode/country, not a single field), phone/mobile (in contact_details, not top-level), and pickPrimaryGuest now checks primary_client (was checking fields that don't exist in the real API) - Bundle the standalone push extension into backend/extension-src/, add GET /api/extension/download (zips on request via archiver) and a download button on the Settings page - Remove newbook_hotel_id — vestigial from the legacy system's multi-hotel routing model, never actually reached NewBook's API, this stack is single-hotel-per-deployment so there's nothing to route between Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
3b2e25df3f
commit
4d3774ef0d
25 changed files with 3557 additions and 15 deletions
|
|
@ -54,6 +54,11 @@ export function deleteTerminal(id: string): Promise<{ ok: boolean }> {
|
|||
export function fetchCheckins(limit = 100): Promise<Checkin[]> { return request(`/checkins?limit=${limit}`) }
|
||||
export function checkinPdfUrl(id: number): string { return `${BASE}/checkins/${id}/pdf` }
|
||||
|
||||
// Standalone push extension — bundled into this app at build time (see
|
||||
// backend/extension-src), zipped fresh on each request rather than served as
|
||||
// a static file. See project_checkin memory's "Standalone push extension".
|
||||
export function extensionDownloadUrl(): string { return `${BASE}/extension/download` }
|
||||
|
||||
// Marketing
|
||||
export function fetchMarketingProviders(): Promise<MarketingProvider[]> { return request('/marketing/providers') }
|
||||
export function updateMarketingProvider(provider: string, body: { active: boolean; config: Record<string, string> }): Promise<MarketingProvider> {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { MonitorCog } from 'lucide-react'
|
||||
import { MonitorCog, Download } from 'lucide-react'
|
||||
import {
|
||||
fetchSettings, updateSettings, testNewbookConnection,
|
||||
fetchKioskPasswordStatus, setKioskPassword,
|
||||
fetchKioskPasswordStatus, setKioskPassword, extensionDownloadUrl,
|
||||
} from '../api'
|
||||
import type { AppSettings } from '../types'
|
||||
|
||||
export default function Settings() {
|
||||
const [settings, setSettings] = useState<AppSettings>({
|
||||
newbook_hotel_id: '', regcard_custom_field_id: '',
|
||||
regcard_custom_field_id: '',
|
||||
online_checkin_complete_custom_field_id: '', terms_and_conditions_text: '',
|
||||
})
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
|
@ -76,13 +76,6 @@ export default function Settings() {
|
|||
|
||||
<div className="section-title">NewBook Integration</div>
|
||||
<div className="field-row">
|
||||
<div className="field">
|
||||
<label>NewBook Hotel / Location ID</label>
|
||||
<input
|
||||
type="text" value={settings.newbook_hotel_id}
|
||||
onChange={e => setSettings(s => ({ ...s, newbook_hotel_id: e.target.value }))}
|
||||
/>
|
||||
</div>
|
||||
<div className="field">
|
||||
<label>Regcard PDF Link — Custom Field ID</label>
|
||||
<input
|
||||
|
|
@ -127,6 +120,20 @@ export default function Settings() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div className="section-title">Push Extension</div>
|
||||
<p className="field-hint" style={{ marginBottom: 10 }}>
|
||||
Standalone Chrome extension — adds a "Send to Check-In Tablet" button when a NewBook booking
|
||||
is open. Not published anywhere yet, so it needs installing manually on each reception PC:
|
||||
download, unzip, then <code>chrome://extensions</code> → enable Developer mode → Load
|
||||
unpacked → select the unzipped folder. It'll need a Terminal API key from the Terminals page
|
||||
to actually authorize pushes — create one there first.
|
||||
</p>
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<a className="btn" href={extensionDownloadUrl()} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, textDecoration: 'none' }}>
|
||||
<Download size={16} strokeWidth={1.75} /> Download Extension (.zip)
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="section-title">Kiosk Tablets</div>
|
||||
<p className="field-hint" style={{ marginBottom: 10 }}>
|
||||
A shared password every check-in tablet uses to set itself up at <code>/tablet-checkin/kiosk</code> —
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ export interface MarketingSyncRow {
|
|||
}
|
||||
|
||||
export interface AppSettings {
|
||||
newbook_hotel_id: string
|
||||
regcard_custom_field_id: string
|
||||
online_checkin_complete_custom_field_id: string
|
||||
terms_and_conditions_text: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue