releasebird-javascript-sdk 1.0.90 → 1.0.92

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.
@@ -0,0 +1,251 @@
1
+ import RbirdSessionManager from './RbirdSessionManager';
2
+
3
+ // CONTENT_URL is defined globally via webpack.DefinePlugin
4
+ /* global CONTENT_URL */
5
+
6
+ export class RbirdBookingManager {
7
+ static instance;
8
+
9
+ constructor() {
10
+ this.apiKey = null;
11
+ this.isOpen = false;
12
+ }
13
+
14
+ static getInstance() {
15
+ if (!RbirdBookingManager.instance) {
16
+ RbirdBookingManager.instance = new RbirdBookingManager();
17
+ }
18
+ return RbirdBookingManager.instance;
19
+ }
20
+
21
+ init(apiKey) {
22
+ if (typeof window === 'undefined') return;
23
+ this.apiKey = apiKey;
24
+ this.injectStyles();
25
+ }
26
+
27
+ /**
28
+ * Show the booking modal
29
+ * @param {Object} options - Optional configuration
30
+ * @param {Function} options.onSuccess - Callback when booking is completed
31
+ * @param {Function} options.onClose - Callback when modal is closed
32
+ */
33
+ showBooking(options = {}) {
34
+ if (typeof window === 'undefined') return;
35
+ if (!this.apiKey) {
36
+ console.error('[RbirdBookingManager] SDK not initialized. Call Rbird.initialize() first.');
37
+ return;
38
+ }
39
+ if (this.isOpen) {
40
+ console.warn('[RbirdBookingManager] Booking modal is already open.');
41
+ return;
42
+ }
43
+
44
+ const sessionManager = RbirdSessionManager.getInstance();
45
+ const state = sessionManager.getState();
46
+
47
+ // Build iframe URL
48
+ let iframeUrl = `${CONTENT_URL}/widget?apiKey=${this.apiKey}&view=BOOKING`;
49
+
50
+ if (state?.identify?.people) {
51
+ iframeUrl += `&people=${state.identify.people}`;
52
+ }
53
+ if (state?.identify?.hash) {
54
+ iframeUrl += `&hash=${state.identify.hash}`;
55
+ }
56
+ if (sessionManager.anonymousIdentifier) {
57
+ iframeUrl += `&ai=${sessionManager.anonymousIdentifier}`;
58
+ }
59
+
60
+ this.createModal(iframeUrl, options);
61
+ this.isOpen = true;
62
+ }
63
+
64
+ createModal(iframeUrl, options) {
65
+ // Create overlay
66
+ const overlay = document.createElement('div');
67
+ overlay.className = 'rbird-booking-overlay';
68
+ overlay.id = 'rbird-booking-overlay';
69
+
70
+ // Create modal container
71
+ const modal = document.createElement('div');
72
+ modal.className = 'rbird-booking-modal';
73
+ modal.id = 'rbird-booking-modal';
74
+
75
+ // Create close button
76
+ const closeButton = document.createElement('button');
77
+ closeButton.className = 'rbird-booking-close';
78
+ closeButton.innerHTML = '×';
79
+ closeButton.onclick = () => this.closeBooking(options.onClose);
80
+
81
+ // Create iframe
82
+ const iframe = document.createElement('iframe');
83
+ iframe.className = 'rbird-booking-iframe';
84
+ iframe.src = iframeUrl;
85
+ iframe.id = 'rbird-booking-iframe';
86
+ iframe.allow = 'clipboard-write';
87
+
88
+ modal.appendChild(closeButton);
89
+ modal.appendChild(iframe);
90
+ overlay.appendChild(modal);
91
+
92
+ // Close on overlay click
93
+ overlay.addEventListener('click', (e) => {
94
+ if (e.target === overlay) {
95
+ this.closeBooking(options.onClose);
96
+ }
97
+ });
98
+
99
+ // Handle messages from iframe
100
+ this.messageHandler = (e) => {
101
+ if (e.data === 'close' || e.data === 'closeWidget') {
102
+ this.closeBooking(options.onClose);
103
+ }
104
+ if (e.data === 'bookingSuccess') {
105
+ if (options.onSuccess) {
106
+ options.onSuccess();
107
+ }
108
+ this.closeBooking(options.onClose);
109
+ }
110
+ };
111
+ window.addEventListener('message', this.messageHandler);
112
+
113
+ // Handle escape key
114
+ this.keyHandler = (e) => {
115
+ if (e.key === 'Escape') {
116
+ this.closeBooking(options.onClose);
117
+ }
118
+ };
119
+ window.addEventListener('keydown', this.keyHandler);
120
+
121
+ document.body.appendChild(overlay);
122
+
123
+ // Animate in
124
+ requestAnimationFrame(() => {
125
+ overlay.classList.add('rbird-booking-overlay-visible');
126
+ });
127
+ }
128
+
129
+ closeBooking(onClose) {
130
+ const overlay = document.getElementById('rbird-booking-overlay');
131
+ if (overlay) {
132
+ overlay.classList.remove('rbird-booking-overlay-visible');
133
+ setTimeout(() => {
134
+ overlay.remove();
135
+ }, 300);
136
+ }
137
+
138
+ // Clean up event listeners
139
+ if (this.messageHandler) {
140
+ window.removeEventListener('message', this.messageHandler);
141
+ }
142
+ if (this.keyHandler) {
143
+ window.removeEventListener('keydown', this.keyHandler);
144
+ }
145
+
146
+ this.isOpen = false;
147
+
148
+ if (onClose) {
149
+ onClose();
150
+ }
151
+ }
152
+
153
+ injectStyles() {
154
+ if (typeof window === 'undefined' || document.getElementById('rbird-booking-styles')) return;
155
+
156
+ const style = document.createElement('style');
157
+ style.id = 'rbird-booking-styles';
158
+ style.textContent = `
159
+ .rbird-booking-overlay {
160
+ position: fixed !important;
161
+ top: 0 !important;
162
+ left: 0 !important;
163
+ right: 0 !important;
164
+ bottom: 0 !important;
165
+ background-color: rgba(0, 0, 0, 0) !important;
166
+ display: flex !important;
167
+ align-items: center !important;
168
+ justify-content: center !important;
169
+ z-index: 10001 !important;
170
+ padding: 20px !important;
171
+ opacity: 0;
172
+ transition: background-color 0.3s, opacity 0.3s;
173
+ box-sizing: border-box !important;
174
+ }
175
+
176
+ .rbird-booking-overlay-visible {
177
+ background-color: rgba(0, 0, 0, 0.5) !important;
178
+ opacity: 1 !important;
179
+ }
180
+
181
+ .rbird-booking-modal {
182
+ position: relative !important;
183
+ background: #ffffff !important;
184
+ border-radius: 16px !important;
185
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important;
186
+ width: 100% !important;
187
+ max-width: 420px !important;
188
+ height: 80vh !important;
189
+ max-height: 700px !important;
190
+ overflow: hidden !important;
191
+ animation: rbirdBookingSlideIn 0.3s ease-out;
192
+ }
193
+
194
+ .rbird-booking-close {
195
+ position: absolute !important;
196
+ top: 8px !important;
197
+ right: 8px !important;
198
+ background: rgba(0, 0, 0, 0.1) !important;
199
+ border: none !important;
200
+ width: 32px !important;
201
+ height: 32px !important;
202
+ border-radius: 50% !important;
203
+ font-size: 20px !important;
204
+ line-height: 1 !important;
205
+ cursor: pointer !important;
206
+ color: #374151 !important;
207
+ display: flex !important;
208
+ align-items: center !important;
209
+ justify-content: center !important;
210
+ transition: background-color 0.2s, color 0.2s !important;
211
+ z-index: 10 !important;
212
+ }
213
+
214
+ .rbird-booking-close:hover {
215
+ background: rgba(0, 0, 0, 0.2) !important;
216
+ color: #1f2937 !important;
217
+ }
218
+
219
+ .rbird-booking-iframe {
220
+ width: 100% !important;
221
+ height: 100% !important;
222
+ border: none !important;
223
+ }
224
+
225
+ @keyframes rbirdBookingSlideIn {
226
+ from {
227
+ opacity: 0;
228
+ transform: translateY(-20px) scale(0.95);
229
+ }
230
+ to {
231
+ opacity: 1;
232
+ transform: translateY(0) scale(1);
233
+ }
234
+ }
235
+
236
+ @media (max-width: 480px) {
237
+ .rbird-booking-overlay {
238
+ padding: 0 !important;
239
+ }
240
+
241
+ .rbird-booking-modal {
242
+ max-width: 100% !important;
243
+ height: 100% !important;
244
+ max-height: 100% !important;
245
+ border-radius: 0 !important;
246
+ }
247
+ }
248
+ `;
249
+ document.head.appendChild(style);
250
+ }
251
+ }
@@ -1014,11 +1014,7 @@ export default class RbirdWebsiteWidget {
1014
1014
  this.hideWidgetButton.style.bottom = `${window.innerHeight - buttonRect.bottom + 55}px`;
1015
1015
  }
1016
1016
 
1017
- // Only update badge and bubbles if we have a custom position
1018
- const savedPosition = this.loadWidgetPosition();
1019
- if (!savedPosition) return;
1020
-
1021
- // Update badge position
1017
+ // Always update badge position based on current button position
1022
1018
  if (this.countBadge) {
1023
1019
  this.countBadge.style.left = `${buttonRect.right - 10}px`;
1024
1020
  this.countBadge.style.right = 'unset';
package/src/index.js CHANGED
@@ -6,6 +6,7 @@ import { RbirdBannerManager } from "./RbirdBannerManager";
6
6
  import { RbirdFormManager } from "./RbirdFormManager";
7
7
  import { RbirdSurveyManager } from "./RbirdSurveyManager";
8
8
  import { RbirdAutomationManager } from "./RbirdAutomationManager";
9
+ import { RbirdBookingManager } from "./RbirdBookingManager";
9
10
 
10
11
  class Rbird {
11
12
 
@@ -104,6 +105,10 @@ class Rbird {
104
105
  const automationManager = RbirdAutomationManager.getInstance();
105
106
  automationManager.init(apiKey);
106
107
 
108
+ // Initialize booking manager
109
+ const bookingManager = RbirdBookingManager.getInstance();
110
+ bookingManager.init(apiKey);
111
+
107
112
  resolve();
108
113
  });
109
114
  });
@@ -203,6 +208,21 @@ class Rbird {
203
208
  }
204
209
  }
205
210
 
211
+ /**
212
+ * Show the booking modal
213
+ * @param {Object} options - Optional configuration
214
+ * @param {Function} options.onSuccess - Callback when booking is completed
215
+ * @param {Function} options.onClose - Callback when modal is closed
216
+ */
217
+ static showBooking(options = {}) {
218
+ if (typeof window === 'undefined') return;
219
+ try {
220
+ RbirdBookingManager.getInstance().showBooking(options);
221
+ } catch (e) {
222
+ console.error(e);
223
+ }
224
+ }
225
+
206
226
  }
207
227
 
208
228
  export const runFunctionWhenDomIsReady = (callback) => {