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.
- package/build/index.js +1 -1
- package/package.json +3 -2
- package/published/1.0.87/index.js +1 -1
- package/published/1.0.88/index.js +1 -0
- package/published/1.0.89/index.js +1 -0
- package/published/latest/index.js +1 -1
- package/src/RbirdAutomationManager.js +416 -0
- package/src/RbirdFormManager.js +7 -2
- package/src/RbirdSurveyManager.js +720 -0
- package/src/RbirdWebsiteWidget.js +89 -8
- package/src/index.js +42 -0
|
@@ -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
|
+
}
|