releasebird-javascript-sdk 1.0.87 → 1.0.89

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,720 @@
1
+ import RbirdSessionManager from './RbirdSessionManager';
2
+
3
+ // API is defined globally via webpack.DefinePlugin
4
+ /* global API */
5
+
6
+ export class RbirdSurveyManager {
7
+ static instance;
8
+
9
+ constructor() {
10
+ this.displayedSurveys = new Set();
11
+ this.apiKey = null;
12
+ }
13
+
14
+ static getInstance() {
15
+ if (!RbirdSurveyManager.instance) {
16
+ RbirdSurveyManager.instance = new RbirdSurveyManager();
17
+ }
18
+ return RbirdSurveyManager.instance;
19
+ }
20
+
21
+ init(apiKey) {
22
+ if (typeof window === 'undefined') return;
23
+ this.apiKey = apiKey;
24
+ this.injectStyles();
25
+ }
26
+
27
+ /**
28
+ * Show a survey by its ID
29
+ * @param {string} surveyId - The ID of the survey to show
30
+ * @param {Object} options - Optional configuration
31
+ * @param {string} options.target - CSS selector for inline rendering (optional)
32
+ * @param {Function} options.onSubmit - Callback when survey is submitted
33
+ * @param {Function} options.onClose - Callback when survey is closed
34
+ */
35
+ showSurvey(surveyId, options = {}) {
36
+ if (typeof window === 'undefined') return;
37
+ if (!this.apiKey) {
38
+ console.error('[RbirdSurveyManager] SDK not initialized. Call Rbird.initialize() first.');
39
+ return;
40
+ }
41
+ if (!surveyId) {
42
+ console.error('[RbirdSurveyManager] Survey ID is required.');
43
+ return;
44
+ }
45
+
46
+ // For inline surveys, check if target element exists and is empty (SPA navigation case)
47
+ if (options.target) {
48
+ const targetElement = document.querySelector(options.target);
49
+ if (targetElement && targetElement.children.length === 0) {
50
+ this.displayedSurveys.delete(surveyId);
51
+ }
52
+ }
53
+
54
+ // Check if survey is already displayed
55
+ if (this.displayedSurveys.has(surveyId)) {
56
+ const existingSurvey = document.getElementById(`rbird-survey-${surveyId}`);
57
+ const existingOverlay = document.getElementById(`rbird-survey-overlay-${surveyId}`);
58
+ if (!existingSurvey && !existingOverlay) {
59
+ this.displayedSurveys.delete(surveyId);
60
+ } else {
61
+ console.warn('[RbirdSurveyManager] Survey is already displayed:', surveyId);
62
+ return;
63
+ }
64
+ }
65
+
66
+ const sessionManager = RbirdSessionManager.getInstance();
67
+ const state = sessionManager.getState();
68
+
69
+ const http = new XMLHttpRequest();
70
+ const browserLang = navigator.language ? navigator.language.split('-')[0] : 'en';
71
+ const url = `${API}/ewidget/surveys/${surveyId}`;
72
+ http.open("GET", url);
73
+ http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
74
+ http.setRequestHeader("apiKey", this.apiKey);
75
+ http.setRequestHeader("languageCode", browserLang);
76
+
77
+ if (state?.identify?.people) {
78
+ http.setRequestHeader("peopleId", state.identify.people);
79
+ }
80
+ if (sessionManager.anonymousIdentifier) {
81
+ http.setRequestHeader("anonymousId", sessionManager.anonymousIdentifier);
82
+ }
83
+
84
+ const self = this;
85
+ http.onreadystatechange = function () {
86
+ if (http.readyState === 4) {
87
+ if (http.status === 200) {
88
+ try {
89
+ const survey = JSON.parse(http.responseText);
90
+ if (options.target) {
91
+ self.renderInlineSurvey(survey, options);
92
+ } else {
93
+ self.renderModalSurvey(survey, options);
94
+ }
95
+ } catch (exp) {
96
+ console.error('[RbirdSurveyManager] Error parsing survey response:', exp);
97
+ }
98
+ } else {
99
+ console.error('[RbirdSurveyManager] Failed to fetch survey. Status:', http.status);
100
+ }
101
+ }
102
+ };
103
+ http.send();
104
+ }
105
+
106
+ renderInlineSurvey(survey, options) {
107
+ const targetElement = document.querySelector(options.target);
108
+ if (!targetElement) {
109
+ console.error('[RbirdSurveyManager] Target element not found:', options.target);
110
+ return;
111
+ }
112
+
113
+ const surveyElement = this.createSurveyElement(survey, false, options);
114
+ targetElement.innerHTML = '';
115
+ targetElement.appendChild(surveyElement);
116
+ this.displayedSurveys.add(survey.id);
117
+ }
118
+
119
+ renderModalSurvey(survey, options) {
120
+ const overlay = document.createElement('div');
121
+ overlay.className = 'rbird-survey-overlay';
122
+ overlay.id = `rbird-survey-overlay-${survey.id}`;
123
+
124
+ const modal = this.createSurveyElement(survey, true, options);
125
+ overlay.appendChild(modal);
126
+
127
+ // Close on overlay click
128
+ overlay.addEventListener('click', (e) => {
129
+ if (e.target === overlay) {
130
+ this.closeSurvey(survey.id, options.onClose);
131
+ }
132
+ });
133
+
134
+ document.body.appendChild(overlay);
135
+ this.displayedSurveys.add(survey.id);
136
+
137
+ // Animate in
138
+ requestAnimationFrame(() => {
139
+ overlay.classList.add('rbird-survey-overlay-visible');
140
+ });
141
+ }
142
+
143
+ createSurveyElement(survey, isModal, options) {
144
+ const container = document.createElement('div');
145
+ container.className = isModal ? 'rbird-survey-modal' : 'rbird-survey-inline';
146
+ container.id = `rbird-survey-${survey.id}`;
147
+
148
+ const questionsHtml = survey.questions.map((q, index) =>
149
+ this.createQuestionHtml(q, index)
150
+ ).join('');
151
+
152
+ container.innerHTML = `
153
+ <div class="rbird-survey-content" style="${this.getSurveyStyles(isModal)}">
154
+ ${isModal ? `
155
+ <button class="rbird-survey-close" style="${this.getCloseButtonStyles()}" onclick="window.RbirdSurveyManager.getInstance().closeSurvey('${survey.id}')">
156
+ ×
157
+ </button>
158
+ ` : ''}
159
+ <div class="rbird-survey-body">
160
+ ${survey.title ? `<h3 class="rbird-survey-title" style="${this.getTitleStyles()}">${this.escapeHtml(survey.title)}</h3>` : ''}
161
+ ${survey.description ? `<p class="rbird-survey-description" style="${this.getDescriptionStyles()}">${this.escapeHtml(survey.description)}</p>` : ''}
162
+ <form class="rbird-survey-questions" data-survey-id="${survey.id}">
163
+ ${questionsHtml}
164
+ <button type="submit" class="rbird-survey-submit" style="${this.getSubmitButtonStyles()}">
165
+ Submit
166
+ </button>
167
+ </form>
168
+ <div class="rbird-survey-success" style="display: none; text-align: center; padding: 40px 20px;">
169
+ <div style="font-size: 48px; margin-bottom: 16px;">🎉</div>
170
+ <h3 style="margin: 0 0 8px 0; font-size: 20px; color: #1f2937;">Thank you!</h3>
171
+ <p style="margin: 0; color: #6b7280; font-size: 14px;">Your response has been recorded.</p>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ `;
176
+
177
+ // Attach submit handler
178
+ const form = container.querySelector('form');
179
+ form.addEventListener('submit', (e) => {
180
+ e.preventDefault();
181
+ this.submitSurvey(survey.id, form, options);
182
+ });
183
+
184
+ // Make instance accessible globally for close button
185
+ window.RbirdSurveyManager = RbirdSurveyManager;
186
+
187
+ return container;
188
+ }
189
+
190
+ createQuestionHtml(question, index) {
191
+ const requiredMark = question.required ? '<span style="color: #ef4444;">*</span>' : '';
192
+
193
+ let html = `<div class="rbird-survey-question" style="margin-bottom: 24px;" data-question-id="${question.id}">`;
194
+ html += `<label style="${this.getLabelStyles()}">${this.escapeHtml(question.question)} ${requiredMark}</label>`;
195
+
196
+ switch (question.type) {
197
+ case 'RATING':
198
+ html += this.createRatingInput(question);
199
+ break;
200
+ case 'NPS':
201
+ html += this.createNpsInput(question);
202
+ break;
203
+ case 'EMOJI':
204
+ html += this.createEmojiInput(question);
205
+ break;
206
+ case 'TEXT':
207
+ html += this.createTextInput(question);
208
+ break;
209
+ case 'MULTIPLE_CHOICE':
210
+ html += this.createMultipleChoiceInput(question);
211
+ break;
212
+ case 'CHECKBOX':
213
+ html += this.createCheckboxInput(question);
214
+ break;
215
+ default:
216
+ html += this.createTextInput(question);
217
+ }
218
+
219
+ html += '</div>';
220
+ return html;
221
+ }
222
+
223
+ createRatingInput(question) {
224
+ return `
225
+ <div class="rbird-rating-container" style="display: flex; gap: 8px; margin-top: 8px;">
226
+ ${[1, 2, 3, 4, 5].map(value => `
227
+ <button type="button" class="rbird-rating-star" data-value="${value}" style="${this.getRatingStarStyles()}">
228
+
229
+ </button>
230
+ `).join('')}
231
+ </div>
232
+ <input type="hidden" name="${question.id}" ${question.required ? 'required' : ''}>
233
+ `;
234
+ }
235
+
236
+ createNpsInput(question) {
237
+ return `
238
+ <div class="rbird-nps-container" style="margin-top: 8px;">
239
+ <div style="display: flex; gap: 4px; flex-wrap: wrap;">
240
+ ${[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(value => `
241
+ <button type="button" class="rbird-nps-button" data-value="${value}" style="${this.getNpsButtonStyles(value)}">
242
+ ${value}
243
+ </button>
244
+ `).join('')}
245
+ </div>
246
+ <div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 12px; color: #6b7280;">
247
+ <span>Not at all likely</span>
248
+ <span>Extremely likely</span>
249
+ </div>
250
+ </div>
251
+ <input type="hidden" name="${question.id}" ${question.required ? 'required' : ''}>
252
+ `;
253
+ }
254
+
255
+ createEmojiInput(question) {
256
+ const emojis = ['😞', '😐', '😊', '😃', '🤩'];
257
+ return `
258
+ <div class="rbird-emoji-container" style="display: flex; gap: 16px; margin-top: 8px; justify-content: center;">
259
+ ${emojis.map((emoji) => `
260
+ <button type="button" class="rbird-emoji-button" data-value="${emoji}" style="${this.getEmojiButtonStyles()}">
261
+ ${emoji}
262
+ </button>
263
+ `).join('')}
264
+ </div>
265
+ <input type="hidden" name="${question.id}" ${question.required ? 'required' : ''}>
266
+ `;
267
+ }
268
+
269
+ createTextInput(question) {
270
+ return `
271
+ <textarea
272
+ name="${question.id}"
273
+ style="${this.getTextareaStyles()}"
274
+ rows="3"
275
+ placeholder="Your answer..."
276
+ ${question.required ? 'required' : ''}
277
+ ></textarea>
278
+ `;
279
+ }
280
+
281
+ createMultipleChoiceInput(question) {
282
+ if (!question.options || question.options.length === 0) {
283
+ return this.createTextInput(question);
284
+ }
285
+
286
+ return `
287
+ <div class="rbird-radio-container" style="margin-top: 8px;">
288
+ ${question.options.map((option, index) => `
289
+ <label style="display: flex; align-items: center; padding: 12px; margin-bottom: 8px; border: 1px solid #e5e7eb; border-radius: 8px; cursor: pointer; transition: all 0.2s;">
290
+ <input type="radio" name="${question.id}" value="${this.escapeHtml(option)}" style="margin-right: 12px;" ${question.required && index === 0 ? '' : ''}>
291
+ <span style="font-size: 14px; color: #374151;">${this.escapeHtml(option)}</span>
292
+ </label>
293
+ `).join('')}
294
+ </div>
295
+ `;
296
+ }
297
+
298
+ createCheckboxInput(question) {
299
+ if (!question.options || question.options.length === 0) {
300
+ return this.createTextInput(question);
301
+ }
302
+
303
+ return `
304
+ <div class="rbird-checkbox-container" style="margin-top: 8px;">
305
+ ${question.options.map(option => `
306
+ <label style="display: flex; align-items: center; padding: 12px; margin-bottom: 8px; border: 1px solid #e5e7eb; border-radius: 8px; cursor: pointer; transition: all 0.2s;">
307
+ <input type="checkbox" name="${question.id}" value="${this.escapeHtml(option)}" style="margin-right: 12px;">
308
+ <span style="font-size: 14px; color: #374151;">${this.escapeHtml(option)}</span>
309
+ </label>
310
+ `).join('')}
311
+ </div>
312
+ `;
313
+ }
314
+
315
+ submitSurvey(surveyId, formElement, options) {
316
+ const answers = [];
317
+ const questionElements = formElement.querySelectorAll('.rbird-survey-question');
318
+
319
+ questionElements.forEach(qEl => {
320
+ const questionId = qEl.getAttribute('data-question-id');
321
+ let value = null;
322
+ let questionType = null;
323
+
324
+ // Check for hidden input (rating, nps, emoji)
325
+ const hiddenInput = qEl.querySelector(`input[type="hidden"][name="${questionId}"]`);
326
+ if (hiddenInput && hiddenInput.value) {
327
+ value = hiddenInput.value;
328
+ // Determine question type based on container class
329
+ if (qEl.querySelector('.rbird-rating-container')) {
330
+ questionType = 'RATING';
331
+ value = parseInt(value, 10); // Convert to number for rating
332
+ } else if (qEl.querySelector('.rbird-nps-container')) {
333
+ questionType = 'NPS';
334
+ value = parseInt(value, 10); // Convert to number for NPS
335
+ } else if (qEl.querySelector('.rbird-emoji-container')) {
336
+ questionType = 'EMOJI';
337
+ // Emoji value is already a string (the emoji itself)
338
+ }
339
+ }
340
+
341
+ // Check for textarea
342
+ const textarea = qEl.querySelector(`textarea[name="${questionId}"]`);
343
+ if (textarea && textarea.value) {
344
+ value = textarea.value;
345
+ questionType = 'TEXT';
346
+ }
347
+
348
+ // Check for radio buttons
349
+ const checkedRadio = qEl.querySelector(`input[type="radio"][name="${questionId}"]:checked`);
350
+ if (checkedRadio) {
351
+ value = checkedRadio.value;
352
+ questionType = 'MULTIPLE_CHOICE';
353
+ }
354
+
355
+ // Check for checkboxes
356
+ const checkedCheckboxes = qEl.querySelectorAll(`input[type="checkbox"][name="${questionId}"]:checked`);
357
+ if (checkedCheckboxes.length > 0) {
358
+ value = Array.from(checkedCheckboxes).map(cb => cb.value);
359
+ questionType = 'CHECKBOX';
360
+ }
361
+
362
+ if (value !== null) {
363
+ answers.push({
364
+ questionId: questionId,
365
+ questionType: questionType,
366
+ value: value
367
+ });
368
+ }
369
+ });
370
+
371
+ const sessionManager = RbirdSessionManager.getInstance();
372
+ const state = sessionManager.getState();
373
+
374
+ const http = new XMLHttpRequest();
375
+ http.open("POST", `${API}/ewidget/surveys/${surveyId}/submit`);
376
+ http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
377
+ http.setRequestHeader("apiKey", this.apiKey);
378
+
379
+ if (state?.identify?.people) {
380
+ http.setRequestHeader("peopleId", state.identify.people);
381
+ }
382
+ if (sessionManager.anonymousIdentifier) {
383
+ http.setRequestHeader("anonymousId", sessionManager.anonymousIdentifier);
384
+ }
385
+
386
+ const self = this;
387
+ const submitButton = formElement.querySelector('button[type="submit"]');
388
+ if (submitButton) {
389
+ submitButton.disabled = true;
390
+ submitButton.textContent = 'Sending...';
391
+ }
392
+
393
+ http.onreadystatechange = function () {
394
+ if (http.readyState === 4) {
395
+ if (http.status === 200 || http.status === 201) {
396
+ // Show success message
397
+ const container = document.getElementById(`rbird-survey-${surveyId}`);
398
+ if (container) {
399
+ const form = container.querySelector('form');
400
+ const successMessage = container.querySelector('.rbird-survey-success');
401
+ if (form) form.style.display = 'none';
402
+ if (successMessage) successMessage.style.display = 'block';
403
+ }
404
+
405
+ if (options.onSubmit) {
406
+ options.onSubmit(answers);
407
+ }
408
+ } else {
409
+ console.error('[RbirdSurveyManager] Failed to submit survey. Status:', http.status);
410
+ if (submitButton) {
411
+ submitButton.disabled = false;
412
+ submitButton.textContent = 'Submit';
413
+ }
414
+ alert('Failed to submit survey. Please try again.');
415
+ }
416
+ }
417
+ };
418
+
419
+ http.send(JSON.stringify({
420
+ answers: answers
421
+ }));
422
+ }
423
+
424
+ closeSurvey(surveyId, onClose) {
425
+ const overlay = document.getElementById(`rbird-survey-overlay-${surveyId}`);
426
+ if (overlay) {
427
+ overlay.classList.remove('rbird-survey-overlay-visible');
428
+ setTimeout(() => {
429
+ overlay.remove();
430
+ }, 300);
431
+ }
432
+
433
+ this.displayedSurveys.delete(surveyId);
434
+
435
+ if (onClose) {
436
+ onClose();
437
+ }
438
+ }
439
+
440
+ // Styles
441
+ getSurveyStyles(isModal) {
442
+ return `
443
+ background-color: #ffffff !important;
444
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !important;
445
+ border-radius: 12px !important;
446
+ padding: 32px !important;
447
+ min-width: min(400px, calc(100vw - 40px)) !important;
448
+ ${isModal ? 'max-width: 500px !important; width: 100% !important; max-height: 90vh !important; overflow-y: auto !important; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important;' : 'width: 100% !important;'}
449
+ box-sizing: border-box !important;
450
+ `;
451
+ }
452
+
453
+ getCloseButtonStyles() {
454
+ return `
455
+ position: absolute;
456
+ top: 12px;
457
+ right: 12px;
458
+ background: none;
459
+ border: none;
460
+ font-size: 24px;
461
+ cursor: pointer;
462
+ color: #9ca3af;
463
+ width: 32px;
464
+ height: 32px;
465
+ display: flex;
466
+ align-items: center;
467
+ justify-content: center;
468
+ border-radius: 50%;
469
+ transition: all 0.2s;
470
+ opacity: 0.7;
471
+ `;
472
+ }
473
+
474
+ getTitleStyles() {
475
+ return `
476
+ margin: 0 0 8px 0;
477
+ font-size: 20px;
478
+ font-weight: 600;
479
+ color: #1f2937;
480
+ `;
481
+ }
482
+
483
+ getDescriptionStyles() {
484
+ return `
485
+ margin: 0 0 20px 0;
486
+ font-size: 14px;
487
+ color: #6b7280;
488
+ line-height: 1.5;
489
+ `;
490
+ }
491
+
492
+ getLabelStyles() {
493
+ return `
494
+ display: block;
495
+ margin-bottom: 8px;
496
+ font-size: 14px;
497
+ font-weight: 500;
498
+ color: #374151;
499
+ `;
500
+ }
501
+
502
+ getTextareaStyles() {
503
+ return `
504
+ width: 100%;
505
+ padding: 12px;
506
+ border: 1px solid #e5e7eb;
507
+ border-radius: 8px;
508
+ font-size: 14px;
509
+ font-family: inherit;
510
+ resize: vertical;
511
+ box-sizing: border-box;
512
+ outline: none;
513
+ transition: border-color 0.2s;
514
+ `;
515
+ }
516
+
517
+ getRatingStarStyles() {
518
+ return `
519
+ background: none;
520
+ border: none;
521
+ font-size: 32px;
522
+ cursor: pointer;
523
+ color: #d1d5db;
524
+ transition: all 0.2s;
525
+ padding: 4px;
526
+ `;
527
+ }
528
+
529
+ getNpsButtonStyles(value) {
530
+ let bgColor = '#f3f4f6';
531
+ if (value <= 6) bgColor = '#fecaca';
532
+ else if (value <= 8) bgColor = '#fef3c7';
533
+ else bgColor = '#bbf7d0';
534
+
535
+ return `
536
+ width: 32px;
537
+ height: 32px;
538
+ border: 1px solid #e5e7eb;
539
+ border-radius: 6px;
540
+ background: ${bgColor};
541
+ cursor: pointer;
542
+ font-size: 12px;
543
+ font-weight: 500;
544
+ transition: all 0.2s;
545
+ `;
546
+ }
547
+
548
+ getEmojiButtonStyles() {
549
+ return `
550
+ background: none;
551
+ border: 2px solid transparent;
552
+ font-size: 36px;
553
+ cursor: pointer;
554
+ padding: 8px;
555
+ border-radius: 12px;
556
+ transition: all 0.2s;
557
+ `;
558
+ }
559
+
560
+ getSubmitButtonStyles() {
561
+ return `
562
+ width: 100%;
563
+ padding: 14px 24px;
564
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
565
+ color: white;
566
+ border: none;
567
+ border-radius: 8px;
568
+ font-size: 16px;
569
+ font-weight: 500;
570
+ cursor: pointer;
571
+ margin-top: 16px;
572
+ transition: all 0.2s;
573
+ `;
574
+ }
575
+
576
+ escapeHtml(text) {
577
+ if (!text) return '';
578
+ const div = document.createElement('div');
579
+ div.textContent = text;
580
+ return div.innerHTML;
581
+ }
582
+
583
+ injectStyles() {
584
+ if (typeof window === 'undefined' || document.getElementById('rbird-survey-styles')) return;
585
+
586
+ const style = document.createElement('style');
587
+ style.id = 'rbird-survey-styles';
588
+ style.textContent = `
589
+ .rbird-survey-overlay {
590
+ position: fixed !important;
591
+ top: 0 !important;
592
+ left: 0 !important;
593
+ right: 0 !important;
594
+ bottom: 0 !important;
595
+ background-color: rgba(0, 0, 0, 0) !important;
596
+ display: flex !important;
597
+ align-items: center !important;
598
+ justify-content: center !important;
599
+ z-index: 10001 !important;
600
+ padding: 20px !important;
601
+ opacity: 0;
602
+ transition: background-color 0.3s, opacity 0.3s;
603
+ box-sizing: border-box !important;
604
+ }
605
+
606
+ .rbird-survey-overlay-visible {
607
+ background-color: rgba(0, 0, 0, 0.5) !important;
608
+ opacity: 1 !important;
609
+ }
610
+
611
+ .rbird-survey-modal {
612
+ position: relative !important;
613
+ animation: rbirdSurveySlideIn 0.3s ease-out;
614
+ box-sizing: border-box !important;
615
+ }
616
+
617
+ .rbird-survey-inline {
618
+ width: 100% !important;
619
+ box-sizing: border-box !important;
620
+ }
621
+
622
+ .rbird-survey-content {
623
+ position: relative !important;
624
+ box-sizing: border-box !important;
625
+ }
626
+
627
+ .rbird-survey-close:hover {
628
+ opacity: 1 !important;
629
+ }
630
+
631
+ .rbird-survey-submit:hover {
632
+ opacity: 0.9 !important;
633
+ transform: translateY(-1px);
634
+ }
635
+
636
+ .rbird-survey-submit:disabled {
637
+ opacity: 0.6 !important;
638
+ cursor: not-allowed !important;
639
+ }
640
+
641
+ .rbird-rating-star:hover,
642
+ .rbird-rating-star.active {
643
+ color: #fbbf24 !important;
644
+ transform: scale(1.1);
645
+ }
646
+
647
+ .rbird-nps-button:hover,
648
+ .rbird-nps-button.active {
649
+ transform: scale(1.1);
650
+ border-color: #667eea !important;
651
+ }
652
+
653
+ .rbird-emoji-button:hover,
654
+ .rbird-emoji-button.active {
655
+ border-color: #667eea !important;
656
+ transform: scale(1.2);
657
+ }
658
+
659
+ @keyframes rbirdSurveySlideIn {
660
+ from {
661
+ opacity: 0;
662
+ transform: translateY(-20px) scale(0.95);
663
+ }
664
+ to {
665
+ opacity: 1;
666
+ transform: translateY(0) scale(1);
667
+ }
668
+ }
669
+ `;
670
+ document.head.appendChild(style);
671
+
672
+ // Add click handlers for rating/nps/emoji inputs
673
+ document.addEventListener('click', (e) => {
674
+ // Rating stars
675
+ if (e.target.classList.contains('rbird-rating-star')) {
676
+ const container = e.target.closest('.rbird-rating-container');
677
+ const value = e.target.getAttribute('data-value');
678
+ const hiddenInput = container.parentElement.querySelector('input[type="hidden"]');
679
+
680
+ container.querySelectorAll('.rbird-rating-star').forEach((star, index) => {
681
+ if (index < parseInt(value)) {
682
+ star.classList.add('active');
683
+ } else {
684
+ star.classList.remove('active');
685
+ }
686
+ });
687
+
688
+ if (hiddenInput) hiddenInput.value = value;
689
+ }
690
+
691
+ // NPS buttons
692
+ if (e.target.classList.contains('rbird-nps-button')) {
693
+ const container = e.target.closest('.rbird-nps-container');
694
+ const value = e.target.getAttribute('data-value');
695
+ const hiddenInput = container.parentElement.querySelector('input[type="hidden"]');
696
+
697
+ container.querySelectorAll('.rbird-nps-button').forEach(btn => {
698
+ btn.classList.remove('active');
699
+ });
700
+ e.target.classList.add('active');
701
+
702
+ if (hiddenInput) hiddenInput.value = value;
703
+ }
704
+
705
+ // Emoji buttons
706
+ if (e.target.classList.contains('rbird-emoji-button')) {
707
+ const container = e.target.closest('.rbird-emoji-container');
708
+ const value = e.target.getAttribute('data-value');
709
+ const hiddenInput = container.parentElement.querySelector('input[type="hidden"]');
710
+
711
+ container.querySelectorAll('.rbird-emoji-button').forEach(btn => {
712
+ btn.classList.remove('active');
713
+ });
714
+ e.target.classList.add('active');
715
+
716
+ if (hiddenInput) hiddenInput.value = value;
717
+ }
718
+ });
719
+ }
720
+ }