@magicfeedback/popup-sdk 1.6.0 → 1.7.1
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 +34 -1
- package/dist/assets/assets/style.css +63 -14
- package/dist/{chunk-AN7JIVWB.mjs → chunk-W6MPSWMS.mjs} +352 -15
- package/dist/chunk-W6MPSWMS.mjs.map +1 -0
- package/dist/{chunk-Z3LLJMSH.mjs → chunk-WNIUIOKF.mjs} +332 -15
- package/dist/chunk-WNIUIOKF.mjs.map +1 -0
- package/dist/index.d.mts +99 -1
- package/dist/index.d.ts +99 -1
- package/dist/index.js +1647 -1366
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +200 -28
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +13 -0
- package/dist/react-native.d.ts +13 -0
- package/dist/react-native.js +550 -55
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +189 -28
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-SELXQ3UE.mjs → renderPopup-EWGKG53W.mjs} +42 -18
- package/dist/renderPopup-EWGKG53W.mjs.map +1 -0
- package/dist/renderPopup-HHQMAW3G.mjs +3114 -0
- package/dist/renderPopup-HHQMAW3G.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-AN7JIVWB.mjs.map +0 -1
- package/dist/chunk-Z3LLJMSH.mjs.map +0 -1
- package/dist/renderPopup-M6MKTDEH.mjs +0 -3330
- package/dist/renderPopup-M6MKTDEH.mjs.map +0 -1
- package/dist/renderPopup-SELXQ3UE.mjs.map +0 -1
package/dist/react-native.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
LABELS,
|
|
3
|
+
RESOLVE_LOCALE_JS,
|
|
4
|
+
RTL_LOCALES,
|
|
2
5
|
STORAGE_KEYS,
|
|
3
6
|
TrackingManager,
|
|
4
7
|
__require,
|
|
@@ -6,10 +9,13 @@ import {
|
|
|
6
9
|
buildFontFamilyValue,
|
|
7
10
|
buildSurveyIdentity,
|
|
8
11
|
createDefaultStorage,
|
|
12
|
+
directionFor,
|
|
13
|
+
getLabels,
|
|
14
|
+
resolveActionLabels,
|
|
9
15
|
sdkWarn,
|
|
10
16
|
setLogger,
|
|
11
17
|
style_default
|
|
12
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-WNIUIOKF.mjs";
|
|
13
19
|
|
|
14
20
|
// src/react-native/index.tsx
|
|
15
21
|
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
@@ -217,9 +223,13 @@ var POSITION_MAP = {
|
|
|
217
223
|
function jsonForScript(value) {
|
|
218
224
|
return JSON.stringify(value ?? null).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
219
225
|
}
|
|
226
|
+
function trimmedOrNull(value) {
|
|
227
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
228
|
+
return trimmed ? value : null;
|
|
229
|
+
}
|
|
220
230
|
function buildSurveyHtml(opts) {
|
|
221
231
|
const env = opts.env === "development" ? "dev" : "prod";
|
|
222
|
-
const version = opts.version ?? "2.2.
|
|
232
|
+
const version = opts.version ?? "2.2.22";
|
|
223
233
|
const cdn = `https://cdn.jsdelivr.net/npm/@magicfeedback/native@${version}/dist/magicfeedback-sdk.browser.js`;
|
|
224
234
|
const sid = jsonForScript(opts.surveyId);
|
|
225
235
|
const pid = jsonForScript(opts.productId);
|
|
@@ -251,10 +261,22 @@ function buildSurveyHtml(opts) {
|
|
|
251
261
|
const titleJson = jsonForScript(opts.title ?? "");
|
|
252
262
|
const customCss = (opts.surveyCss ?? "").replace(/<\/\s*style/gi, "<\\/style");
|
|
253
263
|
const progressPref = opts.showProgressBar === void 0 ? "null" : String(opts.showProgressBar);
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
const
|
|
264
|
+
const initLabels = getLabels(opts.language);
|
|
265
|
+
const initActionLabels = resolveActionLabels(opts.actions, opts.language);
|
|
266
|
+
const backLabel = jsonForScript(initActionLabels.back);
|
|
267
|
+
const startLabel = jsonForScript(initActionLabels.start);
|
|
268
|
+
const completeLabel = jsonForScript(initActionLabels.complete);
|
|
269
|
+
const submitLabel = jsonForScript(initActionLabels.accept);
|
|
270
|
+
const labelsTableJson = jsonForScript(LABELS);
|
|
271
|
+
const actionOverridesJson = jsonForScript({
|
|
272
|
+
accept: trimmedOrNull(opts.actions?.accept?.label),
|
|
273
|
+
start: trimmedOrNull(opts.actions?.start?.label),
|
|
274
|
+
complete: trimmedOrNull(opts.actions?.complete?.label),
|
|
275
|
+
back: trimmedOrNull(opts.actions?.back?.label)
|
|
276
|
+
});
|
|
277
|
+
const initLangJson = jsonForScript(opts.language ?? "");
|
|
278
|
+
const initDirection = directionFor(opts.language);
|
|
279
|
+
const rtlLocalesJson = jsonForScript(RTL_LOCALES);
|
|
258
280
|
return `<!DOCTYPE html><html><head>
|
|
259
281
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
260
282
|
<meta name="color-scheme" content="${colorScheme}"/>
|
|
@@ -267,8 +289,8 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
267
289
|
.deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
|
|
268
290
|
/* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
|
|
269
291
|
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:
|
|
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-
|
|
292
|
+
#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:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
293
|
+
#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-inline-start:auto}
|
|
272
294
|
/* Progreso alineado con la cabecera: sin padding horizontal propio, lo marca la tarjeta.
|
|
273
295
|
El vertical es el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta. */
|
|
274
296
|
.deepdots-progress{display:none;flex-direction:column;gap:8px;width:100%;flex:0 0 auto;padding:16px 0;box-sizing:border-box}
|
|
@@ -325,10 +347,10 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
|
|
|
325
347
|
${customCss}
|
|
326
348
|
</style>
|
|
327
349
|
</head><body>
|
|
328
|
-
<div class="${popupClass}" id="dd-popup">
|
|
350
|
+
<div class="${popupClass}" id="dd-popup" dir="${initDirection}">
|
|
329
351
|
<div class="deepdots-popup-header">
|
|
330
352
|
<h2 id="dd-title" class="deepdots-popup-title" hidden></h2>
|
|
331
|
-
<button type="button" id="dd-close" aria-label="
|
|
353
|
+
<button type="button" id="dd-close" aria-label="${initLabels.closeAria}">
|
|
332
354
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
333
355
|
<path d="M5 5L19 19M5 19L19 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="butt"/>
|
|
334
356
|
</svg>
|
|
@@ -337,23 +359,23 @@ ${customCss}
|
|
|
337
359
|
<div class="deepdots-progress" id="dd-progress">
|
|
338
360
|
<div class="deepdots-progress-head">
|
|
339
361
|
<span id="dd-progress-label"><span id="dd-progress-current"></span><span id="dd-progress-total"></span></span>
|
|
340
|
-
<span id="dd-progress-followup"
|
|
362
|
+
<span id="dd-progress-followup">${initLabels.followUp}</span>
|
|
341
363
|
</div>
|
|
342
364
|
<div class="deepdots-progress-track"><div id="dd-progress-bar"></div></div>
|
|
343
365
|
</div>
|
|
344
366
|
<div class="deepdots-popup-container-content" id="dd-content">
|
|
345
367
|
<div class="deepdots-popup-main" id="dd-main">
|
|
346
368
|
<div id="dd-form-wrapper">
|
|
347
|
-
<div class="mf-spinner" id="dd-spinner" role="status" aria-label="
|
|
369
|
+
<div class="mf-spinner" id="dd-spinner" role="status" aria-label="${initLabels.loadingAria}"><div class="mf-spinner-circle"></div></div>
|
|
348
370
|
<div id="mf"></div>
|
|
349
371
|
</div>
|
|
350
372
|
<div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
|
|
351
373
|
</div>
|
|
352
374
|
<div class="deepdots-popup-footer" id="dd-footer">
|
|
353
|
-
<button type="button" class="dd-nav-btn" id="dd-submit"
|
|
354
|
-
<button type="button" class="dd-nav-btn" id="dd-back"
|
|
355
|
-
<button type="button" class="dd-nav-btn" id="dd-complete"
|
|
356
|
-
<button type="button" class="dd-nav-btn" id="dd-start"
|
|
375
|
+
<button type="button" class="dd-nav-btn" id="dd-submit"></button>
|
|
376
|
+
<button type="button" class="dd-nav-btn" id="dd-back"></button>
|
|
377
|
+
<button type="button" class="dd-nav-btn" id="dd-complete"></button>
|
|
378
|
+
<button type="button" class="dd-nav-btn" id="dd-start"></button>
|
|
357
379
|
</div>
|
|
358
380
|
</div>
|
|
359
381
|
</div>
|
|
@@ -382,6 +404,32 @@ ${customCss}
|
|
|
382
404
|
var progressTotal=document.getElementById('dd-progress-total');
|
|
383
405
|
var progressFollowUp=document.getElementById('dd-progress-followup');
|
|
384
406
|
var progressBar=document.getElementById('dd-progress-bar');
|
|
407
|
+
var closeEl=document.getElementById('dd-close');
|
|
408
|
+
|
|
409
|
+
// --- i18n del chrome -------------------------------------------------------------------
|
|
410
|
+
// La tabla completa viaja embebida porque el idioma del survey (\`formData.lang[0]\`) solo se
|
|
411
|
+
// conoce ya dentro del WebView. \`ddResolveLocale\` es el espejo del \`resolveLocale\` de TS
|
|
412
|
+
// (paridad cubierta por test).
|
|
413
|
+
var DD_LABELS=${labelsTableJson};
|
|
414
|
+
var DD_ACTION_OVERRIDES=${actionOverridesJson};
|
|
415
|
+
${RESOLVE_LOCALE_JS}
|
|
416
|
+
var DD_LABELS_ACTIVE=DD_LABELS[ddResolveLocale(${initLangJson})];
|
|
417
|
+
var DD_RTL=${rtlLocalesJson};
|
|
418
|
+
function ddIsRtl(lang){ return DD_RTL.indexOf(ddResolveLocale(lang))!==-1; }
|
|
419
|
+
function ddApplyLabels(lang){
|
|
420
|
+
var next=DD_LABELS[ddResolveLocale(lang)];
|
|
421
|
+
if(!next) return;
|
|
422
|
+
DD_LABELS_ACTIVE=next;
|
|
423
|
+
// El survey ya se ha volteado a s\xED mismo: el chrome tiene que acompa\xF1arlo.
|
|
424
|
+
popup.setAttribute('dir', ddIsRtl(lang) ? 'rtl' : 'ltr');
|
|
425
|
+
backBtn.textContent=DD_ACTION_OVERRIDES.back||next.back;
|
|
426
|
+
startBtn.textContent=DD_ACTION_OVERRIDES.start||next.start;
|
|
427
|
+
completeBtn.textContent=DD_ACTION_OVERRIDES.complete||next.complete;
|
|
428
|
+
submitBtn.textContent=DD_ACTION_OVERRIDES.accept||next.accept;
|
|
429
|
+
if(closeEl){ closeEl.setAttribute('aria-label',next.closeAria); }
|
|
430
|
+
if(spinner){ spinner.setAttribute('aria-label',next.loadingAria); }
|
|
431
|
+
progressFollowUp.textContent=next.followUp;
|
|
432
|
+
}
|
|
385
433
|
|
|
386
434
|
function setTitle(t){
|
|
387
435
|
if(!t) return;
|
|
@@ -422,8 +470,8 @@ ${customCss}
|
|
|
422
470
|
progressCurrent.textContent=Math.round(pct)+'%';
|
|
423
471
|
progressTotal.textContent='';
|
|
424
472
|
} else {
|
|
425
|
-
progressCurrent.textContent='
|
|
426
|
-
progressTotal.textContent=' of '+total;
|
|
473
|
+
progressCurrent.textContent=DD_LABELS_ACTIVE.question+' '+label;
|
|
474
|
+
progressTotal.textContent=' '+DD_LABELS_ACTIVE.of+' '+total;
|
|
427
475
|
}
|
|
428
476
|
progressFollowUp.style.display=p&&p.followup?'inline-block':'none';
|
|
429
477
|
}
|
|
@@ -433,7 +481,7 @@ ${customCss}
|
|
|
433
481
|
completeBtn.textContent=${completeLabel};
|
|
434
482
|
submitBtn.textContent=${submitLabel};
|
|
435
483
|
|
|
436
|
-
|
|
484
|
+
closeEl.onclick=function(){ emitJSON('popup_close'); };
|
|
437
485
|
backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
|
|
438
486
|
startBtn.onclick=function(){
|
|
439
487
|
if(window.DeepdotsForm && window.DeepdotsForm.startForm){
|
|
@@ -528,6 +576,14 @@ ${customCss}
|
|
|
528
576
|
// fallback es un literal gen\xE9rico que ignora style.successMessage.
|
|
529
577
|
addSuccessScreen:false,
|
|
530
578
|
onLoadedEvent:function(args){
|
|
579
|
+
// Idioma del survey: manda sobre el del init para que el chrome no se quede en
|
|
580
|
+
// ingl\xE9s delante de un survey traducido.
|
|
581
|
+
var langs=args && args.formData ? args.formData.lang : null;
|
|
582
|
+
if(langs && langs.length){
|
|
583
|
+
for(var li=0;li<langs.length;li++){
|
|
584
|
+
if(typeof langs[li]==='string' && langs[li].trim()){ ddApplyLabels(langs[li]); break; }
|
|
585
|
+
}
|
|
586
|
+
}
|
|
531
587
|
var s=args && args.formData ? args.formData.style : null;
|
|
532
588
|
if(s && !stylesInjected){
|
|
533
589
|
stylesInjected=true;
|
|
@@ -554,8 +610,10 @@ ${customCss}
|
|
|
554
610
|
if(s.logoSize==='small'){ logoImg.style.maxHeight='30px'; }
|
|
555
611
|
else if(s.logoSize==='medium'){ logoImg.style.maxHeight='50px'; }
|
|
556
612
|
else if(s.logoSize==='large'){ logoImg.style.maxHeight='70px'; }
|
|
557
|
-
|
|
558
|
-
|
|
613
|
+
// M\xE1rgenes l\xF3gicos: con un survey RTL el popup va con dir="rtl" y el logo
|
|
614
|
+
// tiene que acompa\xF1ar al chrome. En LTR el resultado es el mismo de antes.
|
|
615
|
+
if(s.logoPosition==='left'){ logoImg.style.margin='12px 0 0 0'; logoImg.style.setProperty('margin-inline-start','0'); logoImg.style.setProperty('margin-inline-end','16px'); }
|
|
616
|
+
else if(s.logoPosition==='right'){ logoImg.style.margin='12px 0 0 0'; logoImg.style.setProperty('margin-inline-start','auto'); logoImg.style.setProperty('margin-inline-end','0'); }
|
|
559
617
|
else if(s.logoPosition==='center'){ logoImg.style.margin='12px auto 0 auto'; }
|
|
560
618
|
// Encima de la barra de progreso, como hermano del header (espejo de ui/logo.ts en
|
|
561
619
|
// web). Fuera de #dd-main, as\xED el logo no se va con el scroll del formulario.
|
|
@@ -581,12 +639,12 @@ ${customCss}
|
|
|
581
639
|
setLoading(false);
|
|
582
640
|
if(error.toLowerCase().indexOf('no response')!==-1){
|
|
583
641
|
// La p\xE1gina no ha cambiado: el estado de navegaci\xF3n se queda como estaba.
|
|
584
|
-
errorHint.textContent=
|
|
642
|
+
errorHint.textContent=DD_LABELS_ACTIVE.errorRequired;
|
|
585
643
|
errorHint.style.display='block';
|
|
586
644
|
updateNavButtons();
|
|
587
645
|
return;
|
|
588
646
|
}
|
|
589
|
-
errorHint.textContent=
|
|
647
|
+
errorHint.textContent=DD_LABELS_ACTIVE.errorSubmit;
|
|
590
648
|
errorHint.style.display='block';
|
|
591
649
|
return;
|
|
592
650
|
}
|
|
@@ -658,7 +716,8 @@ var ReactNativePopupRenderer = class {
|
|
|
658
716
|
chrome: renderChrome,
|
|
659
717
|
title: options?.title,
|
|
660
718
|
showProgressBar: options?.showProgressBar,
|
|
661
|
-
surveyCss: options?.surveyCss
|
|
719
|
+
surveyCss: options?.surveyCss,
|
|
720
|
+
language: options?.language
|
|
662
721
|
});
|
|
663
722
|
if (this.options.onShow) {
|
|
664
723
|
this.options.onShow({ surveyId, productId, html });
|
|
@@ -754,7 +813,7 @@ var BrowserPopupRenderer = class {
|
|
|
754
813
|
if (!this.container) return;
|
|
755
814
|
this.visible = true;
|
|
756
815
|
const container = this.container;
|
|
757
|
-
void import("./renderPopup-
|
|
816
|
+
void import("./renderPopup-EWGKG53W.mjs").then(({ renderPopup }) => {
|
|
758
817
|
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
|
|
759
818
|
});
|
|
760
819
|
}
|
|
@@ -1506,6 +1565,75 @@ var CrashReporter = class {
|
|
|
1506
1565
|
}
|
|
1507
1566
|
};
|
|
1508
1567
|
|
|
1568
|
+
// src/core/popup-state-store.ts
|
|
1569
|
+
var POPUP_STATE_STORAGE_KEY = "deepdots.popups.state";
|
|
1570
|
+
var MAX_TRACKED_POPUP_ENTRIES = 200;
|
|
1571
|
+
function emptyState() {
|
|
1572
|
+
return { lastShown: {}, progress: {} };
|
|
1573
|
+
}
|
|
1574
|
+
function isValidTimestamp(value) {
|
|
1575
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
1576
|
+
}
|
|
1577
|
+
function capEntries(entries, timestampOf) {
|
|
1578
|
+
if (entries.length <= MAX_TRACKED_POPUP_ENTRIES) return entries;
|
|
1579
|
+
return [...entries].sort((a, b) => timestampOf(b[1]) - timestampOf(a[1])).slice(0, MAX_TRACKED_POPUP_ENTRIES);
|
|
1580
|
+
}
|
|
1581
|
+
function readPopupState(storage) {
|
|
1582
|
+
let raw = null;
|
|
1583
|
+
try {
|
|
1584
|
+
raw = storage.getItem(POPUP_STATE_STORAGE_KEY);
|
|
1585
|
+
} catch {
|
|
1586
|
+
return emptyState();
|
|
1587
|
+
}
|
|
1588
|
+
if (!raw) return emptyState();
|
|
1589
|
+
let parsed;
|
|
1590
|
+
try {
|
|
1591
|
+
parsed = JSON.parse(raw);
|
|
1592
|
+
} catch {
|
|
1593
|
+
return emptyState();
|
|
1594
|
+
}
|
|
1595
|
+
if (typeof parsed !== "object" || parsed === null) return emptyState();
|
|
1596
|
+
const source = parsed;
|
|
1597
|
+
const state = emptyState();
|
|
1598
|
+
if (typeof source.lastShown === "object" && source.lastShown !== null) {
|
|
1599
|
+
const valid = Object.entries(source.lastShown).filter((entry) => isValidTimestamp(entry[1]));
|
|
1600
|
+
capEntries(valid, (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
1601
|
+
state.lastShown[popupId] = timestamp;
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
if (typeof source.progress === "object" && source.progress !== null) {
|
|
1605
|
+
const valid = Object.entries(source.progress).filter((entry) => {
|
|
1606
|
+
const value = entry[1];
|
|
1607
|
+
if (typeof value !== "object" || value === null) return false;
|
|
1608
|
+
const candidate = value;
|
|
1609
|
+
return POPUP_TRIGGER_CONDITION_STATUSES.includes(candidate.status) && isValidTimestamp(candidate.timestamp);
|
|
1610
|
+
});
|
|
1611
|
+
capEntries(valid, (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
1612
|
+
state.progress[surveyId] = { status: entry.status, timestamp: entry.timestamp };
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
return state;
|
|
1616
|
+
}
|
|
1617
|
+
function writePopupState(storage, state) {
|
|
1618
|
+
const capped = emptyState();
|
|
1619
|
+
capEntries(Object.entries(state.lastShown), (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
|
|
1620
|
+
capped.lastShown[popupId] = timestamp;
|
|
1621
|
+
});
|
|
1622
|
+
capEntries(Object.entries(state.progress), (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
|
|
1623
|
+
capped.progress[surveyId] = entry;
|
|
1624
|
+
});
|
|
1625
|
+
try {
|
|
1626
|
+
storage.setItem(POPUP_STATE_STORAGE_KEY, JSON.stringify(capped));
|
|
1627
|
+
} catch {
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
function clearPopupState(storage) {
|
|
1631
|
+
try {
|
|
1632
|
+
storage.removeItem(POPUP_STATE_STORAGE_KEY);
|
|
1633
|
+
} catch {
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1509
1637
|
// src/analytics/messaging.ts
|
|
1510
1638
|
var MESSAGE_CHANNELS = ["push", "in_app"];
|
|
1511
1639
|
function buildMessageParams(stage, o) {
|
|
@@ -1593,6 +1721,10 @@ var DeepdotsPopups = class {
|
|
|
1593
1721
|
this.popupDefinitions = [];
|
|
1594
1722
|
this.popupsLoaded = false;
|
|
1595
1723
|
this.pendingAutoLaunch = false;
|
|
1724
|
+
// Estado que alimenta las reglas de redisplay. Copia de trabajo en memoria; la fuente
|
|
1725
|
+
// duradera es el storage (`popup-state-store`), rehidratada en `init()` — sin eso, una
|
|
1726
|
+
// recarga reiniciaba el cooldown y el popup volvía a salir. `answeredSurveys` se deriva
|
|
1727
|
+
// de las entradas COMPLETED de `surveyProgress` (los dos los escribe `markSurveyAnswered`).
|
|
1596
1728
|
this.answeredSurveys = /* @__PURE__ */ new Set();
|
|
1597
1729
|
this.surveyProgress = /* @__PURE__ */ new Map();
|
|
1598
1730
|
this.lastShown = /* @__PURE__ */ new Map();
|
|
@@ -1668,6 +1800,7 @@ var DeepdotsPopups = class {
|
|
|
1668
1800
|
};
|
|
1669
1801
|
const storage = config.storage ?? createDefaultStorage();
|
|
1670
1802
|
this.storage = storage;
|
|
1803
|
+
this.loadPopupState(storage);
|
|
1671
1804
|
this.tracking = new TrackingManager({
|
|
1672
1805
|
storage,
|
|
1673
1806
|
clientUserId: this.config.userId,
|
|
@@ -1935,6 +2068,10 @@ var DeepdotsPopups = class {
|
|
|
1935
2068
|
}) : null;
|
|
1936
2069
|
this.analytics?.resetUserScope();
|
|
1937
2070
|
this.messageGuard.reset();
|
|
2071
|
+
this.lastShown.clear();
|
|
2072
|
+
this.surveyProgress.clear();
|
|
2073
|
+
this.answeredSurveys.clear();
|
|
2074
|
+
clearPopupState(storage);
|
|
1938
2075
|
this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
|
|
1939
2076
|
this.openSession();
|
|
1940
2077
|
}
|
|
@@ -2106,6 +2243,7 @@ var DeepdotsPopups = class {
|
|
|
2106
2243
|
this.log("Showing popup (definition)", def);
|
|
2107
2244
|
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
2108
2245
|
this.lastShown.set(def.id, Date.now());
|
|
2246
|
+
this.persistPopupState();
|
|
2109
2247
|
this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
|
|
2110
2248
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
2111
2249
|
}
|
|
@@ -2464,13 +2602,13 @@ var DeepdotsPopups = class {
|
|
|
2464
2602
|
miniService,
|
|
2465
2603
|
analyticsFeedbackSessionId,
|
|
2466
2604
|
this.renderChrome,
|
|
2467
|
-
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
|
|
2605
|
+
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss, language: this.language }
|
|
2468
2606
|
);
|
|
2469
2607
|
return;
|
|
2470
2608
|
}
|
|
2471
2609
|
if (!this.popupContainer) return;
|
|
2472
2610
|
const container = this.popupContainer;
|
|
2473
|
-
void import("./renderPopup-
|
|
2611
|
+
void import("./renderPopup-EWGKG53W.mjs").then(({ renderPopup }) => {
|
|
2474
2612
|
renderPopup(
|
|
2475
2613
|
container,
|
|
2476
2614
|
surveyId,
|
|
@@ -2484,7 +2622,7 @@ var DeepdotsPopups = class {
|
|
|
2484
2622
|
sessionId,
|
|
2485
2623
|
miniService,
|
|
2486
2624
|
analyticsFeedbackSessionId,
|
|
2487
|
-
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
|
|
2625
|
+
{ title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss, language: this.language }
|
|
2488
2626
|
);
|
|
2489
2627
|
});
|
|
2490
2628
|
}
|
|
@@ -2585,6 +2723,29 @@ var DeepdotsPopups = class {
|
|
|
2585
2723
|
return;
|
|
2586
2724
|
}
|
|
2587
2725
|
this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
|
|
2726
|
+
this.persistPopupState();
|
|
2727
|
+
}
|
|
2728
|
+
/**
|
|
2729
|
+
* Rehidrata el estado de redisplay desde el storage. `answeredSurveys` se reconstruye
|
|
2730
|
+
* desde las entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
2731
|
+
*/
|
|
2732
|
+
loadPopupState(storage) {
|
|
2733
|
+
const state = readPopupState(storage);
|
|
2734
|
+
Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
|
|
2735
|
+
this.lastShown.set(popupId, timestamp);
|
|
2736
|
+
});
|
|
2737
|
+
Object.entries(state.progress).forEach(([surveyId, entry]) => {
|
|
2738
|
+
this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
|
|
2739
|
+
if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
|
|
2740
|
+
});
|
|
2741
|
+
}
|
|
2742
|
+
/** Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria. */
|
|
2743
|
+
persistPopupState() {
|
|
2744
|
+
if (!this.storage) return;
|
|
2745
|
+
writePopupState(this.storage, {
|
|
2746
|
+
lastShown: Object.fromEntries(this.lastShown),
|
|
2747
|
+
progress: Object.fromEntries(this.surveyProgress)
|
|
2748
|
+
});
|
|
2588
2749
|
}
|
|
2589
2750
|
isPopupDefinition(value) {
|
|
2590
2751
|
if (typeof value !== "object" || value === null) return false;
|