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