From 121976b3dbb654ed6ce97c9a7c669b62dfbc9f85 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Thu, 9 Jul 2026 23:45:33 +0000 Subject: [PATCH] =?UTF-8?q?Fix=20Plotly=20=C2=A3=20format=20warning=20and?= =?UTF-8?q?=20add=20scraper=20backend=20selector=20to=20Settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MarketView: split tickformat '£,.0f' into tickprefix+'£' + tickformat ',.0f' (Plotly d3 format doesn't accept £ prefix inline) - Settings System tab: add editable dropdown for booking_scraper_backend (hotel page vs search results) with description of the tradeoff; backend was previously read-only in the table Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/pages/MarketView.tsx | 2 +- frontend/src/pages/Settings.tsx | 43 ++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/MarketView.tsx b/frontend/src/pages/MarketView.tsx index 8713c93..5fff104 100644 --- a/frontend/src/pages/MarketView.tsx +++ b/frontend/src/pages/MarketView.tsx @@ -1252,7 +1252,7 @@ const RateHistoryModalComponent: React.FC<{ modal: RateHistoryModal; onClose: () height: 300, legend: { orientation: 'h', y: -0.25 }, xaxis: { title: { text: '' }, tickformat: '%d %b %H:%M', type: 'date' }, - yaxis: { title: { text: 'Rate (£)' }, tickformat: '£,.0f' }, + yaxis: { title: { text: 'Rate (£)' }, tickprefix: '£', tickformat: ',.0f' }, plot_bgcolor: 'var(--body-bg)', paper_bgcolor: 'var(--card-bg)', font: { family: 'inherit', size: 11, color: 'var(--text-dark)' }, diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index c27cecb..593264a 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -798,13 +798,22 @@ function RoomCategoriesCard() { // ─── System Tab ─────────────────────────────────────────────────────────────── function SystemTab({ config, isLoading }: { config: SystemConfig | undefined; isLoading: boolean }) { + const qc = useQueryClient() + + const saveMutation = useMutation({ + mutationFn: (payload: { key: string; value: string }) => + api.post('/competitors/config/system', payload), + onSuccess: () => qc.invalidateQueries({ queryKey: ['system-config'] }), + }) + if (isLoading) { return
Loading…
} + const backend = config?.['booking_scraper_backend'] ?? 'playwright_local' + const displayKeys = [ 'booking_scraper_enabled', - 'booking_scraper_backend', 'booking_scraper_daily_time', 'booking_proxy_enabled', 'booking_proxy_host', @@ -815,7 +824,33 @@ function SystemTab({ config, isLoading }: { config: SystemConfig | undefined; is ] return ( -
+
+
+
Scraper Backend
+
+

+ Controls how Booking.com rates are fetched. Hotel page scrapes each + competitor's own property page — captures all room types and rate plan variants (meal + plan, cancellation policy, availability). Search results scrapes the + location search page — faster but only returns the single best-available rate per hotel + with no room-type breakdown. +

+
+ + {saveMutation.isPending && Saving…} + {saveMutation.isSuccess && ✓ Saved} +
+
+
+
System Configuration
@@ -836,13 +871,13 @@ function SystemTab({ config, isLoading }: { config: SystemConfig | undefined; is - ))} + ))}
-
+
To configure the Booking.com scraper location and hotel tiers, use the Settings tab inside{' '} Market View.