@nuitee/booking-widget 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1189,18 +1189,21 @@ if (typeof window !== 'undefined') {
1189
1189
  _fetchRuntimeConfig() {
1190
1190
  const self = this;
1191
1191
  const key = String(this.options.propertyKey).trim();
1192
+ const isSandbox = this.options.mode === 'sandbox';
1193
+ // Cache key is mode-aware so sandbox and live configs are stored separately.
1194
+ const cacheKey = isSandbox ? key + ':sandbox' : key;
1192
1195
 
1193
- if (__bwConfigCache[key]) {
1194
- this._applyApiColors(__bwConfigCache[key]);
1196
+ if (__bwConfigCache[cacheKey]) {
1197
+ this._applyApiColors(__bwConfigCache[cacheKey]);
1195
1198
  this._configState = 'loaded';
1196
1199
  this.applyColors();
1197
- return Promise.resolve(__bwConfigCache[key]);
1200
+ return Promise.resolve(__bwConfigCache[cacheKey]);
1198
1201
  }
1199
1202
 
1200
1203
  this._configState = 'loading';
1201
1204
  this.render();
1202
1205
 
1203
- const url = 'https://ai.thehotelplanet.com/load-config?apikey=' + encodeURIComponent(key) + '&mode=sandbox';
1206
+ const url = 'https://ai.thehotelplanet.com/load-config?apikey=' + encodeURIComponent(key) + (isSandbox ? '&mode=sandbox' : '');
1204
1207
  this._configPromise = fetch(url)
1205
1208
  .then(function (res) {
1206
1209
  if (!res.ok) throw new Error('Failed to load widget configuration (HTTP ' + res.status + ').');
@@ -1213,7 +1216,7 @@ if (typeof window !== 'undefined') {
1213
1216
  if (data.primaryColor) apiColors.primary = data.primaryColor;
1214
1217
  if (data.buttonTextColor) apiColors.primaryText = data.buttonTextColor;
1215
1218
  if (data.widgetCardColor) apiColors.card = data.widgetCardColor;
1216
- __bwConfigCache[key] = apiColors;
1219
+ __bwConfigCache[cacheKey] = apiColors;
1217
1220
  self._applyApiColors(apiColors);
1218
1221
  self._configState = 'loaded';
1219
1222
  self.applyColors();
@@ -81,6 +81,7 @@
81
81
  --bg: hsl(30, 10%, 8%);
82
82
  --fg: hsl(40, 20%, 90%);
83
83
  --card: hsl(30, 8%, 12%);
84
+ --card-solid: hsl(30, 8%, 12%);
84
85
  --card-fg: hsl(40, 20%, 90%);
85
86
  --primary: hsl(38, 60%, 55%);
86
87
  --primary-fg: hsl(30, 10%, 8%);
@@ -611,7 +612,7 @@
611
612
  max-width: calc(100vw - 2em);
612
613
  box-sizing: border-box;
613
614
  z-index: 10;
614
- background: var(--card-solid, var(--card));
615
+ background: var(--card-solid);
615
616
  border: 1px solid var(--border);
616
617
  border-radius: var(--radius);
617
618
  padding: 1em;
@@ -467,18 +467,21 @@ class BookingWidget {
467
467
  const self = this;
468
468
  const propertyKey = this.options.propertyKey;
469
469
  const key = String(propertyKey).trim();
470
+ const isSandbox = this.options.mode === 'sandbox';
471
+ // Cache key is mode-aware so sandbox and live configs are stored separately.
472
+ const cacheKey = isSandbox ? key + ':sandbox' : key;
470
473
 
471
- if (__bwConfigCache[key]) {
472
- this._applyApiColors(__bwConfigCache[key]);
474
+ if (__bwConfigCache[cacheKey]) {
475
+ this._applyApiColors(__bwConfigCache[cacheKey]);
473
476
  this._configState = 'loaded';
474
477
  this.applyColors();
475
- return Promise.resolve(__bwConfigCache[key]);
478
+ return Promise.resolve(__bwConfigCache[cacheKey]);
476
479
  }
477
480
 
478
481
  this._configState = 'loading';
479
482
  this.render();
480
483
 
481
- const url = 'https://ai.thehotelplanet.com/load-config?apikey=' + encodeURIComponent(key) + '&mode=sandbox';
484
+ const url = 'https://ai.thehotelplanet.com/load-config?apikey=' + encodeURIComponent(key) + (isSandbox ? '&mode=sandbox' : '');
482
485
  this._configPromise = fetch(url)
483
486
  .then(function (res) {
484
487
  if (!res.ok) throw new Error('Failed to load widget configuration (HTTP ' + res.status + ').');
@@ -491,7 +494,7 @@ class BookingWidget {
491
494
  if (data.primaryColor) apiColors.primary = data.primaryColor;
492
495
  if (data.buttonTextColor) apiColors.primaryText = data.buttonTextColor;
493
496
  if (data.widgetCardColor) apiColors.card = data.widgetCardColor;
494
- __bwConfigCache[key] = apiColors;
497
+ __bwConfigCache[cacheKey] = apiColors;
495
498
  self._applyApiColors(apiColors);
496
499
  self._configState = 'loaded';
497
500
  self.applyColors();
@@ -81,6 +81,7 @@
81
81
  --bg: hsl(30, 10%, 8%);
82
82
  --fg: hsl(40, 20%, 90%);
83
83
  --card: hsl(30, 8%, 12%);
84
+ --card-solid: hsl(30, 8%, 12%);
84
85
  --card-fg: hsl(40, 20%, 90%);
85
86
  --primary: hsl(38, 60%, 55%);
86
87
  --primary-fg: hsl(30, 10%, 8%);
@@ -611,7 +612,7 @@
611
612
  max-width: calc(100vw - 2em);
612
613
  box-sizing: border-box;
613
614
  z-index: 10;
614
- background: var(--card-solid, var(--card));
615
+ background: var(--card-solid);
615
616
  border: 1px solid var(--border);
616
617
  border-radius: var(--radius);
617
618
  padding: 1em;
@@ -240,7 +240,7 @@ const BookingWidget = ({
240
240
  setConfigLoading(true);
241
241
  setConfigError(null);
242
242
  setConfigLoaded(false);
243
- fetchRuntimeConfig(propertyKey, colors)
243
+ fetchRuntimeConfig(propertyKey, colors, mode)
244
244
  .then(({ widgetStyles }) => {
245
245
  if (cancelled) return;
246
246
  setRuntimeWidgetStyles(widgetStyles);
@@ -253,7 +253,7 @@ const BookingWidget = ({
253
253
  setConfigLoading(false);
254
254
  });
255
255
  return () => { cancelled = true; };
256
- }, [propertyKey, colors, configRetryCount]);
256
+ }, [propertyKey, colors, mode, configRetryCount]);
257
257
 
258
258
  // Apply resolved CSS custom properties to the widget element.
259
259
  useEffect(() => {
@@ -81,6 +81,7 @@
81
81
  --bg: hsl(30, 10%, 8%);
82
82
  --fg: hsl(40, 20%, 90%);
83
83
  --card: hsl(30, 8%, 12%);
84
+ --card-solid: hsl(30, 8%, 12%);
84
85
  --card-fg: hsl(40, 20%, 90%);
85
86
  --primary: hsl(38, 60%, 55%);
86
87
  --primary-fg: hsl(30, 10%, 8%);
@@ -611,7 +612,7 @@
611
612
  max-width: calc(100vw - 2em);
612
613
  box-sizing: border-box;
613
614
  z-index: 10;
614
- background: var(--card-solid, var(--card));
615
+ background: var(--card-solid);
615
616
  border: 1px solid var(--border);
616
617
  border-radius: var(--radius);
617
618
  padding: 1em;
@@ -64,27 +64,31 @@ export function mergeColors(mappedApiColors, installerColors) {
64
64
  * - Throws synchronously (or rejects) when propertyKey is null, undefined, or
65
65
  * an empty string. Callers must catch this and render a "Missing Configuration"
66
66
  * error state rather than attempting to render the normal widget UI.
67
- * - Caches the raw API color payload by propertyKey. Subsequent calls for the
68
- * same key re-use the cache and only re-merge installer overrides.
67
+ * - Caches the raw API color payload by propertyKey + mode. Subsequent calls for
68
+ * the same key+mode re-use the cache and only re-merge installer overrides.
69
69
  *
70
- * @param {string} propertyKey - The hotel property key / API key.
71
- * @param {object|null} installerColors - Optional installer color overrides.
70
+ * @param {string} propertyKey - The hotel property key / API key.
71
+ * @param {object|null} installerColors - Optional installer color overrides.
72
+ * @param {string} [mode] - Pass 'sandbox' to append &mode=sandbox to the request.
72
73
  * @returns {Promise<{ apiColors: object, colors: object, widgetStyles: object }>}
73
74
  */
74
- export async function fetchRuntimeConfig(propertyKey, installerColors = null) {
75
+ export async function fetchRuntimeConfig(propertyKey, installerColors = null, mode = null) {
75
76
  if (!propertyKey || !String(propertyKey).trim()) {
76
77
  throw new Error('propertyKey is required to initialize the booking widget.');
77
78
  }
78
79
 
79
80
  const key = String(propertyKey).trim();
81
+ const isSandbox = mode === 'sandbox';
82
+ // Cache separately for sandbox vs live so switching modes gets a fresh fetch.
83
+ const cacheKey = isSandbox ? `${key}:sandbox` : key;
80
84
 
81
- if (_configCache.has(key)) {
82
- const apiColors = _configCache.get(key);
85
+ if (_configCache.has(cacheKey)) {
86
+ const apiColors = _configCache.get(cacheKey);
83
87
  const colors = mergeColors(apiColors, installerColors);
84
88
  return { apiColors, colors, widgetStyles: deriveWidgetStyles(colors) };
85
89
  }
86
90
 
87
- const url = `${CONFIG_BASE_URL}?apikey=${encodeURIComponent(key)}&mode=sandbox`;
91
+ const url = `${CONFIG_BASE_URL}?apikey=${encodeURIComponent(key)}${isSandbox ? '&mode=sandbox' : ''}`;
88
92
  const res = await fetch(url);
89
93
  if (!res.ok) {
90
94
  throw new Error(`Failed to load widget configuration (HTTP ${res.status}).`);
@@ -92,7 +96,7 @@ export async function fetchRuntimeConfig(propertyKey, installerColors = null) {
92
96
 
93
97
  const data = await res.json();
94
98
  const apiColors = mapApiColors(data);
95
- _configCache.set(key, apiColors);
99
+ _configCache.set(cacheKey, apiColors);
96
100
 
97
101
  const colors = mergeColors(apiColors, installerColors);
98
102
  return { apiColors, colors, widgetStyles: deriveWidgetStyles(colors) };
@@ -730,6 +730,9 @@ export default {
730
730
  propertyKey() {
731
731
  this._initRuntimeConfig();
732
732
  },
733
+ mode() {
734
+ this._initRuntimeConfig();
735
+ },
733
736
  colors: {
734
737
  deep: true,
735
738
  handler() { this._initRuntimeConfig(); },
@@ -779,7 +782,7 @@ export default {
779
782
  this.configError = null;
780
783
  this.configLoaded = false;
781
784
  try {
782
- const { widgetStyles } = await fetchRuntimeConfig(this.propertyKey, this.colors);
785
+ const { widgetStyles } = await fetchRuntimeConfig(this.propertyKey, this.colors, this.mode);
783
786
  this.runtimeWidgetStyles = widgetStyles;
784
787
  this.configLoaded = true;
785
788
  } catch (err) {
@@ -81,6 +81,7 @@
81
81
  --bg: hsl(30, 10%, 8%);
82
82
  --fg: hsl(40, 20%, 90%);
83
83
  --card: hsl(30, 8%, 12%);
84
+ --card-solid: hsl(30, 8%, 12%);
84
85
  --card-fg: hsl(40, 20%, 90%);
85
86
  --primary: hsl(38, 60%, 55%);
86
87
  --primary-fg: hsl(30, 10%, 8%);
@@ -611,7 +612,7 @@
611
612
  max-width: calc(100vw - 2em);
612
613
  box-sizing: border-box;
613
614
  z-index: 10;
614
- background: var(--card-solid, var(--card));
615
+ background: var(--card-solid);
615
616
  border: 1px solid var(--border);
616
617
  border-radius: var(--radius);
617
618
  padding: 1em;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuitee/booking-widget",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A beautiful, customizable booking widget modal that can be embedded in any website. Supports vanilla JavaScript, React, and Vue.js.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",