@magicfeedback/popup-sdk 1.3.0 → 1.5.0
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/README.md +6 -0
- package/dist/assets/assets/style.css +9 -2
- package/dist/chunk-D7QAGWGC.mjs +176 -0
- package/dist/{chunk-R4B3K2ZW.mjs.map → chunk-D7QAGWGC.mjs.map} +1 -1
- package/dist/chunk-JSBMP4MI.mjs +197 -0
- package/dist/{chunk-XFA2Y6CK.mjs.map → chunk-JSBMP4MI.mjs.map} +1 -1
- package/dist/index.d.mts +82 -3
- package/dist/index.d.ts +82 -3
- package/dist/index.js +447 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +257 -49
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +55 -2
- package/dist/react-native.d.ts +55 -2
- package/dist/react-native.js +447 -90
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +257 -49
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-ZYXOUBCP.mjs → renderPopup-4WZ7V435.mjs} +194 -45
- package/dist/renderPopup-4WZ7V435.mjs.map +1 -0
- package/dist/{renderPopup-NJK7Z46E.mjs → renderPopup-PXJEND4Y.mjs} +194 -45
- package/dist/renderPopup-PXJEND4Y.mjs.map +1 -0
- package/package.json +5 -10
- package/dist/chunk-R4B3K2ZW.mjs +0 -176
- package/dist/chunk-XFA2Y6CK.mjs +0 -197
- package/dist/renderPopup-NJK7Z46E.mjs.map +0 -1
- package/dist/renderPopup-ZYXOUBCP.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
sdkWarn,
|
|
10
10
|
setLogger,
|
|
11
11
|
style_default
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JSBMP4MI.mjs";
|
|
13
13
|
|
|
14
14
|
// src/types/index.ts
|
|
15
15
|
var POPUP_TRIGGER_CONDITION_STATUSES = [
|
|
@@ -19,6 +19,10 @@ var POPUP_TRIGGER_CONDITION_STATUSES = [
|
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
// src/triggers/index.ts
|
|
22
|
+
function toNumericValue(value, fallback) {
|
|
23
|
+
const n = Number(value);
|
|
24
|
+
return Number.isFinite(n) ? n : fallback;
|
|
25
|
+
}
|
|
22
26
|
function setupTrigger(popups, trigger) {
|
|
23
27
|
switch (trigger.type) {
|
|
24
28
|
case "time":
|
|
@@ -39,14 +43,14 @@ function setupTrigger(popups, trigger) {
|
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
function setupTimeTrigger(popups, trigger) {
|
|
42
|
-
const delay = trigger.value
|
|
46
|
+
const delay = toNumericValue(trigger.value, 5e3);
|
|
43
47
|
setTimeout(() => {
|
|
44
48
|
popups.triggerSurvey(trigger.surveyId, trigger.popupId);
|
|
45
49
|
}, delay);
|
|
46
50
|
popups.debug(`Time trigger set for ${delay}ms`);
|
|
47
51
|
}
|
|
48
52
|
function setupScrollTrigger(popups, trigger) {
|
|
49
|
-
const threshold = trigger.value
|
|
53
|
+
const threshold = toNumericValue(trigger.value, 50);
|
|
50
54
|
const handler = () => {
|
|
51
55
|
const scrollPercentage = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
|
|
52
56
|
if (scrollPercentage >= threshold) {
|
|
@@ -205,14 +209,17 @@ var POSITION_MAP = {
|
|
|
205
209
|
"top-right": { justifyContent: "flex-end", alignItems: "flex-start", padding: "16px", background: "transparent" },
|
|
206
210
|
"top-left": { justifyContent: "flex-start", alignItems: "flex-start", padding: "16px", background: "transparent" }
|
|
207
211
|
};
|
|
212
|
+
function jsonForScript(value) {
|
|
213
|
+
return JSON.stringify(value ?? null).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
214
|
+
}
|
|
208
215
|
function buildSurveyHtml(opts) {
|
|
209
216
|
const env = opts.env === "development" ? "dev" : "prod";
|
|
210
217
|
const version = opts.version ?? "2.2.4";
|
|
211
218
|
const cdn = `https://cdn.jsdelivr.net/npm/@magicfeedback/native@${version}/dist/magicfeedback-sdk.browser.js`;
|
|
212
|
-
const sid =
|
|
213
|
-
const pid =
|
|
214
|
-
const profileJson =
|
|
215
|
-
const metaJson =
|
|
219
|
+
const sid = jsonForScript(opts.surveyId);
|
|
220
|
+
const pid = jsonForScript(opts.productId);
|
|
221
|
+
const profileJson = jsonForScript(opts.profile ?? []);
|
|
222
|
+
const metaJson = jsonForScript(opts.metadata ?? []);
|
|
216
223
|
const fontFaceCss = opts.font ? buildFontFaceCss(opts.font.family, opts.font.url) : "";
|
|
217
224
|
const fontFamilyValue = opts.font ? buildFontFamilyValue(opts.font.family) : "-apple-system,system-ui,sans-serif";
|
|
218
225
|
const popupClass = opts.font?.family ? "deepdots-popup deepdots-has-font" : "deepdots-popup";
|
|
@@ -220,11 +227,29 @@ function buildSurveyHtml(opts) {
|
|
|
220
227
|
const popupBg = isDark ? "#1e1e1e" : "#fff";
|
|
221
228
|
const colorScheme = isDark ? "dark" : "light";
|
|
222
229
|
const textPrimary = isDark ? "#f0f0f0" : "#111";
|
|
230
|
+
const textMuted = isDark ? "#9ca3af" : "#6b7280";
|
|
231
|
+
const trackBg = isDark ? "#3f3f46" : "#e5e7eb";
|
|
223
232
|
const pos = POSITION_MAP[opts.position ?? "center"] ?? POSITION_MAP.center;
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
const
|
|
233
|
+
const chrome = opts.chrome !== false;
|
|
234
|
+
const bodyBg = chrome ? pos.background : "transparent";
|
|
235
|
+
const bodyPadding = chrome ? pos.padding : "0";
|
|
236
|
+
const bodyDisplay = chrome ? "flex" : "block";
|
|
237
|
+
const cardBg = chrome ? popupBg : "transparent";
|
|
238
|
+
const cardShadow = chrome ? "0 4px 6px rgba(0,0,0,0.1)" : "none";
|
|
239
|
+
const cardRadius = chrome ? "8px" : "0";
|
|
240
|
+
const cardMaxWidth = chrome ? "600px" : "none";
|
|
241
|
+
const cardWidth = chrome ? "90%" : "100%";
|
|
242
|
+
const cardMinHeight = chrome ? "200px" : "0";
|
|
243
|
+
const cardHeight = chrome ? "auto" : "100%";
|
|
244
|
+
const cardMaxHeight = chrome ? "90vh" : "100%";
|
|
245
|
+
const mobileCard = chrome ? `.deepdots-popup{width:calc(100% - 24px);max-width:calc(100% - 24px);border-radius:12px;padding:calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)) 16px}` : `.deepdots-popup{width:100%;max-width:100%;border-radius:0;padding:16px}`;
|
|
246
|
+
const titleJson = jsonForScript(opts.title ?? "");
|
|
247
|
+
const customCss = (opts.surveyCss ?? "").replace(/<\/\s*style/gi, "<\\/style");
|
|
248
|
+
const progressPref = opts.showProgressBar === void 0 ? "null" : String(opts.showProgressBar);
|
|
249
|
+
const backLabel = jsonForScript(opts.actions?.back?.label ?? "Back");
|
|
250
|
+
const startLabel = jsonForScript(opts.actions?.start?.label ?? "Start survey");
|
|
251
|
+
const completeLabel = jsonForScript(opts.actions?.complete?.label ?? "Complete survey");
|
|
252
|
+
const submitLabel = jsonForScript(opts.actions?.accept?.label ?? "Send");
|
|
228
253
|
return `<!DOCTYPE html><html><head>
|
|
229
254
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
230
255
|
<meta name="color-scheme" content="${colorScheme}"/>
|
|
@@ -232,57 +257,98 @@ function buildSurveyHtml(opts) {
|
|
|
232
257
|
${style_default}
|
|
233
258
|
${fontFaceCss}
|
|
234
259
|
html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
|
|
235
|
-
body{display
|
|
236
|
-
.deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${
|
|
237
|
-
.deepdots-popup-header{display:flex;justify-content:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
260
|
+
body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
|
|
261
|
+
.deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${cardBg};color-scheme:${colorScheme};border-radius:${cardRadius};padding:24px;box-shadow:${cardShadow};max-width:${cardMaxWidth};width:${cardWidth};min-height:${cardMinHeight};height:${cardHeight};max-height:${cardMaxHeight};box-sizing:border-box}
|
|
262
|
+
.deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
|
|
263
|
+
/* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
|
|
264
|
+
margin-bottom 40px), pensada para los enunciados y no para el t\xEDtulo de la cabecera. */
|
|
265
|
+
#dd-title{margin:0;font-family:var(--deepdots-font,'Montserrat',inherit);font-size:17px;font-weight:600;line-height:1.3;color:${textPrimary};text-transform:none;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
266
|
+
#dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px;flex:0 0 auto;margin-left:auto}
|
|
267
|
+
/* Progreso alineado con la cabecera: sin padding horizontal propio, lo marca la tarjeta.
|
|
268
|
+
El vertical es el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta. */
|
|
269
|
+
.deepdots-progress{display:none;flex-direction:column;gap:8px;width:100%;flex:0 0 auto;padding:16px 0;box-sizing:border-box}
|
|
270
|
+
.deepdots-progress-head{display:flex;flex-direction:row;justify-content:space-between;align-items:center;width:100%;gap:8px}
|
|
271
|
+
#dd-progress-label{font-size:13px;line-height:1.2}
|
|
272
|
+
/* "Question 1" en negrita y "of 3" en regular gris, como el mockup. */
|
|
273
|
+
#dd-progress-current{font-weight:700;color:${textPrimary}}
|
|
274
|
+
#dd-progress-total{font-weight:400;color:${textMuted}}
|
|
275
|
+
#dd-progress-followup{display:none;font-size:12px;font-weight:600;color:#fff;background:rgba(59,130,246,0.44);border-radius:999px;padding:2px 10px}
|
|
276
|
+
.deepdots-progress-track{width:100%;height:4px;border-radius:999px;background:${trackBg};overflow:hidden}
|
|
277
|
+
#dd-progress-bar{height:100%;width:0%;background:#22C55E;border-radius:999px;transition:width 450ms ease}
|
|
278
|
+
/* El popup es una columna: solo el bloque de preguntas hace scroll, para que el footer
|
|
279
|
+
con las acciones quede siempre visible en el borde inferior (antes viv\xEDa dentro del
|
|
280
|
+
\xE1rea scrollable y hab\xEDa que bajar hasta el final para ver "Send"). */
|
|
281
|
+
/* Sin sangrado extra: el contenido se alinea con el t\xEDtulo y con la barra de progreso (antes
|
|
282
|
+
sumaba 20px a los lados sobre el padding de la tarjeta y quedaba m\xE1s adentro que la cabecera). */
|
|
283
|
+
/* Sin barra de progreso, este padding-top es el que separa la cabecera de la pregunta. Con
|
|
284
|
+
barra, el JS lo pone a 0 y el hueco lo aporta el padding inferior del bloque de progreso,
|
|
285
|
+
de modo que el espacio por arriba y por abajo de la barra es id\xE9ntico. */
|
|
286
|
+
.deepdots-popup-container-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:16px 0 0 0;overflow:hidden;box-sizing:border-box}
|
|
287
|
+
/* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra y
|
|
288
|
+
descompensaba la simetr\xEDa. Solo se anula en el primero: entre preguntas sigue separando. */
|
|
289
|
+
.deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label{margin-top:0}
|
|
290
|
+
.deepdots-popup-main{display:flex;flex-direction:column;width:100%;flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;position:relative}
|
|
241
291
|
#dd-form-wrapper{width:100%;flex:1 1 auto}
|
|
242
292
|
#mf{width:100%;box-sizing:border-box;visibility:hidden}
|
|
243
293
|
.deepdots-popup-main *{max-width:100%;box-sizing:border-box}
|
|
244
294
|
#dd-logo{max-height:40px;max-width:100%;object-fit:contain}
|
|
245
295
|
.deepdots-error-hint{display:none;margin:12px 0 0 0;padding:10px 12px;border-radius:6px;background:#FEF3C7;color:#92400E;border:1px solid #FCD34D;font-size:13px}
|
|
246
|
-
.
|
|
247
|
-
.
|
|
248
|
-
|
|
296
|
+
/* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
|
|
297
|
+
.deepdots-success{display:none;width:100%;text-align:center;padding:24px 0;color:${textPrimary}}
|
|
298
|
+
.deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
|
|
299
|
+
.deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
300
|
+
.deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:4px;margin-top:auto;width:100%;padding-top:12px}
|
|
301
|
+
.dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:6px;cursor:pointer;font-size:15px;font-weight:600;align-items:center;justify-content:center;text-align:center}
|
|
302
|
+
/* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
|
|
303
|
+
#dd-back{background:transparent;color:${textMuted};border:none}
|
|
249
304
|
#dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
|
|
250
305
|
#dd-submit:disabled,#dd-start:disabled,#dd-back:disabled,#dd-complete:disabled{opacity:0.6;cursor:not-allowed}
|
|
251
306
|
.mf-spinner{display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
|
|
252
307
|
.mf-spinner-circle{width:28px;height:28px;border:3px solid #e0e6ed;border-top-color:#1E293B;border-radius:50%;animation:ddspin 0.9s linear infinite}
|
|
253
308
|
@keyframes ddspin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
|
|
254
309
|
@media (max-width:640px){
|
|
255
|
-
|
|
256
|
-
.
|
|
310
|
+
${mobileCard}
|
|
311
|
+
/* Apilados: la acci\xF3n principal (Send/Start/Complete) arriba y Back debajo. El orden del
|
|
312
|
+
DOM ya es ese, as\xED que \`column\` (no \`column-reverse\`) es lo que lo respeta. */
|
|
313
|
+
.deepdots-popup-footer{flex-direction:column;gap:4px}
|
|
257
314
|
.dd-nav-btn{width:100%}
|
|
258
315
|
.magicfeedback-checkbox-container,.magicfeedback-radio-container{margin:4px 0;padding:4px 8px}
|
|
259
316
|
.magicfeedback-checkbox label,.magicfeedback-radio-container label{font-size:15px}
|
|
260
317
|
.deepdots-popup input[type="radio"]{margin:6px 0 6px 8px}
|
|
261
318
|
.deepdots-popup input[type="checkbox"]{width:16px;height:16px}
|
|
262
319
|
}
|
|
320
|
+
${customCss}
|
|
263
321
|
</style>
|
|
264
322
|
</head><body>
|
|
265
323
|
<div class="${popupClass}" id="dd-popup">
|
|
266
324
|
<div class="deepdots-popup-header">
|
|
325
|
+
<h2 id="dd-title" class="deepdots-popup-title" hidden></h2>
|
|
267
326
|
<button type="button" id="dd-close" aria-label="Close popup">
|
|
268
327
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
269
328
|
<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
270
329
|
</svg>
|
|
271
330
|
</button>
|
|
272
331
|
</div>
|
|
273
|
-
<div class="deepdots-
|
|
332
|
+
<div class="deepdots-progress" id="dd-progress">
|
|
333
|
+
<div class="deepdots-progress-head">
|
|
334
|
+
<span id="dd-progress-label"><span id="dd-progress-current"></span><span id="dd-progress-total"></span></span>
|
|
335
|
+
<span id="dd-progress-followup">Follow-up</span>
|
|
336
|
+
</div>
|
|
337
|
+
<div class="deepdots-progress-track"><div id="dd-progress-bar"></div></div>
|
|
338
|
+
</div>
|
|
339
|
+
<div class="deepdots-popup-container-content" id="dd-content">
|
|
274
340
|
<div class="deepdots-popup-main" id="dd-main">
|
|
275
341
|
<div id="dd-form-wrapper">
|
|
276
342
|
<div class="mf-spinner" id="dd-spinner" role="status" aria-label="Loading survey"><div class="mf-spinner-circle"></div></div>
|
|
277
343
|
<div id="mf"></div>
|
|
278
344
|
</div>
|
|
279
345
|
<div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
</
|
|
346
|
+
</div>
|
|
347
|
+
<div class="deepdots-popup-footer" id="dd-footer">
|
|
348
|
+
<button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
|
|
349
|
+
<button type="button" class="dd-nav-btn" id="dd-back">Back</button>
|
|
350
|
+
<button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
|
|
351
|
+
<button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
|
|
286
352
|
</div>
|
|
287
353
|
</div>
|
|
288
354
|
</div>
|
|
@@ -291,9 +357,11 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
291
357
|
function emit(s){ try{ if(window.ReactNativeWebView){ window.ReactNativeWebView.postMessage(s); } }catch(e){} }
|
|
292
358
|
function emitJSON(n,p){ try{ emit(JSON.stringify({name:n,payload:p||{}})); }catch(e){} }
|
|
293
359
|
window.DeepdotsClose = function(){ emitJSON('popup_close'); };
|
|
360
|
+
var chromeOn=${chrome ? "true" : "false"};
|
|
294
361
|
|
|
295
362
|
var popup=document.getElementById('dd-popup');
|
|
296
363
|
var main=document.getElementById('dd-main');
|
|
364
|
+
var content=document.getElementById('dd-content');
|
|
297
365
|
var footer=document.getElementById('dd-footer');
|
|
298
366
|
var spinner=document.getElementById('dd-spinner');
|
|
299
367
|
var formHost=document.getElementById('mf');
|
|
@@ -302,6 +370,58 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
302
370
|
var startBtn=document.getElementById('dd-start');
|
|
303
371
|
var completeBtn=document.getElementById('dd-complete');
|
|
304
372
|
var submitBtn=document.getElementById('dd-submit');
|
|
373
|
+
var titleEl=document.getElementById('dd-title');
|
|
374
|
+
var progressEl=document.getElementById('dd-progress');
|
|
375
|
+
var progressLabel=document.getElementById('dd-progress-label');
|
|
376
|
+
var progressCurrent=document.getElementById('dd-progress-current');
|
|
377
|
+
var progressTotal=document.getElementById('dd-progress-total');
|
|
378
|
+
var progressFollowUp=document.getElementById('dd-progress-followup');
|
|
379
|
+
var progressBar=document.getElementById('dd-progress-bar');
|
|
380
|
+
|
|
381
|
+
function setTitle(t){
|
|
382
|
+
if(!t) return;
|
|
383
|
+
titleEl.textContent=t;
|
|
384
|
+
titleEl.hidden=false;
|
|
385
|
+
}
|
|
386
|
+
setTitle(${titleJson});
|
|
387
|
+
|
|
388
|
+
// Estado de la barra de progreso. \`progressPref\` null = manda la plataforma (style).
|
|
389
|
+
var progressPref=${progressPref};
|
|
390
|
+
var progressEnabled=progressPref===true;
|
|
391
|
+
var progressShowUnit=true;
|
|
392
|
+
var progressUnit='fraction';
|
|
393
|
+
var onStartPage=false;
|
|
394
|
+
|
|
395
|
+
function updateProgress(p){
|
|
396
|
+
var total=p&&typeof p.total==='number'?p.total:0;
|
|
397
|
+
var progress=p&&typeof p.progress==='number'?p.progress:0;
|
|
398
|
+
// Solo tiene sentido con m\xE1s de una p\xE1gina, fuera de la pantalla de inicio y sin completar.
|
|
399
|
+
if(!progressEnabled||onStartPage||p&&p.completed||total<=1){
|
|
400
|
+
progressEl.style.display='none';
|
|
401
|
+
// Sin barra, el hueco cabecera\u2192pregunta lo pone el contenido.
|
|
402
|
+
content.style.paddingTop='16px';
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
progressEl.style.display='flex';
|
|
406
|
+
// Con barra, el hueco inferior ya lo pone el bloque de progreso: no duplicarlo.
|
|
407
|
+
content.style.paddingTop='0';
|
|
408
|
+
// Espejo de LineProgressQuestion (MagicSurvey): la barra usa el valor real (las follow-up
|
|
409
|
+
// suman +0.5 y avanzan media casilla) y la etiqueta redondea hacia abajo, porque una
|
|
410
|
+
// follow-up es un paso DENTRO de la misma pregunta, no la siguiente.
|
|
411
|
+
var current=Math.min(total,Math.max(1,progress+1));
|
|
412
|
+
var pct=Math.min(100,Math.max(0,(current/total)*100));
|
|
413
|
+
progressBar.style.width=pct+'%';
|
|
414
|
+
var label=Math.min(total,Math.max(1,Math.floor(progress)+1));
|
|
415
|
+
progressLabel.style.display=progressShowUnit?'block':'none';
|
|
416
|
+
if(progressUnit==='percentage'){
|
|
417
|
+
progressCurrent.textContent=Math.round(pct)+'%';
|
|
418
|
+
progressTotal.textContent='';
|
|
419
|
+
} else {
|
|
420
|
+
progressCurrent.textContent='Question '+label;
|
|
421
|
+
progressTotal.textContent=' of '+total;
|
|
422
|
+
}
|
|
423
|
+
progressFollowUp.style.display=p&&p.followup?'inline-block':'none';
|
|
424
|
+
}
|
|
305
425
|
|
|
306
426
|
backBtn.textContent=${backLabel};
|
|
307
427
|
startBtn.textContent=${startLabel};
|
|
@@ -310,7 +430,13 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
310
430
|
|
|
311
431
|
document.getElementById('dd-close').onclick=function(){ emitJSON('popup_close'); };
|
|
312
432
|
backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
|
|
313
|
-
startBtn.onclick=function(){
|
|
433
|
+
startBtn.onclick=function(){
|
|
434
|
+
if(window.DeepdotsForm && window.DeepdotsForm.startForm){
|
|
435
|
+
window.DeepdotsForm.startForm();
|
|
436
|
+
onStartPage=false;
|
|
437
|
+
updateProgress({ progress:window.DeepdotsForm.progress, total:window.DeepdotsForm.total, completed:false, followup:false });
|
|
438
|
+
}
|
|
439
|
+
};
|
|
314
440
|
completeBtn.onclick=function(){ emitJSON('popup_close'); };
|
|
315
441
|
var surveyCompletedEmitted=false;
|
|
316
442
|
submitBtn.onclick=function(){
|
|
@@ -318,6 +444,36 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
318
444
|
if(window.DeepdotsForm && window.DeepdotsForm.send){ window.DeepdotsForm.send(); }
|
|
319
445
|
};
|
|
320
446
|
|
|
447
|
+
// Mensaje final configurado en la plataforma (\`style.successMessage\`). Se guarda al cargar
|
|
448
|
+
// y se pinta al completar. Va por innerHTML porque es HTML del editor de la plataforma
|
|
449
|
+
// (imagen + texto), igual que ya hace \`renderStartMessage\` con el mensaje de inicio.
|
|
450
|
+
var successMessageHtml='';
|
|
451
|
+
function showSuccessScreen(){
|
|
452
|
+
progressEl.style.display='none';
|
|
453
|
+
var wrapper=document.getElementById('dd-form-wrapper');
|
|
454
|
+
if(wrapper){ wrapper.style.display='none'; }
|
|
455
|
+
var done=document.getElementById('dd-success');
|
|
456
|
+
if(!done){
|
|
457
|
+
done=document.createElement('div');
|
|
458
|
+
done.id='dd-success';
|
|
459
|
+
done.className='deepdots-success';
|
|
460
|
+
main.insertBefore(done, errorHint);
|
|
461
|
+
}
|
|
462
|
+
done.innerHTML=successMessageHtml || '<p>Thank you for your feedback!</p>';
|
|
463
|
+
done.style.display='block';
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Profundidad de navegaci\xF3n DENTRO del survey: +1 por p\xE1gina avanzada, -1 al volver.
|
|
467
|
+
// Sustituye a la condici\xF3n \`total>1 && progress>0 && progress<total\`, que escond\xEDa el
|
|
468
|
+
// Back siempre que la siguiente pantalla era una follow-up din\xE1mica: las follow-up no
|
|
469
|
+
// entran en el grafo (suman +0.5 al progress y no tocan el total), as\xED que un survey de
|
|
470
|
+
// una pregunta con follow-up tiene total=1 y nunca cumpl\xEDa \`total>1\`.
|
|
471
|
+
var pageDepth=0;
|
|
472
|
+
|
|
473
|
+
function updateNavButtons(){
|
|
474
|
+
updateButtons(pageDepth>0?'in_progress_next':'in_progress_first');
|
|
475
|
+
}
|
|
476
|
+
|
|
321
477
|
function updateButtons(state){
|
|
322
478
|
backBtn.style.display='none';
|
|
323
479
|
startBtn.style.display='none';
|
|
@@ -362,11 +518,21 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
362
518
|
form.generate('mf', {
|
|
363
519
|
addButton:false,
|
|
364
520
|
getMetaData:true,
|
|
521
|
+
// La pantalla final la pinta el popup: renderSuccess de @magicfeedback/native usa
|
|
522
|
+
// textContent, as\xED que el mensaje de la plataforma (HTML con imagen) no se ver\xEDa, y su
|
|
523
|
+
// fallback es un literal gen\xE9rico que ignora style.successMessage.
|
|
524
|
+
addSuccessScreen:false,
|
|
365
525
|
onLoadedEvent:function(args){
|
|
366
526
|
var s=args && args.formData ? args.formData.style : null;
|
|
367
527
|
if(s && !stylesInjected){
|
|
368
528
|
stylesInjected=true;
|
|
369
|
-
if(s.
|
|
529
|
+
if(s.successMessage){ successMessageHtml=s.successMessage; }
|
|
530
|
+
// La barra de progreso la decide el host (init) y, si no se pronuncia, la plataforma.
|
|
531
|
+
if(progressPref===null){ progressEnabled=s.showProgressBar===true; }
|
|
532
|
+
if(s.showProgressUnit!==undefined){ progressShowUnit=s.showProgressUnit!==false; }
|
|
533
|
+
if(s.progressUnit){ progressUnit=s.progressUnit; }
|
|
534
|
+
if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
|
|
535
|
+
if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
|
|
370
536
|
if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
|
|
371
537
|
if(s.buttonPrimaryColor){
|
|
372
538
|
submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
|
|
@@ -374,7 +540,8 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
374
540
|
completeBtn.style.background=s.buttonPrimaryColor; completeBtn.style.border='none'; completeBtn.style.color='#fff';
|
|
375
541
|
}
|
|
376
542
|
if(s.buttonSecondaryColor){
|
|
377
|
-
|
|
543
|
+
// Bot\xF3n de texto: solo ti\xF1e la etiqueta, sin recuperar fondo ni borde.
|
|
544
|
+
backBtn.style.background='transparent'; backBtn.style.color=s.buttonSecondaryColor; backBtn.style.border='none';
|
|
378
545
|
}
|
|
379
546
|
if(s.logo && !document.getElementById('dd-logo')){
|
|
380
547
|
var logoImg=document.createElement('img');
|
|
@@ -387,11 +554,13 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
387
554
|
else if(s.logoPosition==='center'){ logoImg.style.margin='0 auto 20px auto'; logoImg.style.display='block'; }
|
|
388
555
|
main.insertBefore(logoImg, document.getElementById('dd-form-wrapper'));
|
|
389
556
|
}
|
|
390
|
-
if(s.startMessage && s.startMessage!==''){ updateButtons('start'); }
|
|
557
|
+
if(s.startMessage && s.startMessage!==''){ onStartPage=true; updateButtons('start'); }
|
|
391
558
|
else { updateButtons('in_progress_first'); }
|
|
392
559
|
} else {
|
|
393
560
|
updateButtons('in_progress_first');
|
|
394
561
|
}
|
|
562
|
+
// El total solo se conoce una vez montado el form; sin \xE9l no hay barra que pintar.
|
|
563
|
+
updateProgress({ progress:form.progress, total:form.total, completed:false, followup:false });
|
|
395
564
|
emitJSON('loaded');
|
|
396
565
|
setLoading(false);
|
|
397
566
|
},
|
|
@@ -404,9 +573,10 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
404
573
|
if(error){
|
|
405
574
|
setLoading(false);
|
|
406
575
|
if(error.toLowerCase().indexOf('no response')!==-1){
|
|
576
|
+
// La p\xE1gina no ha cambiado: el estado de navegaci\xF3n se queda como estaba.
|
|
407
577
|
errorHint.textContent='Please answer the required question to continue.';
|
|
408
578
|
errorHint.style.display='block';
|
|
409
|
-
|
|
579
|
+
updateNavButtons();
|
|
410
580
|
return;
|
|
411
581
|
}
|
|
412
582
|
errorHint.textContent='An error occurred while submitting. Please try again or close the popup.';
|
|
@@ -417,17 +587,23 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
|
|
|
417
587
|
setLoading(false);
|
|
418
588
|
if(p && p.completed){
|
|
419
589
|
surveyCompletedEmitted=true;
|
|
590
|
+
showSuccessScreen();
|
|
420
591
|
updateButtons('completed');
|
|
592
|
+
updateProgress(p);
|
|
421
593
|
emitJSON('survey_completed', p);
|
|
422
594
|
return;
|
|
423
595
|
}
|
|
424
|
-
|
|
425
|
-
|
|
596
|
+
pageDepth++;
|
|
597
|
+
updateNavButtons();
|
|
598
|
+
updateProgress(p);
|
|
426
599
|
emitJSON('after_submit', p);
|
|
427
600
|
},
|
|
428
601
|
onBackEvent:function(p){
|
|
429
|
-
|
|
430
|
-
|
|
602
|
+
// Con error ("No page found") no hubo navegaci\xF3n: la profundidad no se toca.
|
|
603
|
+
if(!(p&&p.error)){ pageDepth=Math.max(0,pageDepth-1); }
|
|
604
|
+
updateNavButtons();
|
|
605
|
+
// onBackEvent no trae \`total\`: se lee del form, que es su due\xF1o.
|
|
606
|
+
updateProgress({ progress:p&&p.progress, total:form.total, completed:false, followup:p&&p.followup });
|
|
431
607
|
emitJSON('back', p);
|
|
432
608
|
}
|
|
433
609
|
}).catch(function(e){ setLoading(false); emit('error:init'); });
|
|
@@ -455,7 +631,7 @@ var ReactNativePopupRenderer = class {
|
|
|
455
631
|
}
|
|
456
632
|
init() {
|
|
457
633
|
}
|
|
458
|
-
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
|
|
634
|
+
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome, options) {
|
|
459
635
|
this.emitFn = emit;
|
|
460
636
|
this.onCloseFn = onClose;
|
|
461
637
|
this.currentSurveyId = surveyId;
|
|
@@ -470,7 +646,12 @@ var ReactNativePopupRenderer = class {
|
|
|
470
646
|
font: style?.font,
|
|
471
647
|
theme: style?.theme,
|
|
472
648
|
position: style?.position,
|
|
473
|
-
actions
|
|
649
|
+
actions,
|
|
650
|
+
// renderChrome:false (init) → HTML sin tarjeta/overlay: el host lo envuelve en su Modal.
|
|
651
|
+
chrome: renderChrome,
|
|
652
|
+
title: options?.title,
|
|
653
|
+
showProgressBar: options?.showProgressBar,
|
|
654
|
+
surveyCss: options?.surveyCss
|
|
474
655
|
});
|
|
475
656
|
if (this.options.onShow) {
|
|
476
657
|
this.options.onShow({ surveyId, productId, html });
|
|
@@ -510,7 +691,6 @@ var ReactNativePopupRenderer = class {
|
|
|
510
691
|
break;
|
|
511
692
|
case "survey_completed":
|
|
512
693
|
this.emitFn("survey_completed", surveyId);
|
|
513
|
-
this.onCloseFn?.();
|
|
514
694
|
break;
|
|
515
695
|
case "popup_close":
|
|
516
696
|
this.onCloseFn?.();
|
|
@@ -561,14 +741,14 @@ var BrowserPopupRenderer = class {
|
|
|
561
741
|
document.body.appendChild(this.container);
|
|
562
742
|
}
|
|
563
743
|
}
|
|
564
|
-
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
|
|
744
|
+
show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
|
|
565
745
|
if (this.visible) return;
|
|
566
746
|
if (!this.container || !document.body.contains(this.container)) this.init();
|
|
567
747
|
if (!this.container) return;
|
|
568
748
|
this.visible = true;
|
|
569
749
|
const container = this.container;
|
|
570
|
-
void import("./renderPopup-
|
|
571
|
-
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId);
|
|
750
|
+
void import("./renderPopup-PXJEND4Y.mjs").then(({ renderPopup }) => {
|
|
751
|
+
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
|
|
572
752
|
});
|
|
573
753
|
}
|
|
574
754
|
hide() {
|
|
@@ -1415,6 +1595,12 @@ var DeepdotsPopups = class {
|
|
|
1415
1595
|
this.deferredExitTimers = [];
|
|
1416
1596
|
this.baseUrl = "";
|
|
1417
1597
|
this.env = "production";
|
|
1598
|
+
/** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
|
|
1599
|
+
this.renderChrome = true;
|
|
1600
|
+
/** Barra de progreso. undefined = la decide la plataforma (style.showProgressBar). */
|
|
1601
|
+
this.showProgressBar = void 0;
|
|
1602
|
+
/** CSS del host inyectado al final de los estilos del popup. */
|
|
1603
|
+
this.surveyCss = void 0;
|
|
1418
1604
|
/** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
|
|
1419
1605
|
this.tracking = null;
|
|
1420
1606
|
/** Capa de analytics (canal separado del feedback). Null hasta init(). */
|
|
@@ -1465,6 +1651,9 @@ var DeepdotsPopups = class {
|
|
|
1465
1651
|
const env = resolveEnvironment(config.nodeEnv);
|
|
1466
1652
|
this.baseUrl = env.apiBaseUrl;
|
|
1467
1653
|
this.env = config.nodeEnv || "production";
|
|
1654
|
+
this.renderChrome = config.renderChrome ?? true;
|
|
1655
|
+
this.showProgressBar = config.showProgressBar;
|
|
1656
|
+
this.surveyCss = config.surveyCss;
|
|
1468
1657
|
this.config = {
|
|
1469
1658
|
apiKey: config.apiKey || void 0,
|
|
1470
1659
|
debug: config.debug || false,
|
|
@@ -1650,6 +1839,22 @@ var DeepdotsPopups = class {
|
|
|
1650
1839
|
trackFunnelStep(funnel, step, taskId, params) {
|
|
1651
1840
|
this.track("deepdots_funnel_step", { funnel, step, task_id: taskId, ...params ?? {} });
|
|
1652
1841
|
}
|
|
1842
|
+
/**
|
|
1843
|
+
* Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
|
|
1844
|
+
* dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
|
|
1845
|
+
*
|
|
1846
|
+
* Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
|
|
1847
|
+
* custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
|
|
1848
|
+
* Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
|
|
1849
|
+
*/
|
|
1850
|
+
trackMeaningfulInteraction(interactionType, params) {
|
|
1851
|
+
const type = typeof interactionType === "string" ? interactionType.trim() : "";
|
|
1852
|
+
if (!type) {
|
|
1853
|
+
console.warn("[DeepdotsPopups] trackMeaningfulInteraction discarded: empty interaction_type");
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
this.track("deepdots_meaningful_interaction", { interaction_type: type, ...params ?? {} });
|
|
1857
|
+
}
|
|
1653
1858
|
/**
|
|
1654
1859
|
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
1655
1860
|
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
@@ -1894,7 +2099,7 @@ var DeepdotsPopups = class {
|
|
|
1894
2099
|
this.log("Showing popup (definition)", def);
|
|
1895
2100
|
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
1896
2101
|
this.lastShown.set(def.id, Date.now());
|
|
1897
|
-
this.renderPopup(def.surveyId, def.productId, def.actions, def.style);
|
|
2102
|
+
this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
|
|
1898
2103
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
1899
2104
|
}
|
|
1900
2105
|
shouldShow(def, pathUrl, skipPathCheck = false) {
|
|
@@ -2232,7 +2437,7 @@ var DeepdotsPopups = class {
|
|
|
2232
2437
|
document.body.appendChild(this.popupContainer);
|
|
2233
2438
|
}
|
|
2234
2439
|
/** Render the popup UI */
|
|
2235
|
-
renderPopup(surveyId, productId, actions, style) {
|
|
2440
|
+
renderPopup(surveyId, productId, actions, style, title) {
|
|
2236
2441
|
const userId = this.tracking?.getUserId() ?? this.config?.userId;
|
|
2237
2442
|
const sessionId = this.tracking?.getSessionId() ?? void 0;
|
|
2238
2443
|
const miniService = this.analytics?.getMiniService() ?? void 0;
|
|
@@ -2250,13 +2455,15 @@ var DeepdotsPopups = class {
|
|
|
2250
2455
|
style,
|
|
2251
2456
|
sessionId,
|
|
2252
2457
|
miniService,
|
|
2253
|
-
analyticsFeedbackSessionId
|
|
2458
|
+
analyticsFeedbackSessionId,
|
|
2459
|
+
this.renderChrome,
|
|
2460
|
+
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
|
|
2254
2461
|
);
|
|
2255
2462
|
return;
|
|
2256
2463
|
}
|
|
2257
2464
|
if (!this.popupContainer) return;
|
|
2258
2465
|
const container = this.popupContainer;
|
|
2259
|
-
void import("./renderPopup-
|
|
2466
|
+
void import("./renderPopup-PXJEND4Y.mjs").then(({ renderPopup }) => {
|
|
2260
2467
|
renderPopup(
|
|
2261
2468
|
container,
|
|
2262
2469
|
surveyId,
|
|
@@ -2269,7 +2476,8 @@ var DeepdotsPopups = class {
|
|
|
2269
2476
|
style,
|
|
2270
2477
|
sessionId,
|
|
2271
2478
|
miniService,
|
|
2272
|
-
analyticsFeedbackSessionId
|
|
2479
|
+
analyticsFeedbackSessionId,
|
|
2480
|
+
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
|
|
2273
2481
|
);
|
|
2274
2482
|
});
|
|
2275
2483
|
}
|