releasebird-javascript-sdk 1.0.91 → 1.0.93

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.
@@ -36,7 +36,10 @@ export class RbirdAutomationManager {
36
36
  // Register event handlers
37
37
  this.registerEventHandlers();
38
38
 
39
- // Start command polling
39
+ // Listen for WebSocket notifications from widget iframe
40
+ this.setupWebSocketListener();
41
+
42
+ // Start command polling (reduced frequency - WebSocket is primary)
40
43
  this.startCommandPolling();
41
44
 
42
45
  // Send first_seen event
@@ -47,6 +50,21 @@ export class RbirdAutomationManager {
47
50
  console.log('[Rbird] Automation manager initialized');
48
51
  }
49
52
 
53
+ /**
54
+ * Setup listener for WebSocket notifications from widget iframe.
55
+ * This allows instant command execution when the backend pushes a notification.
56
+ */
57
+ setupWebSocketListener() {
58
+ window.addEventListener('message', (event) => {
59
+ // Handle automation command notification from widget
60
+ if (event.data === 'automationCommand') {
61
+ console.log('[Rbird] Received WebSocket automation notification');
62
+ // Immediately fetch and execute pending commands
63
+ this.pollCommands();
64
+ }
65
+ });
66
+ }
67
+
50
68
  /**
51
69
  * Get or set the first_seen timestamp
52
70
  */
@@ -177,7 +195,9 @@ export class RbirdAutomationManager {
177
195
  }
178
196
 
179
197
  /**
180
- * Start polling for pending commands
198
+ * Start polling for pending commands.
199
+ * Polling is now a fallback mechanism - WebSocket is the primary delivery method.
200
+ * The interval is set to 60 seconds to catch any missed commands.
181
201
  */
182
202
  startCommandPolling() {
183
203
  if (this.pollingInterval) {
@@ -187,8 +207,8 @@ export class RbirdAutomationManager {
187
207
  // Poll immediately once
188
208
  this.pollCommands();
189
209
 
190
- // Then poll every 3 seconds
191
- this.pollingInterval = setInterval(() => this.pollCommands(), 3000);
210
+ // Poll every 60 seconds as fallback (WebSocket handles instant delivery)
211
+ this.pollingInterval = setInterval(() => this.pollCommands(), 60000);
192
212
  }
193
213
 
194
214
  /**
@@ -0,0 +1,255 @@
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 {string} options.appointmentTypeId - Pre-select a specific appointment type
31
+ * @param {Function} options.onSuccess - Callback when booking is completed
32
+ * @param {Function} options.onClose - Callback when modal is closed
33
+ */
34
+ showBooking(options = {}) {
35
+ if (typeof window === 'undefined') return;
36
+ if (!this.apiKey) {
37
+ console.error('[RbirdBookingManager] SDK not initialized. Call Rbird.initialize() first.');
38
+ return;
39
+ }
40
+ if (this.isOpen) {
41
+ console.warn('[RbirdBookingManager] Booking modal is already open.');
42
+ return;
43
+ }
44
+
45
+ const sessionManager = RbirdSessionManager.getInstance();
46
+ const state = sessionManager.getState();
47
+
48
+ // Build iframe URL
49
+ let iframeUrl = `${CONTENT_URL}/widget?apiKey=${this.apiKey}&view=BOOKING`;
50
+
51
+ if (state?.identify?.people) {
52
+ iframeUrl += `&people=${state.identify.people}`;
53
+ }
54
+ if (state?.identify?.hash) {
55
+ iframeUrl += `&hash=${state.identify.hash}`;
56
+ }
57
+ if (sessionManager.anonymousIdentifier) {
58
+ iframeUrl += `&ai=${sessionManager.anonymousIdentifier}`;
59
+ }
60
+ if (options.appointmentTypeId) {
61
+ iframeUrl += `&appointmentTypeId=${encodeURIComponent(options.appointmentTypeId)}`;
62
+ }
63
+
64
+ this.createModal(iframeUrl, options);
65
+ this.isOpen = true;
66
+ }
67
+
68
+ createModal(iframeUrl, options) {
69
+ // Create overlay
70
+ const overlay = document.createElement('div');
71
+ overlay.className = 'rbird-booking-overlay';
72
+ overlay.id = 'rbird-booking-overlay';
73
+
74
+ // Create modal container
75
+ const modal = document.createElement('div');
76
+ modal.className = 'rbird-booking-modal';
77
+ modal.id = 'rbird-booking-modal';
78
+
79
+ // Create close button
80
+ const closeButton = document.createElement('button');
81
+ closeButton.className = 'rbird-booking-close';
82
+ closeButton.innerHTML = '×';
83
+ closeButton.onclick = () => this.closeBooking(options.onClose);
84
+
85
+ // Create iframe
86
+ const iframe = document.createElement('iframe');
87
+ iframe.className = 'rbird-booking-iframe';
88
+ iframe.src = iframeUrl;
89
+ iframe.id = 'rbird-booking-iframe';
90
+ iframe.allow = 'clipboard-write';
91
+
92
+ modal.appendChild(closeButton);
93
+ modal.appendChild(iframe);
94
+ overlay.appendChild(modal);
95
+
96
+ // Close on overlay click
97
+ overlay.addEventListener('click', (e) => {
98
+ if (e.target === overlay) {
99
+ this.closeBooking(options.onClose);
100
+ }
101
+ });
102
+
103
+ // Handle messages from iframe
104
+ this.messageHandler = (e) => {
105
+ if (e.data === 'close' || e.data === 'closeWidget') {
106
+ this.closeBooking(options.onClose);
107
+ }
108
+ if (e.data === 'bookingSuccess') {
109
+ if (options.onSuccess) {
110
+ options.onSuccess();
111
+ }
112
+ this.closeBooking(options.onClose);
113
+ }
114
+ };
115
+ window.addEventListener('message', this.messageHandler);
116
+
117
+ // Handle escape key
118
+ this.keyHandler = (e) => {
119
+ if (e.key === 'Escape') {
120
+ this.closeBooking(options.onClose);
121
+ }
122
+ };
123
+ window.addEventListener('keydown', this.keyHandler);
124
+
125
+ document.body.appendChild(overlay);
126
+
127
+ // Animate in
128
+ requestAnimationFrame(() => {
129
+ overlay.classList.add('rbird-booking-overlay-visible');
130
+ });
131
+ }
132
+
133
+ closeBooking(onClose) {
134
+ const overlay = document.getElementById('rbird-booking-overlay');
135
+ if (overlay) {
136
+ overlay.classList.remove('rbird-booking-overlay-visible');
137
+ setTimeout(() => {
138
+ overlay.remove();
139
+ }, 300);
140
+ }
141
+
142
+ // Clean up event listeners
143
+ if (this.messageHandler) {
144
+ window.removeEventListener('message', this.messageHandler);
145
+ }
146
+ if (this.keyHandler) {
147
+ window.removeEventListener('keydown', this.keyHandler);
148
+ }
149
+
150
+ this.isOpen = false;
151
+
152
+ if (onClose) {
153
+ onClose();
154
+ }
155
+ }
156
+
157
+ injectStyles() {
158
+ if (typeof window === 'undefined' || document.getElementById('rbird-booking-styles')) return;
159
+
160
+ const style = document.createElement('style');
161
+ style.id = 'rbird-booking-styles';
162
+ style.textContent = `
163
+ .rbird-booking-overlay {
164
+ position: fixed !important;
165
+ top: 0 !important;
166
+ left: 0 !important;
167
+ right: 0 !important;
168
+ bottom: 0 !important;
169
+ background-color: rgba(0, 0, 0, 0) !important;
170
+ display: flex !important;
171
+ align-items: center !important;
172
+ justify-content: center !important;
173
+ z-index: 10001 !important;
174
+ padding: 20px !important;
175
+ opacity: 0;
176
+ transition: background-color 0.3s, opacity 0.3s;
177
+ box-sizing: border-box !important;
178
+ }
179
+
180
+ .rbird-booking-overlay-visible {
181
+ background-color: rgba(0, 0, 0, 0.5) !important;
182
+ opacity: 1 !important;
183
+ }
184
+
185
+ .rbird-booking-modal {
186
+ position: relative !important;
187
+ background: #ffffff !important;
188
+ border-radius: 16px !important;
189
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important;
190
+ width: 100% !important;
191
+ max-width: 420px !important;
192
+ height: 80vh !important;
193
+ max-height: 700px !important;
194
+ overflow: hidden !important;
195
+ animation: rbirdBookingSlideIn 0.3s ease-out;
196
+ }
197
+
198
+ .rbird-booking-close {
199
+ position: absolute !important;
200
+ top: 8px !important;
201
+ right: 8px !important;
202
+ background: rgba(0, 0, 0, 0.1) !important;
203
+ border: none !important;
204
+ width: 32px !important;
205
+ height: 32px !important;
206
+ border-radius: 50% !important;
207
+ font-size: 20px !important;
208
+ line-height: 1 !important;
209
+ cursor: pointer !important;
210
+ color: #374151 !important;
211
+ display: flex !important;
212
+ align-items: center !important;
213
+ justify-content: center !important;
214
+ transition: background-color 0.2s, color 0.2s !important;
215
+ z-index: 10 !important;
216
+ }
217
+
218
+ .rbird-booking-close:hover {
219
+ background: rgba(0, 0, 0, 0.2) !important;
220
+ color: #1f2937 !important;
221
+ }
222
+
223
+ .rbird-booking-iframe {
224
+ width: 100% !important;
225
+ height: 100% !important;
226
+ border: none !important;
227
+ }
228
+
229
+ @keyframes rbirdBookingSlideIn {
230
+ from {
231
+ opacity: 0;
232
+ transform: translateY(-20px) scale(0.95);
233
+ }
234
+ to {
235
+ opacity: 1;
236
+ transform: translateY(0) scale(1);
237
+ }
238
+ }
239
+
240
+ @media (max-width: 480px) {
241
+ .rbird-booking-overlay {
242
+ padding: 0 !important;
243
+ }
244
+
245
+ .rbird-booking-modal {
246
+ max-width: 100% !important;
247
+ height: 100% !important;
248
+ max-height: 100% !important;
249
+ border-radius: 0 !important;
250
+ }
251
+ }
252
+ `;
253
+ document.head.appendChild(style);
254
+ }
255
+ }
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,22 @@ class Rbird {
203
208
  }
204
209
  }
205
210
 
211
+ /**
212
+ * Show the booking modal
213
+ * @param {Object} options - Optional configuration
214
+ * @param {string} options.appointmentTypeId - Pre-select a specific appointment type
215
+ * @param {Function} options.onSuccess - Callback when booking is completed
216
+ * @param {Function} options.onClose - Callback when modal is closed
217
+ */
218
+ static showBooking(options = {}) {
219
+ if (typeof window === 'undefined') return;
220
+ try {
221
+ RbirdBookingManager.getInstance().showBooking(options);
222
+ } catch (e) {
223
+ console.error(e);
224
+ }
225
+ }
226
+
206
227
  }
207
228
 
208
229
  export const runFunctionWhenDomIsReady = (callback) => {