@magicfeedback/popup-sdk 1.0.9 → 1.0.11
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 +19 -16
- package/dist/index.d.mts +20 -13
- package/dist/index.d.ts +20 -13
- package/dist/index.js +300 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +300 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1774,7 +1774,7 @@ function ensureResponsiveStyles(popup) {
|
|
|
1774
1774
|
`;
|
|
1775
1775
|
popup.appendChild(style);
|
|
1776
1776
|
}
|
|
1777
|
-
async function renderPopup(container, surveyId, productId, actions, emit, onClose) {
|
|
1777
|
+
async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production") {
|
|
1778
1778
|
let surveyCompletedEmitted = false;
|
|
1779
1779
|
let stylesInjected = false;
|
|
1780
1780
|
const popup = document.createElement("div");
|
|
@@ -1799,7 +1799,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
1799
1799
|
closeBtn.type = "button";
|
|
1800
1800
|
closeBtn.setAttribute("aria-label", "Close popup");
|
|
1801
1801
|
closeBtn.innerHTML = `
|
|
1802
|
-
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"
|
|
1802
|
+
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1803
1803
|
<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1804
1804
|
</svg>
|
|
1805
1805
|
`;
|
|
@@ -1850,6 +1850,20 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
1850
1850
|
main.style.cssText = "display:flex; flex-direction:column; width:100%; max-height:80vh; overflow-y:auto;";
|
|
1851
1851
|
const formWrapper = document.createElement("div");
|
|
1852
1852
|
formWrapper.style.cssText = "width:100%; flex: 1 1 auto;";
|
|
1853
|
+
const errorHint = document.createElement("div");
|
|
1854
|
+
errorHint.className = "deepdots-error-hint";
|
|
1855
|
+
errorHint.style.cssText = `
|
|
1856
|
+
display: none;
|
|
1857
|
+
margin: 12px 0 0 0;
|
|
1858
|
+
padding: 10px 12px;
|
|
1859
|
+
border-radius: 6px;
|
|
1860
|
+
background: #FEF3C7; /* amber-100 */
|
|
1861
|
+
color: #92400E; /* amber-700 */
|
|
1862
|
+
border: 1px solid #FCD34D; /* amber-300 */
|
|
1863
|
+
font-size: 13px;
|
|
1864
|
+
`;
|
|
1865
|
+
errorHint.setAttribute("role", "alert");
|
|
1866
|
+
errorHint.setAttribute("aria-live", "polite");
|
|
1853
1867
|
const spinnerEl = document.createElement("div");
|
|
1854
1868
|
spinnerEl.className = "mf-spinner";
|
|
1855
1869
|
spinnerEl.setAttribute("role", "status");
|
|
@@ -1863,6 +1877,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
1863
1877
|
formWrapper.appendChild(spinnerEl);
|
|
1864
1878
|
formWrapper.appendChild(formHost);
|
|
1865
1879
|
main.appendChild(formWrapper);
|
|
1880
|
+
main.appendChild(errorHint);
|
|
1866
1881
|
const footer = document.createElement("div");
|
|
1867
1882
|
footer.className = "deepdots-popup-footer";
|
|
1868
1883
|
footer.setAttribute("data-actions-wrapper", "true");
|
|
@@ -2007,7 +2022,6 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2007
2022
|
setLoading(false);
|
|
2008
2023
|
break;
|
|
2009
2024
|
case "error":
|
|
2010
|
-
closeButton.style.display = "inline-flex";
|
|
2011
2025
|
setLoading(false);
|
|
2012
2026
|
break;
|
|
2013
2027
|
}
|
|
@@ -2044,13 +2058,13 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2044
2058
|
setLoading(false);
|
|
2045
2059
|
return;
|
|
2046
2060
|
}
|
|
2047
|
-
import_native.default.init({ debug: true, env: "prod" });
|
|
2061
|
+
import_native.default.init({ debug: true, env: env === "production" ? "prod" : "dev" });
|
|
2048
2062
|
formInstance = import_native.default.form(surveyId, productId);
|
|
2049
2063
|
const generateOptions = {
|
|
2050
2064
|
addButton: false,
|
|
2051
2065
|
getMetaData: true
|
|
2052
2066
|
};
|
|
2053
|
-
generateOptions.onLoadedEvent = ({ formData
|
|
2067
|
+
generateOptions.onLoadedEvent = ({ formData }) => {
|
|
2054
2068
|
try {
|
|
2055
2069
|
} catch (e) {
|
|
2056
2070
|
}
|
|
@@ -2136,11 +2150,23 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
|
|
|
2136
2150
|
emit("popup_clicked", surveyId, { action: "before_submit" });
|
|
2137
2151
|
};
|
|
2138
2152
|
generateOptions.afterSubmitEvent = ({ error, completed, total, progress }) => {
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2153
|
+
const errText = error ? typeof error === "string" ? error : error.message ?? String(error) : "";
|
|
2154
|
+
if (errText) {
|
|
2155
|
+
setLoading(false);
|
|
2156
|
+
if (errText.toLowerCase().includes("no response")) {
|
|
2157
|
+
errorHint.textContent = "Please answer the required question to continue.";
|
|
2158
|
+
errorHint.style.display = "block";
|
|
2159
|
+
emit("popup_clicked", surveyId, { action: "validation_error_required" });
|
|
2160
|
+
updateButtons("in_progress_next");
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
errorHint.textContent = "An error occurred while submitting. Please try again or close the popup.";
|
|
2164
|
+
errorHint.style.display = "block";
|
|
2165
|
+
emit("popup_clicked", surveyId, { action: "submit_error", error: errText });
|
|
2142
2166
|
return;
|
|
2143
2167
|
}
|
|
2168
|
+
errorHint.style.display = "none";
|
|
2169
|
+
setLoading(false);
|
|
2144
2170
|
if (completed) {
|
|
2145
2171
|
emit("survey_completed", surveyId, { action: "completed" });
|
|
2146
2172
|
surveyCompletedEmitted = true;
|
|
@@ -2183,6 +2209,9 @@ function setupTrigger(popups, trigger) {
|
|
|
2183
2209
|
case "exit":
|
|
2184
2210
|
setupExitTrigger(popups, trigger);
|
|
2185
2211
|
break;
|
|
2212
|
+
case "click":
|
|
2213
|
+
setupClickTrigger(popups, trigger);
|
|
2214
|
+
break;
|
|
2186
2215
|
}
|
|
2187
2216
|
}
|
|
2188
2217
|
function setupTimeTrigger(popups, trigger) {
|
|
@@ -2205,23 +2234,120 @@ function setupScrollTrigger(popups, trigger) {
|
|
|
2205
2234
|
popups.debug(`Scroll trigger set for ${threshold}%`);
|
|
2206
2235
|
}
|
|
2207
2236
|
function setupExitTrigger(popups, trigger) {
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2237
|
+
let fired = false;
|
|
2238
|
+
let lastUrl = typeof window !== "undefined" ? window.location.href : "";
|
|
2239
|
+
const historyRef = typeof window !== "undefined" ? window.history : null;
|
|
2240
|
+
const originalPushState = historyRef ? historyRef.pushState.bind(historyRef) : null;
|
|
2241
|
+
const originalReplaceState = historyRef ? historyRef.replaceState.bind(historyRef) : null;
|
|
2242
|
+
const cleanup = () => {
|
|
2243
|
+
document.removeEventListener("click", handleNavClick, true);
|
|
2244
|
+
window.removeEventListener("popstate", handlePopState);
|
|
2245
|
+
if (historyRef && originalPushState) historyRef.pushState = originalPushState;
|
|
2246
|
+
if (historyRef && originalReplaceState) historyRef.replaceState = originalReplaceState;
|
|
2247
|
+
};
|
|
2248
|
+
const fireOnce = () => {
|
|
2249
|
+
if (fired) return;
|
|
2250
|
+
fired = true;
|
|
2251
|
+
popups.triggerSurvey(trigger.surveyId);
|
|
2252
|
+
cleanup();
|
|
2253
|
+
};
|
|
2254
|
+
const handleNavClick = (e) => {
|
|
2255
|
+
if (fired) return;
|
|
2256
|
+
if (e.defaultPrevented) return;
|
|
2257
|
+
if (e.button !== 0) return;
|
|
2258
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
2259
|
+
const target = e.target?.closest?.("a");
|
|
2260
|
+
if (!target) return;
|
|
2261
|
+
const href = target.getAttribute("href");
|
|
2262
|
+
if (!href || href.startsWith("#")) return;
|
|
2263
|
+
const targetAttr = target.getAttribute("target");
|
|
2264
|
+
if (targetAttr && targetAttr !== "_self") return;
|
|
2265
|
+
let url;
|
|
2266
|
+
try {
|
|
2267
|
+
url = new URL(href, window.location.href);
|
|
2268
|
+
} catch {
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2271
|
+
if (url.origin !== window.location.origin) return;
|
|
2272
|
+
e.preventDefault();
|
|
2273
|
+
fireOnce();
|
|
2274
|
+
};
|
|
2275
|
+
const shouldBlockUrl = (rawUrl) => {
|
|
2276
|
+
if (!rawUrl) return false;
|
|
2277
|
+
let url;
|
|
2278
|
+
try {
|
|
2279
|
+
url = rawUrl instanceof URL ? rawUrl : new URL(rawUrl, window.location.href);
|
|
2280
|
+
} catch {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
if (url.origin !== window.location.origin) return false;
|
|
2284
|
+
if (url.href === window.location.href) return false;
|
|
2285
|
+
return true;
|
|
2286
|
+
};
|
|
2287
|
+
const handlePopState = () => {
|
|
2288
|
+
if (fired) return;
|
|
2289
|
+
fireOnce();
|
|
2290
|
+
if (historyRef && originalPushState && lastUrl) {
|
|
2291
|
+
originalPushState(null, document.title, lastUrl);
|
|
2212
2292
|
}
|
|
2213
2293
|
};
|
|
2214
|
-
|
|
2215
|
-
|
|
2294
|
+
if (historyRef && originalPushState && originalReplaceState) {
|
|
2295
|
+
historyRef.pushState = function(data, unused, url) {
|
|
2296
|
+
if (!fired && shouldBlockUrl(url)) {
|
|
2297
|
+
fireOnce();
|
|
2298
|
+
return;
|
|
2299
|
+
}
|
|
2300
|
+
const result = originalPushState(data, unused, url);
|
|
2301
|
+
lastUrl = window.location.href;
|
|
2302
|
+
return result;
|
|
2303
|
+
};
|
|
2304
|
+
historyRef.replaceState = function(data, unused, url) {
|
|
2305
|
+
if (!fired && shouldBlockUrl(url)) {
|
|
2306
|
+
fireOnce();
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
const result = originalReplaceState(data, unused, url);
|
|
2310
|
+
lastUrl = window.location.href;
|
|
2311
|
+
return result;
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
document.addEventListener("click", handleNavClick, true);
|
|
2315
|
+
window.addEventListener("popstate", handlePopState);
|
|
2316
|
+
popups.debug("Exit intent trigger set (navigation/spa)");
|
|
2317
|
+
}
|
|
2318
|
+
function setupClickTrigger(popups, trigger) {
|
|
2319
|
+
const targetId = typeof trigger.value === "string" ? trigger.value : "";
|
|
2320
|
+
if (!targetId) {
|
|
2321
|
+
popups.debug("Click trigger missing element id", trigger);
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
const attach = () => {
|
|
2325
|
+
const el = document.getElementById(targetId);
|
|
2326
|
+
if (!el) {
|
|
2327
|
+
popups.debug("Click trigger target not found", targetId);
|
|
2328
|
+
return false;
|
|
2329
|
+
}
|
|
2330
|
+
const handler = (e) => {
|
|
2331
|
+
if (e.defaultPrevented) return;
|
|
2332
|
+
popups.triggerSurvey(trigger.surveyId);
|
|
2333
|
+
el.removeEventListener("click", handler);
|
|
2334
|
+
};
|
|
2335
|
+
el.addEventListener("click", handler);
|
|
2336
|
+
popups.debug(`Click trigger set for #${targetId}`);
|
|
2337
|
+
return true;
|
|
2338
|
+
};
|
|
2339
|
+
if (typeof document === "undefined") return;
|
|
2340
|
+
if (attach()) return;
|
|
2341
|
+
window.addEventListener("DOMContentLoaded", () => attach(), { once: true });
|
|
2216
2342
|
}
|
|
2217
2343
|
|
|
2218
2344
|
// src/config/env.ts
|
|
2219
2345
|
var ENVIRONMENT_MAP = {
|
|
2220
2346
|
development: {
|
|
2221
|
-
apiBaseUrl: "https://api-dev.
|
|
2347
|
+
apiBaseUrl: "https://api-dev.deepdots.com"
|
|
2222
2348
|
},
|
|
2223
2349
|
production: {
|
|
2224
|
-
apiBaseUrl: "https://api.
|
|
2350
|
+
apiBaseUrl: "https://api.deepdots.com"
|
|
2225
2351
|
}
|
|
2226
2352
|
};
|
|
2227
2353
|
function resolveEnvironment(nodeEnv) {
|
|
@@ -2303,10 +2429,10 @@ var BrowserPopupRenderer = class {
|
|
|
2303
2429
|
document.body.appendChild(this.container);
|
|
2304
2430
|
}
|
|
2305
2431
|
}
|
|
2306
|
-
show(surveyId, productId, actions, emit, onClose) {
|
|
2432
|
+
show(surveyId, productId, actions, emit, onClose, env = "production") {
|
|
2307
2433
|
if (!this.container) this.init();
|
|
2308
2434
|
if (!this.container) return;
|
|
2309
|
-
renderPopup(this.container, surveyId, productId, actions, emit, onClose);
|
|
2435
|
+
renderPopup(this.container, surveyId, productId, actions, emit, onClose, env);
|
|
2310
2436
|
}
|
|
2311
2437
|
hide() {
|
|
2312
2438
|
if (this.container) {
|
|
@@ -2339,8 +2465,12 @@ var DeepdotsPopups = class {
|
|
|
2339
2465
|
this.pendingAutoLaunch = false;
|
|
2340
2466
|
this.answeredSurveys = /* @__PURE__ */ new Set();
|
|
2341
2467
|
this.lastShown = /* @__PURE__ */ new Map();
|
|
2468
|
+
// popupId -> timestamp mostrado
|
|
2469
|
+
this.surveyToPopupId = /* @__PURE__ */ new Map();
|
|
2470
|
+
// surveyId -> popupId
|
|
2471
|
+
this.baseUrl = "";
|
|
2472
|
+
this.env = "production";
|
|
2342
2473
|
}
|
|
2343
|
-
// popupId -> timestamp mostrado
|
|
2344
2474
|
/** Initialize the SDK with configuration */
|
|
2345
2475
|
init(config) {
|
|
2346
2476
|
if (this.initialized) {
|
|
@@ -2348,12 +2478,14 @@ var DeepdotsPopups = class {
|
|
|
2348
2478
|
return;
|
|
2349
2479
|
}
|
|
2350
2480
|
const env = resolveEnvironment(config.nodeEnv);
|
|
2481
|
+
this.baseUrl = env.apiBaseUrl;
|
|
2482
|
+
this.env = config.nodeEnv || "production";
|
|
2351
2483
|
this.config = {
|
|
2352
2484
|
apiKey: config.apiKey || void 0,
|
|
2353
|
-
baseUrl: env.apiBaseUrl,
|
|
2354
2485
|
mode: config.mode || "client",
|
|
2355
2486
|
debug: config.debug || false,
|
|
2356
|
-
popups: config.popups || []
|
|
2487
|
+
popups: config.popups || [],
|
|
2488
|
+
userId: config.userId || void 0
|
|
2357
2489
|
};
|
|
2358
2490
|
this.initialized = true;
|
|
2359
2491
|
this.log("SDK initialized", this.config);
|
|
@@ -2402,8 +2534,9 @@ var DeepdotsPopups = class {
|
|
|
2402
2534
|
if (isDefinition) {
|
|
2403
2535
|
const def = options;
|
|
2404
2536
|
this.log("Showing popup (definition)", def);
|
|
2537
|
+
this.surveyToPopupId.set(def.surveyId, def.id);
|
|
2405
2538
|
this.renderPopup(def.surveyId, def.productId, def.actions);
|
|
2406
|
-
this.emitEvent("popup_shown", def.surveyId);
|
|
2539
|
+
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
2407
2540
|
} else {
|
|
2408
2541
|
const opt = options;
|
|
2409
2542
|
this.log("Showing popup (legacy options)", opt);
|
|
@@ -2432,9 +2565,10 @@ var DeepdotsPopups = class {
|
|
|
2432
2565
|
configureTriggersFromDefinitions() {
|
|
2433
2566
|
const derived = [];
|
|
2434
2567
|
const validDefs = this.validatePopupDefinitions(this.popupDefinitions);
|
|
2568
|
+
console.log("validDefs", validDefs);
|
|
2435
2569
|
validDefs.forEach((def) => {
|
|
2436
|
-
if (!def.
|
|
2437
|
-
const t = def.
|
|
2570
|
+
if (!def.triggers) return;
|
|
2571
|
+
const t = def.triggers;
|
|
2438
2572
|
let type;
|
|
2439
2573
|
switch (t.type) {
|
|
2440
2574
|
case "time_on_page":
|
|
@@ -2446,11 +2580,14 @@ var DeepdotsPopups = class {
|
|
|
2446
2580
|
case "exit":
|
|
2447
2581
|
type = "exit";
|
|
2448
2582
|
break;
|
|
2583
|
+
case "click":
|
|
2584
|
+
type = "click";
|
|
2585
|
+
break;
|
|
2449
2586
|
default:
|
|
2450
2587
|
this.debug("Unsupported trigger type", t.type);
|
|
2451
2588
|
return;
|
|
2452
2589
|
}
|
|
2453
|
-
const value = type === "time" ? t.value * 1e3 : t.value;
|
|
2590
|
+
const value = type === "time" && typeof t.value === "number" ? t.value * 1e3 : t.value;
|
|
2454
2591
|
derived.push({ type, value, surveyId: def.surveyId });
|
|
2455
2592
|
});
|
|
2456
2593
|
if (derived.length) {
|
|
@@ -2472,10 +2609,52 @@ var DeepdotsPopups = class {
|
|
|
2472
2609
|
this.lastShown.set(def.id, Date.now());
|
|
2473
2610
|
}
|
|
2474
2611
|
shouldShow(def) {
|
|
2475
|
-
|
|
2612
|
+
if (!this.matchesSegmentsPath(def)) {
|
|
2613
|
+
return false;
|
|
2614
|
+
}
|
|
2615
|
+
const conditions = def.triggers.condition || [];
|
|
2476
2616
|
if (!conditions.length) return true;
|
|
2477
2617
|
return conditions.every((c) => this.evaluateCondition(def, c));
|
|
2478
2618
|
}
|
|
2619
|
+
matchesSegmentsPath(def) {
|
|
2620
|
+
const paths = def.segments?.path;
|
|
2621
|
+
if (!paths || paths.length === 0) return true;
|
|
2622
|
+
if (typeof window === "undefined" || !window.location) {
|
|
2623
|
+
this.debug("No window.location available for path comparison", { popupId: def.id, paths });
|
|
2624
|
+
return true;
|
|
2625
|
+
}
|
|
2626
|
+
const currentPath = window.location.pathname || "";
|
|
2627
|
+
const currentHref = window.location.href || "";
|
|
2628
|
+
const normalize = (value) => {
|
|
2629
|
+
if (value.length > 1 && value.endsWith("/")) return value.slice(0, -1);
|
|
2630
|
+
return value;
|
|
2631
|
+
};
|
|
2632
|
+
const normalizedPath = normalize(currentPath);
|
|
2633
|
+
const normalizedHref = normalize(currentHref);
|
|
2634
|
+
const matches = paths.some((rawCandidate) => {
|
|
2635
|
+
const candidate = normalize(rawCandidate);
|
|
2636
|
+
let match = false;
|
|
2637
|
+
if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
|
|
2638
|
+
match = normalizedHref === candidate;
|
|
2639
|
+
} else if (candidate.startsWith("/")) {
|
|
2640
|
+
match = normalizedHref.includes(candidate);
|
|
2641
|
+
} else {
|
|
2642
|
+
match = normalizedPath === candidate;
|
|
2643
|
+
}
|
|
2644
|
+
this.debug("Path comparison", {
|
|
2645
|
+
popupId: def.id,
|
|
2646
|
+
candidate,
|
|
2647
|
+
currentPath: normalizedPath,
|
|
2648
|
+
currentHref: normalizedHref,
|
|
2649
|
+
match
|
|
2650
|
+
});
|
|
2651
|
+
return match;
|
|
2652
|
+
});
|
|
2653
|
+
if (!matches) {
|
|
2654
|
+
this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
|
|
2655
|
+
}
|
|
2656
|
+
return matches;
|
|
2657
|
+
}
|
|
2479
2658
|
evaluateCondition(def, condition) {
|
|
2480
2659
|
if (!condition.answered && this.answeredSurveys.has(def.surveyId)) {
|
|
2481
2660
|
return false;
|
|
@@ -2494,29 +2673,59 @@ var DeepdotsPopups = class {
|
|
|
2494
2673
|
markSurveyAnswered(surveyId) {
|
|
2495
2674
|
this.answeredSurveys.add(surveyId);
|
|
2496
2675
|
}
|
|
2497
|
-
/**
|
|
2676
|
+
/** Fetch al servidor para obtener popups */
|
|
2498
2677
|
async fetchPopupsFromServer() {
|
|
2499
|
-
|
|
2500
|
-
|
|
2678
|
+
const apiKey = this.config?.apiKey;
|
|
2679
|
+
const baseUrl = this.baseUrl;
|
|
2680
|
+
if (!apiKey || !baseUrl) {
|
|
2681
|
+
this.log("Missing apiKey or baseUrl. Skipping popups fetch.");
|
|
2682
|
+
return [];
|
|
2683
|
+
}
|
|
2684
|
+
const endpoint = `${baseUrl}/sdk/${encodeURIComponent(apiKey)}/popups`;
|
|
2685
|
+
try {
|
|
2686
|
+
const response = await fetch(endpoint);
|
|
2687
|
+
if (!response.ok) {
|
|
2688
|
+
this.log("Failed to fetch popups", response.status, response.statusText);
|
|
2689
|
+
return [];
|
|
2690
|
+
}
|
|
2691
|
+
const raw = await response.text();
|
|
2692
|
+
const parsed = JSON.parse(raw);
|
|
2693
|
+
if (!Array.isArray(parsed)) {
|
|
2694
|
+
this.log("Unexpected popups payload", parsed);
|
|
2695
|
+
return [];
|
|
2696
|
+
}
|
|
2697
|
+
console.log("res: ", parsed, this.validatePopupDefinitions(parsed));
|
|
2698
|
+
return parsed;
|
|
2699
|
+
} catch (error) {
|
|
2700
|
+
this.log("Error fetching popups", error);
|
|
2701
|
+
return [];
|
|
2702
|
+
}
|
|
2501
2703
|
}
|
|
2502
|
-
/**
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
},
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2704
|
+
/** Notifica eventos de popup a la API */
|
|
2705
|
+
async postPopupEvent(status, popupId, userId) {
|
|
2706
|
+
const apiKey = this.config?.apiKey;
|
|
2707
|
+
const baseUrl = this.baseUrl;
|
|
2708
|
+
if (!apiKey || !baseUrl) {
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2711
|
+
const endpoint = `${baseUrl}/sdk/popups`;
|
|
2712
|
+
try {
|
|
2713
|
+
const response = await fetch(endpoint, {
|
|
2714
|
+
method: "POST",
|
|
2715
|
+
headers: { "Content-Type": "application/json" },
|
|
2716
|
+
body: JSON.stringify({
|
|
2717
|
+
publicKey: apiKey,
|
|
2718
|
+
status,
|
|
2719
|
+
popupId,
|
|
2720
|
+
userId: userId || void 0
|
|
2721
|
+
})
|
|
2722
|
+
});
|
|
2723
|
+
if (!response.ok) {
|
|
2724
|
+
this.log("Failed to post popup event", response.status, response.statusText);
|
|
2518
2725
|
}
|
|
2519
|
-
|
|
2726
|
+
} catch (error) {
|
|
2727
|
+
this.log("Error posting popup event", error);
|
|
2728
|
+
}
|
|
2520
2729
|
}
|
|
2521
2730
|
/** Add an event listener */
|
|
2522
2731
|
on(eventType, listener) {
|
|
@@ -2556,11 +2765,26 @@ var DeepdotsPopups = class {
|
|
|
2556
2765
|
/** Render the popup UI */
|
|
2557
2766
|
renderPopup(surveyId, productId, actions) {
|
|
2558
2767
|
if (this.renderer) {
|
|
2559
|
-
this.renderer.show(
|
|
2768
|
+
this.renderer.show(
|
|
2769
|
+
surveyId,
|
|
2770
|
+
productId,
|
|
2771
|
+
actions,
|
|
2772
|
+
(type, id, payload) => this.emitEvent(type, id, payload),
|
|
2773
|
+
() => this.hidePopup(),
|
|
2774
|
+
this.env
|
|
2775
|
+
);
|
|
2560
2776
|
return;
|
|
2561
2777
|
}
|
|
2562
2778
|
if (!this.popupContainer) return;
|
|
2563
|
-
renderPopup(
|
|
2779
|
+
renderPopup(
|
|
2780
|
+
this.popupContainer,
|
|
2781
|
+
surveyId,
|
|
2782
|
+
productId,
|
|
2783
|
+
actions,
|
|
2784
|
+
(type, id, payload) => this.emitEvent(type, id, payload),
|
|
2785
|
+
() => this.hidePopup(),
|
|
2786
|
+
this.env
|
|
2787
|
+
);
|
|
2564
2788
|
}
|
|
2565
2789
|
/** Hide the popup */
|
|
2566
2790
|
hidePopup() {
|
|
@@ -2580,6 +2804,16 @@ var DeepdotsPopups = class {
|
|
|
2580
2804
|
if (type === "survey_completed") {
|
|
2581
2805
|
this.markSurveyAnswered(surveyId);
|
|
2582
2806
|
}
|
|
2807
|
+
if (type === "popup_shown" || type === "survey_completed") {
|
|
2808
|
+
const popupIdFromData = data?.popupId;
|
|
2809
|
+
const popupId = popupIdFromData || this.surveyToPopupId.get(surveyId);
|
|
2810
|
+
if (popupId) {
|
|
2811
|
+
const userIdFromData = data?.userId;
|
|
2812
|
+
void this.postPopupEvent(type === "popup_shown" ? "opened" : "completed", popupId, userIdFromData || this.config?.userId);
|
|
2813
|
+
} else {
|
|
2814
|
+
this.debug("No popupId available to post event", { type, surveyId });
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2583
2817
|
const listeners = this.listeners.get(type);
|
|
2584
2818
|
if (listeners) {
|
|
2585
2819
|
listeners.forEach((listener) => {
|
|
@@ -2612,10 +2846,26 @@ var DeepdotsPopups = class {
|
|
|
2612
2846
|
isPopupDefinition(value) {
|
|
2613
2847
|
if (typeof value !== "object" || value === null) return false;
|
|
2614
2848
|
const v = value;
|
|
2615
|
-
|
|
2849
|
+
const trigger = v.triggers || v.triggers;
|
|
2850
|
+
if (!trigger) return false;
|
|
2851
|
+
return typeof v.id === "string" && typeof v.title === "string" && typeof v.message === "string" && typeof v.surveyId === "string" && typeof v.productId === "string";
|
|
2852
|
+
}
|
|
2853
|
+
normalizePopupDefinition(def) {
|
|
2854
|
+
if (typeof def !== "object" || def === null) return null;
|
|
2855
|
+
const raw = def;
|
|
2856
|
+
const trigger = raw.triggers || raw.triggers;
|
|
2857
|
+
if (!trigger) return null;
|
|
2858
|
+
const condition = trigger.condition ?? raw.conditions ?? [];
|
|
2859
|
+
return {
|
|
2860
|
+
...raw,
|
|
2861
|
+
triggers: {
|
|
2862
|
+
...trigger,
|
|
2863
|
+
condition
|
|
2864
|
+
}
|
|
2865
|
+
};
|
|
2616
2866
|
}
|
|
2617
2867
|
validatePopupDefinitions(defs) {
|
|
2618
|
-
return defs.filter((
|
|
2868
|
+
return defs.map((def) => this.normalizePopupDefinition(def)).filter((def) => !!def && this.isPopupDefinition(def));
|
|
2619
2869
|
}
|
|
2620
2870
|
};
|
|
2621
2871
|
export {
|