@active-reach/web-sdk 1.28.0 → 1.30.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/dist/aegis-push.min.js +2 -0
- package/dist/aegis-push.min.js.map +1 -0
- package/dist/aegis.min.js +1 -1
- package/dist/aegis.min.js.map +1 -1
- package/dist/inapp/AegisInAppManager.d.ts +37 -3
- package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
- package/dist/inapp/actions.d.ts +76 -0
- package/dist/inapp/actions.d.ts.map +1 -0
- package/dist/inapp/index.d.ts +2 -0
- package/dist/inapp/index.d.ts.map +1 -1
- package/dist/inapp/renderers/card-style.d.ts +3 -0
- package/dist/inapp/renderers/card-style.d.ts.map +1 -1
- package/dist/inapp/renderers/card-template.d.ts +27 -6
- package/dist/inapp/renderers/card-template.d.ts.map +1 -1
- package/dist/inapp/renderers/carousel-cards.d.ts.map +1 -1
- package/dist/inapp/renderers/index.d.ts +2 -0
- package/dist/inapp/renderers/index.d.ts.map +1 -1
- package/dist/inapp/renderers/product-recommendation.d.ts.map +1 -1
- package/dist/inapp/renderers/reviews.d.ts +38 -0
- package/dist/inapp/renderers/reviews.d.ts.map +1 -0
- package/dist/inapp/renderers/types.d.ts +8 -0
- package/dist/inapp/renderers/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +897 -262
- package/dist/index.js.map +1 -1
- package/dist/push/cdn-push.d.ts +21 -0
- package/dist/push/cdn-push.d.ts.map +1 -0
- package/dist/runtime/AegisMessageRuntime.d.ts +10 -1
- package/dist/runtime/AegisMessageRuntime.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -25,6 +25,94 @@ function throttle(func, limit) {
|
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
const PDP_SKU_RE = /\/p\/([^/?#]+)/;
|
|
29
|
+
function parseAction(actionUrl, meta) {
|
|
30
|
+
const url = (actionUrl ?? "").trim();
|
|
31
|
+
const m2 = meta ?? {};
|
|
32
|
+
if (url.startsWith("aegis://")) {
|
|
33
|
+
const rest = url.slice("aegis://".length);
|
|
34
|
+
const [verb, qs] = rest.split("?");
|
|
35
|
+
const params = new URLSearchParams(qs || "");
|
|
36
|
+
switch (verb) {
|
|
37
|
+
case "dismiss":
|
|
38
|
+
return { type: "dismiss" };
|
|
39
|
+
case "request-push":
|
|
40
|
+
case "request_push":
|
|
41
|
+
return { type: "request_push" };
|
|
42
|
+
case "cart-add":
|
|
43
|
+
case "add-to-cart":
|
|
44
|
+
return {
|
|
45
|
+
type: "add_to_cart",
|
|
46
|
+
sku: params.get("sku") || m2.sku || void 0,
|
|
47
|
+
productId: params.get("product_id") || m2.product_id || void 0,
|
|
48
|
+
platformProductId: m2.platform_product_id,
|
|
49
|
+
qty: Number(params.get("qty")) || 1,
|
|
50
|
+
title: m2.title,
|
|
51
|
+
price: m2.price,
|
|
52
|
+
imageUrl: m2.image_url,
|
|
53
|
+
url: m2.platform_url
|
|
54
|
+
};
|
|
55
|
+
case "open-cart":
|
|
56
|
+
case "cart":
|
|
57
|
+
return { type: "open_cart" };
|
|
58
|
+
case "open-login":
|
|
59
|
+
case "login":
|
|
60
|
+
return { type: "open_login" };
|
|
61
|
+
case "open-product":
|
|
62
|
+
case "product": {
|
|
63
|
+
const sku = params.get("sku") || m2.sku || void 0;
|
|
64
|
+
return { type: "open_product", sku, productId: m2.product_id, url: sku ? `/p/${sku}` : void 0 };
|
|
65
|
+
}
|
|
66
|
+
default:
|
|
67
|
+
return { type: "custom", name: verb || "unknown", payload: Object.fromEntries(params) };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const pdp = PDP_SKU_RE.exec(url);
|
|
71
|
+
if (pdp) {
|
|
72
|
+
return {
|
|
73
|
+
type: "open_product",
|
|
74
|
+
sku: decodeURIComponent(pdp[1]),
|
|
75
|
+
productId: m2.product_id,
|
|
76
|
+
url,
|
|
77
|
+
platformProductId: m2.platform_product_id,
|
|
78
|
+
platformUrl: m2.platform_url
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (url) {
|
|
82
|
+
return { type: "navigate", url };
|
|
83
|
+
}
|
|
84
|
+
if (m2.sku || m2.product_id) {
|
|
85
|
+
return {
|
|
86
|
+
type: "add_to_cart",
|
|
87
|
+
sku: m2.sku,
|
|
88
|
+
productId: m2.product_id,
|
|
89
|
+
platformProductId: m2.platform_product_id,
|
|
90
|
+
qty: 1,
|
|
91
|
+
title: m2.title,
|
|
92
|
+
price: m2.price,
|
|
93
|
+
imageUrl: m2.image_url,
|
|
94
|
+
url: m2.platform_url
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return { type: "dismiss" };
|
|
98
|
+
}
|
|
99
|
+
function fallbackUrlForAction(a, productUrl = (sku) => `/p/${encodeURIComponent(sku)}`) {
|
|
100
|
+
switch (a.type) {
|
|
101
|
+
case "navigate":
|
|
102
|
+
return a.url;
|
|
103
|
+
case "open_product":
|
|
104
|
+
return a.url || (a.sku ? productUrl(a.sku) : void 0);
|
|
105
|
+
case "add_to_cart":
|
|
106
|
+
return a.url || (a.sku ? productUrl(a.sku) : void 0);
|
|
107
|
+
case "open_cart":
|
|
108
|
+
return "/cart";
|
|
109
|
+
case "open_login":
|
|
110
|
+
return void 0;
|
|
111
|
+
// host-only; no neutral fallback
|
|
112
|
+
default:
|
|
113
|
+
return void 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
28
116
|
const ICONS = {
|
|
29
117
|
x: [
|
|
30
118
|
["path", { d: "M18 6 6 18" }],
|
|
@@ -223,12 +311,12 @@ const ICONS = {
|
|
|
223
311
|
function escapeAttr(value) {
|
|
224
312
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
225
313
|
}
|
|
226
|
-
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
314
|
+
const SVG_NS$1 = "http://www.w3.org/2000/svg";
|
|
227
315
|
function lucideSvgEl(name, opts = {}) {
|
|
228
316
|
const node = ICONS[name];
|
|
229
317
|
if (!node || typeof document === "undefined") return null;
|
|
230
318
|
const size = opts.size ?? 24;
|
|
231
|
-
const svg = document.createElementNS(SVG_NS, "svg");
|
|
319
|
+
const svg = document.createElementNS(SVG_NS$1, "svg");
|
|
232
320
|
svg.setAttribute("width", String(size));
|
|
233
321
|
svg.setAttribute("height", String(size));
|
|
234
322
|
svg.setAttribute("viewBox", "0 0 24 24");
|
|
@@ -245,7 +333,7 @@ function lucideSvgEl(name, opts = {}) {
|
|
|
245
333
|
svg.setAttribute("aria-hidden", "true");
|
|
246
334
|
}
|
|
247
335
|
for (const [tag, attrs] of node) {
|
|
248
|
-
const child = document.createElementNS(SVG_NS, tag);
|
|
336
|
+
const child = document.createElementNS(SVG_NS$1, tag);
|
|
249
337
|
for (const [k, v] of Object.entries(attrs)) child.setAttribute(k, String(v));
|
|
250
338
|
svg.appendChild(child);
|
|
251
339
|
}
|
|
@@ -437,6 +525,16 @@ function applyPerCardOverride(tpl, look) {
|
|
|
437
525
|
if (look.hide_cta) drop("cta");
|
|
438
526
|
if (look.hide_rating) drop("rating");
|
|
439
527
|
if (look.cta_text) elements = elements.map((e) => e.type === "cta" ? { ...e, text: look.cta_text } : e);
|
|
528
|
+
if (look.cta_action || look.cta_url || look.cta_custom_name) {
|
|
529
|
+
elements = elements.map(
|
|
530
|
+
(e) => e.type === "cta" ? {
|
|
531
|
+
...e,
|
|
532
|
+
...look.cta_action ? { cta_action: look.cta_action } : {},
|
|
533
|
+
...look.cta_url ? { cta_url: look.cta_url } : {},
|
|
534
|
+
...look.cta_custom_name ? { cta_custom_name: look.cta_custom_name } : {}
|
|
535
|
+
} : e
|
|
536
|
+
);
|
|
537
|
+
}
|
|
440
538
|
if (look.badge) {
|
|
441
539
|
const badgeEl = { type: "badge", text: look.badge, color: look.badge_color };
|
|
442
540
|
elements = elements.some((e) => e.type === "badge") ? elements.map((e) => e.type === "badge" ? badgeEl : e) : [elements[0], badgeEl, ...elements.slice(1)].filter(Boolean);
|
|
@@ -450,7 +548,7 @@ function priceText(card) {
|
|
|
450
548
|
if (card.body && /\d/.test(card.body)) return card.body;
|
|
451
549
|
return void 0;
|
|
452
550
|
}
|
|
453
|
-
function paintPrice(card,
|
|
551
|
+
function paintPrice(card, el2, accent, ctx) {
|
|
454
552
|
const price = priceText(card);
|
|
455
553
|
if (price === void 0) return null;
|
|
456
554
|
const meta = card.metadata || {};
|
|
@@ -459,10 +557,10 @@ function paintPrice(card, el, accent, ctx) {
|
|
|
459
557
|
row.style.cssText = "display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;";
|
|
460
558
|
const p = document.createElement("span");
|
|
461
559
|
p.textContent = price;
|
|
462
|
-
if (
|
|
560
|
+
if (el2.variant === "plain") {
|
|
463
561
|
p.style.cssText = `color:${accent};font-weight:700;font-size:13px;`;
|
|
464
562
|
} else {
|
|
465
|
-
const pillBg =
|
|
563
|
+
const pillBg = el2.color ? ctx.sanitizeColor(el2.color) : "#059669";
|
|
466
564
|
p.style.cssText = `background:${pillBg};color:#fff;font-weight:800;font-size:12px;padding:2px 7px;border-radius:6px;box-shadow:0 2px 6px rgba(0,0,0,0.30);`;
|
|
467
565
|
}
|
|
468
566
|
row.appendChild(p);
|
|
@@ -514,14 +612,14 @@ function contrastFg(bg) {
|
|
|
514
612
|
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
515
613
|
return lum < 0.5 ? "#ffffff" : "#1f2937";
|
|
516
614
|
}
|
|
517
|
-
function buildCountdownElement(
|
|
518
|
-
const targetStr = typeof
|
|
615
|
+
function buildCountdownElement(el2, fg, muted) {
|
|
616
|
+
const targetStr = typeof el2.countdown_target === "string" ? el2.countdown_target : "";
|
|
519
617
|
const target = targetStr ? Date.parse(targetStr) : NaN;
|
|
520
618
|
if (!targetStr || isNaN(target)) return null;
|
|
521
619
|
const wrap = document.createElement("div");
|
|
522
620
|
wrap.style.cssText = "display:flex;align-items:baseline;gap:8px;font-variant-numeric:tabular-nums;margin:2px 0;";
|
|
523
621
|
const label = document.createElement("span");
|
|
524
|
-
label.textContent = typeof
|
|
622
|
+
label.textContent = typeof el2.countdown_label === "string" && el2.countdown_label || "Ends in";
|
|
525
623
|
label.style.cssText = `font-size:12px;color:${muted};`;
|
|
526
624
|
const time = document.createElement("span");
|
|
527
625
|
time.style.cssText = `font-size:15px;font-weight:700;color:${fg};letter-spacing:0.2px;`;
|
|
@@ -543,13 +641,13 @@ function buildCountdownElement(el, fg, muted) {
|
|
|
543
641
|
timer = setInterval(tick, 1e3);
|
|
544
642
|
return wrap;
|
|
545
643
|
}
|
|
546
|
-
function appendRatingThanks(wrap,
|
|
547
|
-
appendThanks(wrap,
|
|
548
|
-
const url = isHigh && typeof
|
|
644
|
+
function appendRatingThanks(wrap, el2, ctx, fg, accent, isHigh) {
|
|
645
|
+
appendThanks(wrap, el2, fg, "Thanks for rating us!");
|
|
646
|
+
const url = isHigh && typeof el2.rating_high_url === "string" ? ctx.sanitizeUrl(el2.rating_high_url) : "";
|
|
549
647
|
if (url) {
|
|
550
648
|
const cta = document.createElement("button");
|
|
551
649
|
cta.type = "button";
|
|
552
|
-
cta.textContent =
|
|
650
|
+
cta.textContent = el2.rating_high_cta || "Leave a review";
|
|
553
651
|
cta.style.cssText = `margin:4px auto 0;display:block;padding:9px 18px;border:none;border-radius:999px;background:${accent};color:#fff;font-size:13px;font-weight:800;cursor:pointer;`;
|
|
554
652
|
cta.addEventListener("click", () => {
|
|
555
653
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "rating_input", cta: "high_review" } });
|
|
@@ -559,10 +657,10 @@ function appendRatingThanks(wrap, el, ctx, fg, accent, isHigh) {
|
|
|
559
657
|
wrap.appendChild(cta);
|
|
560
658
|
}
|
|
561
659
|
}
|
|
562
|
-
function renderRatingFollowupStep(wrap,
|
|
660
|
+
function renderRatingFollowupStep(wrap, el2, ctx, stars2, fg, accent) {
|
|
563
661
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
564
662
|
const heading = document.createElement("div");
|
|
565
|
-
heading.textContent =
|
|
663
|
+
heading.textContent = el2.rating_followup_prompt || "Sorry to hear that — what went wrong?";
|
|
566
664
|
heading.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin-bottom:8px;`;
|
|
567
665
|
wrap.appendChild(heading);
|
|
568
666
|
const ta = document.createElement("textarea");
|
|
@@ -576,9 +674,9 @@ function renderRatingFollowupStep(wrap, el, ctx, stars, fg, accent) {
|
|
|
576
674
|
if (done) return;
|
|
577
675
|
done = true;
|
|
578
676
|
const comment = withComment ? ta.value.trim() : "";
|
|
579
|
-
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "rating", comment ? { stars, comment } : { stars }));
|
|
677
|
+
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "rating", comment ? { stars: stars2, comment } : { stars: stars2 }));
|
|
580
678
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, "acknowledge");
|
|
581
|
-
appendThanks(wrap,
|
|
679
|
+
appendThanks(wrap, el2, fg, "Thanks — we’ll do better.");
|
|
582
680
|
};
|
|
583
681
|
const btnRow = document.createElement("div");
|
|
584
682
|
btnRow.style.cssText = "display:flex;gap:8px;justify-content:center;";
|
|
@@ -597,23 +695,23 @@ function renderRatingFollowupStep(wrap, el, ctx, stars, fg, accent) {
|
|
|
597
695
|
wrap.appendChild(btnRow);
|
|
598
696
|
ta.focus();
|
|
599
697
|
}
|
|
600
|
-
function buildRatingInputElement(
|
|
698
|
+
function buildRatingInputElement(el2, ctx, fg) {
|
|
601
699
|
const accent = ctx.sanitizeColor(ctx.campaign.background_color || "#4169e1");
|
|
602
700
|
const wrap = document.createElement("div");
|
|
603
701
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
604
|
-
if (
|
|
702
|
+
if (el2.content) {
|
|
605
703
|
const q = document.createElement("div");
|
|
606
|
-
q.textContent =
|
|
704
|
+
q.textContent = el2.content;
|
|
607
705
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
608
706
|
wrap.appendChild(q);
|
|
609
707
|
}
|
|
610
|
-
const scale = typeof
|
|
708
|
+
const scale = typeof el2.rating_scale === "number" && el2.rating_scale >= 2 && el2.rating_scale <= 10 ? Math.floor(el2.rating_scale) : 5;
|
|
611
709
|
const row = document.createElement("div");
|
|
612
710
|
row.style.cssText = "display:flex;gap:6px;";
|
|
613
|
-
const
|
|
711
|
+
const stars2 = [];
|
|
614
712
|
let submitted = false;
|
|
615
713
|
const paint = (upto) => {
|
|
616
|
-
|
|
714
|
+
stars2.forEach((s, idx) => {
|
|
617
715
|
const on = idx < upto;
|
|
618
716
|
s.setAttribute("stroke", on ? "#f59e0b" : "#d1d5db");
|
|
619
717
|
s.setAttribute("fill", on ? "#f59e0b" : "none");
|
|
@@ -627,7 +725,7 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
627
725
|
const svg = lucideSvgEl("star", { size: 26, color: "#d1d5db" });
|
|
628
726
|
if (svg) {
|
|
629
727
|
btn.appendChild(svg);
|
|
630
|
-
|
|
728
|
+
stars2.push(svg);
|
|
631
729
|
}
|
|
632
730
|
btn.addEventListener("mouseenter", () => {
|
|
633
731
|
if (!submitted) paint(i);
|
|
@@ -641,13 +739,13 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
641
739
|
submitted = true;
|
|
642
740
|
paint(i);
|
|
643
741
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "rating_input", stars: i } });
|
|
644
|
-
const lowThreshold = typeof
|
|
645
|
-
if (
|
|
646
|
-
renderRatingFollowupStep(wrap,
|
|
742
|
+
const lowThreshold = typeof el2.rating_followup_threshold === "number" ? el2.rating_followup_threshold : Math.ceil(scale * 0.8);
|
|
743
|
+
if (el2.rating_followup_enabled === true && i <= lowThreshold) {
|
|
744
|
+
renderRatingFollowupStep(wrap, el2, ctx, i, fg, accent);
|
|
647
745
|
} else {
|
|
648
746
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "rating", { stars: i }));
|
|
649
747
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, i >= Math.ceil(scale * 0.6) ? "affirm" : "acknowledge");
|
|
650
|
-
appendRatingThanks(wrap,
|
|
748
|
+
appendRatingThanks(wrap, el2, ctx, fg, accent, i >= Math.ceil(scale * 0.6));
|
|
651
749
|
}
|
|
652
750
|
});
|
|
653
751
|
row.appendChild(btn);
|
|
@@ -655,8 +753,8 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
655
753
|
wrap.appendChild(row);
|
|
656
754
|
return wrap;
|
|
657
755
|
}
|
|
658
|
-
function appendThanks(wrap,
|
|
659
|
-
const msg = typeof
|
|
756
|
+
function appendThanks(wrap, el2, fg, fallback) {
|
|
757
|
+
const msg = typeof el2.thanks_text === "string" && el2.thanks_text.trim() ? el2.thanks_text : fallback;
|
|
660
758
|
if (!msg) return;
|
|
661
759
|
const note = document.createElement("div");
|
|
662
760
|
note.textContent = msg;
|
|
@@ -664,14 +762,14 @@ function appendThanks(wrap, el, fg, fallback) {
|
|
|
664
762
|
note.style.cssText = `font-size:12px;font-weight:600;color:${fg};opacity:0.85;margin-top:4px;`;
|
|
665
763
|
wrap.appendChild(note);
|
|
666
764
|
}
|
|
667
|
-
function buildPollElement(
|
|
668
|
-
const opts = Array.isArray(
|
|
765
|
+
function buildPollElement(el2, ctx, fg, accent) {
|
|
766
|
+
const opts = Array.isArray(el2.poll_options) ? el2.poll_options.filter((o) => typeof o === "string" && o.trim().length > 0) : [];
|
|
669
767
|
if (opts.length < 2) return null;
|
|
670
768
|
const wrap = document.createElement("div");
|
|
671
769
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
672
|
-
if (
|
|
770
|
+
if (el2.content) {
|
|
673
771
|
const q = document.createElement("div");
|
|
674
|
-
q.textContent =
|
|
772
|
+
q.textContent = el2.content;
|
|
675
773
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
676
774
|
wrap.appendChild(q);
|
|
677
775
|
}
|
|
@@ -701,24 +799,24 @@ function buildPollElement(el, ctx, fg, accent) {
|
|
|
701
799
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "poll", option_index: idx, option_label: label } });
|
|
702
800
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "poll", { option_index: idx, option_label: label }));
|
|
703
801
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, "affirm");
|
|
704
|
-
appendThanks(wrap,
|
|
802
|
+
appendThanks(wrap, el2, fg, "Thanks for your answer!");
|
|
705
803
|
});
|
|
706
804
|
wrap.appendChild(btn);
|
|
707
805
|
});
|
|
708
806
|
return wrap;
|
|
709
807
|
}
|
|
710
|
-
function appendNpsThanks(wrap,
|
|
808
|
+
function appendNpsThanks(wrap, el2, ctx, fg, accent, isPromoter) {
|
|
711
809
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
712
810
|
const note = document.createElement("div");
|
|
713
811
|
note.setAttribute("role", "status");
|
|
714
|
-
note.textContent = (typeof
|
|
812
|
+
note.textContent = (typeof el2.thanks_text === "string" && el2.thanks_text.trim() ? el2.thanks_text : "") || (isPromoter ? "Thank you! We’d love a public review." : "Thanks — your feedback helps us improve.");
|
|
715
813
|
note.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin:6px 0;`;
|
|
716
814
|
wrap.appendChild(note);
|
|
717
|
-
const url = isPromoter && typeof
|
|
815
|
+
const url = isPromoter && typeof el2.nps_promoter_url === "string" ? ctx.sanitizeUrl(el2.nps_promoter_url) : "";
|
|
718
816
|
if (url) {
|
|
719
817
|
const cta = document.createElement("button");
|
|
720
818
|
cta.type = "button";
|
|
721
|
-
cta.textContent =
|
|
819
|
+
cta.textContent = el2.nps_promoter_cta || "Leave a review";
|
|
722
820
|
cta.style.cssText = `margin:4px auto 0;display:block;padding:9px 18px;border:none;border-radius:999px;background:${accent};color:#fff;font-size:13px;font-weight:800;cursor:pointer;`;
|
|
723
821
|
cta.addEventListener("click", () => {
|
|
724
822
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "nps", cta: "promoter_review" } });
|
|
@@ -728,30 +826,30 @@ function appendNpsThanks(wrap, el, ctx, fg, accent, isPromoter) {
|
|
|
728
826
|
wrap.appendChild(cta);
|
|
729
827
|
}
|
|
730
828
|
}
|
|
731
|
-
function renderNpsReasonStep(wrap,
|
|
732
|
-
const promoterThreshold = typeof
|
|
829
|
+
function renderNpsReasonStep(wrap, el2, ctx, score, fg, accent) {
|
|
830
|
+
const promoterThreshold = typeof el2.nps_promoter_threshold === "number" ? el2.nps_promoter_threshold : 9;
|
|
733
831
|
const band = npsBandFromScore(score);
|
|
734
|
-
const prompt = score >= promoterThreshold ?
|
|
832
|
+
const prompt = score >= promoterThreshold ? el2.nps_follow_up_promoter || "What do you love most about us?" : score <= 6 ? el2.nps_follow_up_detractor || "How can we improve?" : el2.nps_follow_up_passive || "What would make us a 10?";
|
|
735
833
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
736
834
|
const heading = document.createElement("div");
|
|
737
835
|
heading.textContent = prompt;
|
|
738
836
|
heading.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin-bottom:8px;`;
|
|
739
837
|
wrap.appendChild(heading);
|
|
740
838
|
const ta = document.createElement("textarea");
|
|
741
|
-
const chips = Array.isArray(
|
|
839
|
+
const chips = Array.isArray(el2.nps_reason_chips) ? el2.nps_reason_chips : [];
|
|
742
840
|
if (chips.length) {
|
|
743
841
|
const chipRow = document.createElement("div");
|
|
744
842
|
chipRow.style.cssText = "display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-bottom:8px;";
|
|
745
843
|
chips.slice(0, 8).forEach((c) => {
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
844
|
+
const chip2 = document.createElement("button");
|
|
845
|
+
chip2.type = "button";
|
|
846
|
+
chip2.textContent = c;
|
|
847
|
+
chip2.style.cssText = `padding:5px 11px;border-radius:999px;border:1px solid color-mix(in srgb, ${accent} 35%, transparent);background:transparent;color:${fg};font-size:12px;cursor:pointer;`;
|
|
848
|
+
chip2.addEventListener("click", () => {
|
|
751
849
|
ta.value = ta.value ? `${ta.value}, ${c}` : c;
|
|
752
850
|
ta.focus();
|
|
753
851
|
});
|
|
754
|
-
chipRow.appendChild(
|
|
852
|
+
chipRow.appendChild(chip2);
|
|
755
853
|
});
|
|
756
854
|
wrap.appendChild(chipRow);
|
|
757
855
|
}
|
|
@@ -767,7 +865,7 @@ function renderNpsReasonStep(wrap, el, ctx, score, fg, accent) {
|
|
|
767
865
|
const comment = withComment ? ta.value.trim() : "";
|
|
768
866
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "nps", comment ? { score, band, comment } : { score, band }));
|
|
769
867
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, score >= promoterThreshold ? "affirm" : score <= 6 ? "empathize" : "acknowledge");
|
|
770
|
-
appendNpsThanks(wrap,
|
|
868
|
+
appendNpsThanks(wrap, el2, ctx, fg, accent, score >= promoterThreshold);
|
|
771
869
|
};
|
|
772
870
|
const btnRow = document.createElement("div");
|
|
773
871
|
btnRow.style.cssText = "display:flex;gap:8px;justify-content:center;";
|
|
@@ -786,12 +884,12 @@ function renderNpsReasonStep(wrap, el, ctx, score, fg, accent) {
|
|
|
786
884
|
wrap.appendChild(btnRow);
|
|
787
885
|
ta.focus();
|
|
788
886
|
}
|
|
789
|
-
function buildNpsElement(
|
|
887
|
+
function buildNpsElement(el2, ctx, fg, accent, muted) {
|
|
790
888
|
const wrap = document.createElement("div");
|
|
791
889
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
792
|
-
if (
|
|
890
|
+
if (el2.content) {
|
|
793
891
|
const q = document.createElement("div");
|
|
794
|
-
q.textContent =
|
|
892
|
+
q.textContent = el2.content;
|
|
795
893
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
796
894
|
wrap.appendChild(q);
|
|
797
895
|
}
|
|
@@ -823,12 +921,12 @@ function buildNpsElement(el, ctx, fg, accent, muted) {
|
|
|
823
921
|
btn.style.opacity = "1";
|
|
824
922
|
const npsPayload = { score: n, band: npsBandFromScore(n) };
|
|
825
923
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "nps", score: n, band: npsPayload.band } });
|
|
826
|
-
if (
|
|
827
|
-
renderNpsReasonStep(wrap,
|
|
924
|
+
if (el2.nps_followup_enabled === true) {
|
|
925
|
+
renderNpsReasonStep(wrap, el2, ctx, n, fg, accent);
|
|
828
926
|
} else {
|
|
829
927
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "nps", { ...npsPayload }));
|
|
830
928
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, n >= 9 ? "affirm" : n >= 7 ? "acknowledge" : "empathize");
|
|
831
|
-
appendThanks(wrap,
|
|
929
|
+
appendThanks(wrap, el2, fg, "Thanks for your feedback!");
|
|
832
930
|
}
|
|
833
931
|
});
|
|
834
932
|
row.appendChild(btn);
|
|
@@ -845,22 +943,22 @@ function buildNpsElement(el, ctx, fg, accent, muted) {
|
|
|
845
943
|
wrap.appendChild(scale);
|
|
846
944
|
return wrap;
|
|
847
945
|
}
|
|
848
|
-
function buildProgressElement(
|
|
946
|
+
function buildProgressElement(el2, ctx, accent, muted) {
|
|
849
947
|
const { trackEvent, campaign, sanitizeColor } = ctx;
|
|
850
|
-
const goal =
|
|
948
|
+
const goal = el2.goal_type || "cart_total";
|
|
851
949
|
const moneyGoal = goal === "cart_total";
|
|
852
|
-
const fill =
|
|
950
|
+
const fill = el2.fill ? sanitizeColor(el2.fill) : accent;
|
|
853
951
|
const props = () => ctx.properties && ctx.properties() || {};
|
|
854
952
|
const sym = () => {
|
|
855
953
|
var _a;
|
|
856
|
-
if (
|
|
954
|
+
if (el2.currency_symbol) return el2.currency_symbol;
|
|
857
955
|
const code = ctx.getCartState && ((_a = ctx.getCartState()) == null ? void 0 : _a.currency);
|
|
858
956
|
const M = { INR: "₹", USD: "$", EUR: "€", GBP: "£" };
|
|
859
957
|
return code && M[code] || "";
|
|
860
958
|
};
|
|
861
959
|
const threshold = () => {
|
|
862
|
-
if (typeof
|
|
863
|
-
if (
|
|
960
|
+
if (typeof el2.threshold === "number" && el2.threshold > 0) return el2.threshold;
|
|
961
|
+
if (el2.threshold_source === "free_delivery_setting") {
|
|
864
962
|
const v = Number(props()["cart.free_delivery_above"]);
|
|
865
963
|
if (v > 0) return v;
|
|
866
964
|
}
|
|
@@ -901,9 +999,9 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
901
999
|
goalType: goal,
|
|
902
1000
|
threshold: th,
|
|
903
1001
|
current: cur,
|
|
904
|
-
rewardText:
|
|
1002
|
+
rewardText: el2.reward_text,
|
|
905
1003
|
currencySymbol: moneyGoal ? sym() : "",
|
|
906
|
-
showPct:
|
|
1004
|
+
showPct: el2.show_pct
|
|
907
1005
|
});
|
|
908
1006
|
sub.textContent = labeled.text;
|
|
909
1007
|
if (complete) {
|
|
@@ -912,8 +1010,8 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
912
1010
|
if (!firedUnlock) {
|
|
913
1011
|
firedUnlock = true;
|
|
914
1012
|
if (seenIncomplete) {
|
|
915
|
-
trackEvent(campaign.id, "clicked", { stepId:
|
|
916
|
-
if (
|
|
1013
|
+
trackEvent(campaign.id, "clicked", { stepId: el2.id || "unlocked" });
|
|
1014
|
+
if (el2.celebrate_on_complete !== false) (_a = ctx.playReaction) == null ? void 0 : _a.call(ctx, wrap, "celebrate");
|
|
917
1015
|
}
|
|
918
1016
|
}
|
|
919
1017
|
} else {
|
|
@@ -931,6 +1029,40 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
931
1029
|
}
|
|
932
1030
|
return wrap;
|
|
933
1031
|
}
|
|
1032
|
+
function buildCtaAction(el2, card, meta, inline, sanitizeUrl) {
|
|
1033
|
+
const kind = el2.cta_action ?? (inline ? "add_to_cart" : "navigate");
|
|
1034
|
+
const safe = (u) => u ? sanitizeUrl(u) || void 0 : void 0;
|
|
1035
|
+
const url = safe(el2.cta_url || card.cta_url);
|
|
1036
|
+
const productId = meta.product_id;
|
|
1037
|
+
const sku = meta.sku;
|
|
1038
|
+
const platformProductId = meta.platform_product_id;
|
|
1039
|
+
const platformUrl = safe(meta.platform_url);
|
|
1040
|
+
switch (kind) {
|
|
1041
|
+
case "open_cart":
|
|
1042
|
+
return { type: "open_cart" };
|
|
1043
|
+
case "open_login":
|
|
1044
|
+
return { type: "open_login" };
|
|
1045
|
+
case "open_product":
|
|
1046
|
+
return { type: "open_product", productId, sku, url: platformUrl || url, platformProductId, platformUrl };
|
|
1047
|
+
case "navigate":
|
|
1048
|
+
return { type: "navigate", url: url || "" };
|
|
1049
|
+
case "custom":
|
|
1050
|
+
return { type: "custom", name: el2.cta_custom_name || "cta", payload: { ...meta, url } };
|
|
1051
|
+
case "add_to_cart":
|
|
1052
|
+
default:
|
|
1053
|
+
return {
|
|
1054
|
+
type: "add_to_cart",
|
|
1055
|
+
productId,
|
|
1056
|
+
sku,
|
|
1057
|
+
platformProductId,
|
|
1058
|
+
title: card.title,
|
|
1059
|
+
price: meta.price ?? card.body,
|
|
1060
|
+
imageUrl: card.image_url,
|
|
1061
|
+
url: platformUrl || url,
|
|
1062
|
+
qty: 1
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
934
1066
|
function renderCardFromTemplate(card, opts) {
|
|
935
1067
|
const { ctx, action, layout, layoutAccent } = opts;
|
|
936
1068
|
const inline = action === "cart";
|
|
@@ -943,13 +1075,14 @@ function renderCardFromTemplate(card, opts) {
|
|
|
943
1075
|
const fg = contrastFg(frame.bg ? sanitizeColor(frame.bg) : "#ffffff");
|
|
944
1076
|
const muted = fg === "#ffffff" ? "rgba(255,255,255,0.72)" : "#6b7280";
|
|
945
1077
|
const tile = document.createElement("div");
|
|
1078
|
+
tile.setAttribute("data-aegis-reaction-anchor", "");
|
|
946
1079
|
const cardFont = resolveCardFont(frame.fontFamily);
|
|
947
1080
|
ensureCardFontLoaded(cardFont);
|
|
948
1081
|
const radius = frame.radius !== void 0 ? `${parseInt(String(frame.radius), 10) || 12}px` : "12px";
|
|
949
1082
|
const fLayout = frame.layout;
|
|
950
1083
|
const dir = fLayout === "row" ? "row" : "column";
|
|
951
1084
|
const tileGap = frame.gap != null ? frame.gap : 6;
|
|
952
|
-
const sizing = fLayout ? frame.width != null ? `width:${typeof frame.width === "number" ? `${frame.width}px` : frame.width};` : "flex:1 1 auto; width:100%;" : layout === "grid" ? "" : "flex:0 0 150px; scroll-snap-align:start;";
|
|
1085
|
+
const sizing = fLayout ? frame.width != null ? `width:${typeof frame.width === "number" ? `${frame.width}px` : frame.width};` : "flex:1 1 auto; width:100%;" : layout === "grid" || layout === "list" ? "" : "flex:0 0 150px; scroll-snap-align:start;";
|
|
953
1086
|
tile.style.cssText = `
|
|
954
1087
|
box-sizing:border-box; display:flex; flex-direction:${dir}; ${fLayout === "row" ? "align-items:center;" : ""} gap:${tileGap}px; position:relative;
|
|
955
1088
|
color:${fg};
|
|
@@ -966,11 +1099,11 @@ function renderCardFromTemplate(card, opts) {
|
|
|
966
1099
|
const elements = tpl.elements && tpl.elements.length ? tpl.elements : DEFAULT_CARD_TEMPLATE.elements;
|
|
967
1100
|
let imageWrap = null;
|
|
968
1101
|
const paintInto = (container, els) => {
|
|
969
|
-
for (const
|
|
970
|
-
switch (
|
|
1102
|
+
for (const el2 of els) {
|
|
1103
|
+
switch (el2.type) {
|
|
971
1104
|
case "image": {
|
|
972
1105
|
const wrap = document.createElement("div");
|
|
973
|
-
wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT$2[
|
|
1106
|
+
wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT$2[el2.aspect || "1/1"] || "1 / 1"};border-radius:${el2.radius ?? 10}px;overflow:hidden;background:#f7f8fa;`;
|
|
974
1107
|
const safeVideo = card.video_url ? sanitizeUrl(card.video_url) : "";
|
|
975
1108
|
if (safeVideo) {
|
|
976
1109
|
const v = document.createElement("video");
|
|
@@ -998,17 +1131,17 @@ function renderCardFromTemplate(card, opts) {
|
|
|
998
1131
|
break;
|
|
999
1132
|
}
|
|
1000
1133
|
case "badge": {
|
|
1001
|
-
const text =
|
|
1134
|
+
const text = el2.text;
|
|
1002
1135
|
if (!text) break;
|
|
1003
1136
|
const badge = document.createElement("span");
|
|
1004
1137
|
badge.textContent = text;
|
|
1005
|
-
const bg =
|
|
1138
|
+
const bg = el2.color ? sanitizeColor(el2.color) : brand;
|
|
1006
1139
|
badge.style.cssText = `position:absolute;top:6px;left:6px;z-index:1;background:${bg};color:#fff;font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:0.03em;padding:3px 6px;border-radius:5px;`;
|
|
1007
1140
|
(imageWrap || container).appendChild(badge);
|
|
1008
1141
|
break;
|
|
1009
1142
|
}
|
|
1010
1143
|
case "price": {
|
|
1011
|
-
const node = paintPrice(card,
|
|
1144
|
+
const node = paintPrice(card, el2, accent, ctx);
|
|
1012
1145
|
if (node) container.appendChild(node);
|
|
1013
1146
|
break;
|
|
1014
1147
|
}
|
|
@@ -1016,8 +1149,8 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1016
1149
|
if (!card.title) break;
|
|
1017
1150
|
const t = document.createElement("div");
|
|
1018
1151
|
t.textContent = card.title;
|
|
1019
|
-
const lines =
|
|
1020
|
-
t.style.cssText = `font-size:12.5px;font-weight:600;line-height:1.3;text-align:${
|
|
1152
|
+
const lines = el2.lines && el2.lines > 0 ? el2.lines : 2;
|
|
1153
|
+
t.style.cssText = `font-size:12.5px;font-weight:600;line-height:1.3;text-align:${el2.align ?? "left"};color:${el2.color ? sanitizeColor(el2.color) : fg};display:-webkit-box;-webkit-line-clamp:${lines};-webkit-box-orient:vertical;overflow:hidden;`;
|
|
1021
1154
|
container.appendChild(t);
|
|
1022
1155
|
break;
|
|
1023
1156
|
}
|
|
@@ -1025,8 +1158,8 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1025
1158
|
if (!card.body) break;
|
|
1026
1159
|
const s = document.createElement("div");
|
|
1027
1160
|
s.textContent = card.body;
|
|
1028
|
-
const lines =
|
|
1029
|
-
s.style.cssText = `font-size:11px;color:${
|
|
1161
|
+
const lines = el2.lines && el2.lines > 0 ? el2.lines : 2;
|
|
1162
|
+
s.style.cssText = `font-size:11px;color:${el2.color ? sanitizeColor(el2.color) : muted};line-height:1.3;text-align:${el2.align ?? "left"};display:-webkit-box;-webkit-line-clamp:${lines};-webkit-box-orient:vertical;overflow:hidden;`;
|
|
1030
1163
|
container.appendChild(s);
|
|
1031
1164
|
break;
|
|
1032
1165
|
}
|
|
@@ -1038,25 +1171,25 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1038
1171
|
case "category": {
|
|
1039
1172
|
const cat = meta.category;
|
|
1040
1173
|
if (typeof cat !== "string" || !cat) break;
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
container.appendChild(
|
|
1174
|
+
const chip2 = document.createElement("span");
|
|
1175
|
+
chip2.textContent = cat;
|
|
1176
|
+
chip2.style.cssText = "align-self:flex-start;background:#f3f4f6;color:#6b7280;font-size:10px;font-weight:500;padding:2px 7px;border-radius:6px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";
|
|
1177
|
+
container.appendChild(chip2);
|
|
1045
1178
|
break;
|
|
1046
1179
|
}
|
|
1047
1180
|
// ── rich-card-editor elements (P0) ──────────────────────────────────
|
|
1048
1181
|
case "icon": {
|
|
1049
|
-
const px = ICON_PX[
|
|
1182
|
+
const px = ICON_PX[el2.size || "md"] || 30;
|
|
1050
1183
|
const node = document.createElement("div");
|
|
1051
|
-
const iconColor =
|
|
1052
|
-
if (
|
|
1053
|
-
const bubbleTint =
|
|
1184
|
+
const iconColor = el2.color ? sanitizeColor(el2.color) : fg;
|
|
1185
|
+
if (el2.bubble) {
|
|
1186
|
+
const bubbleTint = el2.color ? sanitizeColor(el2.color) : brand;
|
|
1054
1187
|
node.style.cssText = `flex:0 0 auto;width:${px}px;height:${px}px;border-radius:999px;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb, ${bubbleTint} 16%, transparent);`;
|
|
1055
1188
|
} else {
|
|
1056
1189
|
node.style.cssText = "flex:0 0 auto;display:flex;align-items:center;";
|
|
1057
1190
|
}
|
|
1058
|
-
const svg = lucideSvgEl(
|
|
1059
|
-
size:
|
|
1191
|
+
const svg = lucideSvgEl(el2.icon_name || "circle-check", {
|
|
1192
|
+
size: el2.bubble ? Math.round(px * 0.55) : Math.round(px * 0.7),
|
|
1060
1193
|
color: iconColor,
|
|
1061
1194
|
strokeWidth: 2
|
|
1062
1195
|
});
|
|
@@ -1066,84 +1199,64 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1066
1199
|
}
|
|
1067
1200
|
case "text": {
|
|
1068
1201
|
const t = document.createElement("div");
|
|
1069
|
-
const fs = TEXT_PX[
|
|
1070
|
-
t.style.cssText = `font-size:${fs}px;font-weight:${WEIGHT[
|
|
1071
|
-
t.textContent = interpolateTokens(
|
|
1202
|
+
const fs = TEXT_PX[el2.size || "md"] || 13;
|
|
1203
|
+
t.style.cssText = `font-size:${fs}px;font-weight:${WEIGHT[el2.weight ?? "medium"]};text-align:${el2.align ?? "left"};color:${el2.color ? sanitizeColor(el2.color) : fg};line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;`;
|
|
1204
|
+
t.textContent = interpolateTokens(el2.content ?? "", ctx);
|
|
1072
1205
|
container.appendChild(t);
|
|
1073
1206
|
break;
|
|
1074
1207
|
}
|
|
1075
1208
|
case "spacer": {
|
|
1076
1209
|
const sp = document.createElement("div");
|
|
1077
|
-
sp.style.height = `${
|
|
1210
|
+
sp.style.height = `${el2.height ?? 8}px`;
|
|
1078
1211
|
container.appendChild(sp);
|
|
1079
1212
|
break;
|
|
1080
1213
|
}
|
|
1081
1214
|
case "progress": {
|
|
1082
|
-
container.appendChild(buildProgressElement(
|
|
1215
|
+
container.appendChild(buildProgressElement(el2, ctx, brand, muted));
|
|
1083
1216
|
break;
|
|
1084
1217
|
}
|
|
1085
1218
|
case "countdown": {
|
|
1086
|
-
const cd = buildCountdownElement(
|
|
1219
|
+
const cd = buildCountdownElement(el2, fg, muted);
|
|
1087
1220
|
if (cd) container.appendChild(cd);
|
|
1088
1221
|
break;
|
|
1089
1222
|
}
|
|
1090
1223
|
case "rating_input": {
|
|
1091
|
-
container.appendChild(buildRatingInputElement(
|
|
1224
|
+
container.appendChild(buildRatingInputElement(el2, ctx, fg));
|
|
1092
1225
|
break;
|
|
1093
1226
|
}
|
|
1094
1227
|
case "poll": {
|
|
1095
|
-
const p = buildPollElement(
|
|
1228
|
+
const p = buildPollElement(el2, ctx, fg, brand);
|
|
1096
1229
|
if (p) container.appendChild(p);
|
|
1097
1230
|
break;
|
|
1098
1231
|
}
|
|
1099
1232
|
case "nps": {
|
|
1100
|
-
container.appendChild(buildNpsElement(
|
|
1233
|
+
container.appendChild(buildNpsElement(el2, ctx, fg, brand, muted));
|
|
1101
1234
|
break;
|
|
1102
1235
|
}
|
|
1103
1236
|
case "group": {
|
|
1104
1237
|
const g = document.createElement("div");
|
|
1105
|
-
const gdir =
|
|
1106
|
-
g.style.cssText = `display:flex;flex-direction:${gdir};${
|
|
1107
|
-
paintInto(g,
|
|
1238
|
+
const gdir = el2.layout === "row" ? "row" : "column";
|
|
1239
|
+
g.style.cssText = `display:flex;flex-direction:${gdir};${el2.layout === "row" ? "align-items:center;" : ""}gap:${el2.gap ?? 4}px;min-width:0;${el2.layout === "row" ? "" : "flex:1 1 auto;"}`;
|
|
1240
|
+
paintInto(g, el2.elements || []);
|
|
1108
1241
|
container.appendChild(g);
|
|
1109
1242
|
break;
|
|
1110
1243
|
}
|
|
1111
1244
|
case "cta": {
|
|
1112
|
-
const label =
|
|
1245
|
+
const label = el2.text || card.cta_text || (inline ? "Add" : "Shop");
|
|
1113
1246
|
const cta = document.createElement("button");
|
|
1114
1247
|
cta.className = "aegis-cta";
|
|
1115
1248
|
cta.textContent = label;
|
|
1116
|
-
const overlayOnImage = !!
|
|
1249
|
+
const overlayOnImage = !!el2.overlay && !!imageWrap;
|
|
1117
1250
|
if (overlayOnImage) {
|
|
1118
|
-
cta.style.cssText =
|
|
1251
|
+
cta.style.cssText = el2.variant === "outline" ? `position:absolute;right:6px;bottom:6px;background:#fff;color:${brand};border:1px solid ${brand};border-radius:9px;padding:5px 18px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:0.04em;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.14);` : `position:absolute;right:6px;bottom:6px;background:${brand};color:#fff;border:none;border-radius:9px;padding:5px 18px;font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:0.04em;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,0.14);`;
|
|
1119
1252
|
} else {
|
|
1120
|
-
cta.style.cssText =
|
|
1253
|
+
cta.style.cssText = el2.variant === "outline" ? `margin-top:${fLayout === "row" ? "0" : "auto"};background:transparent;color:${brand};border:1px solid ${brand};border-radius:999px;padding:6px 10px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;` : `margin-top:${fLayout === "row" ? "0" : "auto"};background:${brand};color:#fff;border:none;border-radius:999px;padding:7px 10px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;`;
|
|
1121
1254
|
}
|
|
1122
1255
|
cta.addEventListener("click", (e) => {
|
|
1256
|
+
var _a;
|
|
1123
1257
|
e.stopPropagation();
|
|
1124
|
-
trackEvent(campaign.id, "clicked", { stepId:
|
|
1125
|
-
|
|
1126
|
-
if (typeof window !== "undefined") {
|
|
1127
|
-
window.dispatchEvent(
|
|
1128
|
-
new CustomEvent("aegis:add-to-cart", {
|
|
1129
|
-
detail: {
|
|
1130
|
-
campaign_id: campaign.id,
|
|
1131
|
-
product_id: meta.product_id,
|
|
1132
|
-
sku: meta.sku,
|
|
1133
|
-
title: card.title,
|
|
1134
|
-
price: meta.price ?? card.body,
|
|
1135
|
-
image_url: card.image_url,
|
|
1136
|
-
cta_url: card.cta_url
|
|
1137
|
-
}
|
|
1138
|
-
})
|
|
1139
|
-
);
|
|
1140
|
-
}
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
if (card.cta_url) {
|
|
1144
|
-
const safe = sanitizeUrl(card.cta_url);
|
|
1145
|
-
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
1146
|
-
}
|
|
1258
|
+
trackEvent(campaign.id, "clicked", { stepId: el2.id || "add" });
|
|
1259
|
+
(_a = ctx.dispatchAction) == null ? void 0 : _a.call(ctx, buildCtaAction(el2, card, meta, inline, sanitizeUrl));
|
|
1147
1260
|
});
|
|
1148
1261
|
(overlayOnImage ? imageWrap : container).appendChild(cta);
|
|
1149
1262
|
break;
|
|
@@ -1153,27 +1266,20 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1153
1266
|
};
|
|
1154
1267
|
paintInto(tile, elements);
|
|
1155
1268
|
const open = (e) => {
|
|
1269
|
+
var _a;
|
|
1156
1270
|
e.stopPropagation();
|
|
1157
1271
|
trackEvent(campaign.id, "clicked");
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
);
|
|
1170
|
-
}
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
if (card.cta_url) {
|
|
1174
|
-
const safe = sanitizeUrl(card.cta_url);
|
|
1175
|
-
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
1176
|
-
}
|
|
1272
|
+
const bm = meta;
|
|
1273
|
+
const safe = (u) => u ? sanitizeUrl(u) || void 0 : void 0;
|
|
1274
|
+
const act = inline ? {
|
|
1275
|
+
type: "open_product",
|
|
1276
|
+
productId: bm.product_id,
|
|
1277
|
+
sku: bm.sku,
|
|
1278
|
+
url: safe(bm.platform_url) || safe(card.cta_url),
|
|
1279
|
+
platformProductId: bm.platform_product_id,
|
|
1280
|
+
platformUrl: safe(bm.platform_url)
|
|
1281
|
+
} : { type: "navigate", url: safe(card.cta_url) || "" };
|
|
1282
|
+
(_a = ctx.dispatchAction) == null ? void 0 : _a.call(ctx, act);
|
|
1177
1283
|
};
|
|
1178
1284
|
if (inline || card.cta_url) tile.addEventListener("click", open);
|
|
1179
1285
|
if (frame.celebrate_on_show === true && ctx.playReaction) {
|
|
@@ -1206,6 +1312,7 @@ function renderCarouselCards(ctx) {
|
|
|
1206
1312
|
}
|
|
1207
1313
|
const autoplay = Number(ic.autoplay_ms) || 0;
|
|
1208
1314
|
const loop = ic.loop !== false;
|
|
1315
|
+
const layout = ic.rec_layout || "row";
|
|
1209
1316
|
addAnimationStyles();
|
|
1210
1317
|
ensureInAppFont();
|
|
1211
1318
|
const bg = "#ffffff";
|
|
@@ -1253,20 +1360,26 @@ function renderCarouselCards(ctx) {
|
|
|
1253
1360
|
header.appendChild(closeBtn);
|
|
1254
1361
|
card.appendChild(header);
|
|
1255
1362
|
const track = document.createElement("div");
|
|
1256
|
-
|
|
1257
|
-
display:
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1363
|
+
if (layout === "grid") {
|
|
1364
|
+
track.style.cssText = "display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 4px 2px;";
|
|
1365
|
+
} else if (layout === "list") {
|
|
1366
|
+
track.style.cssText = "display: flex; flex-direction: column; gap: 10px; padding: 4px 2px;";
|
|
1367
|
+
} else {
|
|
1368
|
+
track.style.cssText = `
|
|
1369
|
+
display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x proximity;
|
|
1370
|
+
scroll-padding-left: 0; scrollbar-width: none; -ms-overflow-style: none;
|
|
1371
|
+
/* room so overflow-x: auto doesn't clip the card drop-shadow */
|
|
1372
|
+
padding: 8px 6px 16px; margin: -8px -6px -6px; -webkit-overflow-scrolling: touch;
|
|
1373
|
+
`;
|
|
1374
|
+
track.style.msOverflowStyle = "none";
|
|
1375
|
+
}
|
|
1263
1376
|
const template = resolveGlobalTemplate(ic);
|
|
1264
1377
|
cards.forEach((c, i) => {
|
|
1265
1378
|
const tile = renderCardFromTemplate(c, {
|
|
1266
1379
|
template,
|
|
1267
1380
|
ctx,
|
|
1268
1381
|
action: "navigate",
|
|
1269
|
-
layout
|
|
1382
|
+
layout,
|
|
1270
1383
|
layoutAccent: accent
|
|
1271
1384
|
});
|
|
1272
1385
|
tile.setAttribute("data-card-index", String(i));
|
|
@@ -1276,6 +1389,12 @@ function renderCarouselCards(ctx) {
|
|
|
1276
1389
|
track.appendChild(tile);
|
|
1277
1390
|
});
|
|
1278
1391
|
card.appendChild(track);
|
|
1392
|
+
if (layout !== "row") {
|
|
1393
|
+
cards.forEach((_, i) => trackEvent(campaign.id, "impression", { stepId: `card_${i}` }));
|
|
1394
|
+
overlay.appendChild(card);
|
|
1395
|
+
document.body.appendChild(overlay);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1279
1398
|
const dots = document.createElement("div");
|
|
1280
1399
|
dots.style.cssText = "display: flex; justify-content: center; gap: 6px; margin-top: 10px;";
|
|
1281
1400
|
const dotEls = [];
|
|
@@ -1305,9 +1424,9 @@ function renderCarouselCards(ctx) {
|
|
|
1305
1424
|
const tiles = track.querySelectorAll("[data-card-index]");
|
|
1306
1425
|
const goto = (idx) => {
|
|
1307
1426
|
activeIdx = (idx % cards.length + cards.length) % cards.length;
|
|
1308
|
-
const
|
|
1309
|
-
if (
|
|
1310
|
-
const delta =
|
|
1427
|
+
const el2 = tiles[activeIdx];
|
|
1428
|
+
if (el2) {
|
|
1429
|
+
const delta = el2.getBoundingClientRect().left - track.getBoundingClientRect().left;
|
|
1311
1430
|
track.scrollTo({ left: track.scrollLeft + delta, behavior: "smooth" });
|
|
1312
1431
|
setActive(activeIdx);
|
|
1313
1432
|
}
|
|
@@ -1924,6 +2043,10 @@ function renderProductRecommendation(ctx) {
|
|
|
1924
2043
|
display: flex; gap: 10px; overflow-x: auto;
|
|
1925
2044
|
scroll-snap-type: x mandatory; padding: 14px 2px 18px;
|
|
1926
2045
|
`;
|
|
2046
|
+
} else if (layout === "list") {
|
|
2047
|
+
grid.style.cssText = `
|
|
2048
|
+
display: flex; flex-direction: column; gap: 10px; padding: 14px 2px 6px;
|
|
2049
|
+
`;
|
|
1927
2050
|
} else {
|
|
1928
2051
|
grid.style.cssText = `
|
|
1929
2052
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
|
|
@@ -1980,9 +2103,11 @@ function renderProductRecommendationInline(ctx, target) {
|
|
|
1980
2103
|
section.appendChild(body);
|
|
1981
2104
|
}
|
|
1982
2105
|
const grid = document.createElement("div");
|
|
1983
|
-
const isRow = layout !== "grid";
|
|
2106
|
+
const isRow = layout === "row" || layout !== "grid" && layout !== "list";
|
|
1984
2107
|
if (layout === "grid") {
|
|
1985
2108
|
grid.style.cssText = "display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;";
|
|
2109
|
+
} else if (layout === "list") {
|
|
2110
|
+
grid.style.cssText = "display: flex; flex-direction: column; gap: 10px;";
|
|
1986
2111
|
} else {
|
|
1987
2112
|
grid.style.cssText = `
|
|
1988
2113
|
display: flex; gap: 10px; overflow-x: auto;
|
|
@@ -2525,10 +2650,10 @@ function brandAccent(ctx) {
|
|
|
2525
2650
|
function injectGameStyles() {
|
|
2526
2651
|
if (typeof document === "undefined" || document.getElementById("aegis-game-styles")) return;
|
|
2527
2652
|
if (typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
2528
|
-
const
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
document.head.appendChild(
|
|
2653
|
+
const el2 = document.createElement("style");
|
|
2654
|
+
el2.id = "aegis-game-styles";
|
|
2655
|
+
el2.textContent = "@keyframes aegisBoxRattle{0%,100%{transform:scale(1) rotate(0)}20%{transform:scale(1.05) rotate(-4deg)}40%{transform:scale(1.05) rotate(4deg)}60%{transform:scale(1.06) rotate(-3deg)}80%{transform:scale(1.06) rotate(3deg)}}@keyframes aegisStampIn{0%{transform:scale(2.4) rotate(-20deg);opacity:0}55%{transform:scale(0.82) rotate(7deg);opacity:1}100%{transform:scale(1) rotate(-6deg);opacity:1}}@keyframes aegisBadgePop{0%{transform:scale(0) rotate(-12deg);opacity:0}70%{transform:scale(1.18) rotate(4deg);opacity:1}100%{transform:scale(1) rotate(0);opacity:1}}";
|
|
2656
|
+
document.head.appendChild(el2);
|
|
2532
2657
|
}
|
|
2533
2658
|
function openGameModal(ctx, className, maxWidth = 360) {
|
|
2534
2659
|
const { campaign, trackEvent, addAnimationStyles } = ctx;
|
|
@@ -2623,10 +2748,10 @@ function renderStreak(ctx) {
|
|
|
2623
2748
|
s.content.appendChild(gEl("div", "font-size:22px;font-weight:800;margin:4px 0 2px", `${count}-day streak!`));
|
|
2624
2749
|
const chips = gEl("div", "display:flex;justify-content:center;gap:8px;margin:12px 0");
|
|
2625
2750
|
for (let i = 0; i < 7; i++) {
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
chips.appendChild(
|
|
2751
|
+
const chip2 = gEl("div", "display:inline-flex;flex-direction:column;align-items:center;gap:3px;font-size:11px;opacity:0.8");
|
|
2752
|
+
chip2.appendChild(gEl("span", "", days[i]));
|
|
2753
|
+
chip2.appendChild(gEl("span", "font-size:16px", i < count % 7 || count >= 7 && i < 7 ? "✅" : i === count % 7 ? "🔥" : "⚪"));
|
|
2754
|
+
chips.appendChild(chip2);
|
|
2630
2755
|
}
|
|
2631
2756
|
s.content.appendChild(chips);
|
|
2632
2757
|
const note = gEl("div", "font-size:13px;opacity:0.8");
|
|
@@ -3991,15 +4116,15 @@ class AegisChat {
|
|
|
3991
4116
|
row.className = "aegis-chat-quickreplies";
|
|
3992
4117
|
for (const label of this.quickReplies) {
|
|
3993
4118
|
if (typeof label !== "string" || !label.trim()) continue;
|
|
3994
|
-
const
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
4119
|
+
const chip2 = document.createElement("button");
|
|
4120
|
+
chip2.type = "button";
|
|
4121
|
+
chip2.className = "aegis-chat-chip";
|
|
4122
|
+
chip2.textContent = label;
|
|
4123
|
+
chip2.addEventListener("click", () => {
|
|
3999
4124
|
row.remove();
|
|
4000
4125
|
void this.send(label);
|
|
4001
4126
|
});
|
|
4002
|
-
row.appendChild(
|
|
4127
|
+
row.appendChild(chip2);
|
|
4003
4128
|
}
|
|
4004
4129
|
if (row.childElementCount > 0) this.thread.appendChild(row);
|
|
4005
4130
|
}
|
|
@@ -4036,8 +4161,8 @@ class AegisChat {
|
|
|
4036
4161
|
}
|
|
4037
4162
|
if (msg.interactive && Array.isArray(msg.interactive)) {
|
|
4038
4163
|
for (const inter of msg.interactive) {
|
|
4039
|
-
const
|
|
4040
|
-
if (
|
|
4164
|
+
const el2 = this.renderInteractive(inter);
|
|
4165
|
+
if (el2) row.appendChild(el2);
|
|
4041
4166
|
}
|
|
4042
4167
|
}
|
|
4043
4168
|
this.thread.appendChild(row);
|
|
@@ -4901,6 +5026,408 @@ function disposeActiveWebChat() {
|
|
|
4901
5026
|
activeInstance == null ? void 0 : activeInstance.destroy();
|
|
4902
5027
|
activeInstance = null;
|
|
4903
5028
|
}
|
|
5029
|
+
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
5030
|
+
function el(tag, css, text) {
|
|
5031
|
+
const e = document.createElement(tag);
|
|
5032
|
+
if (css) e.style.cssText = css;
|
|
5033
|
+
if (text != null) e.textContent = text;
|
|
5034
|
+
return e;
|
|
5035
|
+
}
|
|
5036
|
+
function stars(rating, size = 14) {
|
|
5037
|
+
const wrap = el("span", "display:inline-flex;gap:1px;vertical-align:middle;");
|
|
5038
|
+
wrap.setAttribute("aria-label", `${rating} out of 5`);
|
|
5039
|
+
for (let i = 1; i <= 5; i++) {
|
|
5040
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5041
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5042
|
+
svg.setAttribute("width", String(size));
|
|
5043
|
+
svg.setAttribute("height", String(size));
|
|
5044
|
+
const path = document.createElementNS(SVG_NS, "path");
|
|
5045
|
+
path.setAttribute(
|
|
5046
|
+
"d",
|
|
5047
|
+
"M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
|
|
5048
|
+
);
|
|
5049
|
+
path.setAttribute("fill", i <= rating ? "#f59e0b" : "#e2e8f0");
|
|
5050
|
+
svg.appendChild(path);
|
|
5051
|
+
wrap.appendChild(svg);
|
|
5052
|
+
}
|
|
5053
|
+
return wrap;
|
|
5054
|
+
}
|
|
5055
|
+
function chip(text, kind) {
|
|
5056
|
+
const palette = kind === "verified" ? "background:#ecfdf5;color:#047857;" : "background:#fffbeb;color:#b45309;";
|
|
5057
|
+
return el(
|
|
5058
|
+
"span",
|
|
5059
|
+
`display:inline-flex;align-items:center;font-size:11px;font-weight:600;padding:2px 8px;border-radius:999px;${palette}`,
|
|
5060
|
+
text
|
|
5061
|
+
);
|
|
5062
|
+
}
|
|
5063
|
+
function sparkles() {
|
|
5064
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5065
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5066
|
+
svg.setAttribute("width", "15");
|
|
5067
|
+
svg.setAttribute("height", "15");
|
|
5068
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5069
|
+
p.setAttribute("d", "M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6L12 3z");
|
|
5070
|
+
p.setAttribute("fill", "#7c3aed");
|
|
5071
|
+
svg.appendChild(p);
|
|
5072
|
+
return svg;
|
|
5073
|
+
}
|
|
5074
|
+
function miniStar() {
|
|
5075
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5076
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5077
|
+
svg.setAttribute("width", "11");
|
|
5078
|
+
svg.setAttribute("height", "11");
|
|
5079
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5080
|
+
p.setAttribute(
|
|
5081
|
+
"d",
|
|
5082
|
+
"M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
|
|
5083
|
+
);
|
|
5084
|
+
p.setAttribute("fill", "#f59e0b");
|
|
5085
|
+
svg.appendChild(p);
|
|
5086
|
+
return svg;
|
|
5087
|
+
}
|
|
5088
|
+
function distributionRows(dist, total) {
|
|
5089
|
+
const box = el("div", "display:flex;flex-direction:column;gap:3px;margin:10px 0 4px;");
|
|
5090
|
+
for (let r = 5; r >= 1; r--) {
|
|
5091
|
+
const n = dist[String(r)] ?? 0;
|
|
5092
|
+
const pct = total > 0 ? Math.round(n / total * 100) : 0;
|
|
5093
|
+
const row = el("div", "display:flex;align-items:center;gap:8px;font-size:12px;color:#64748b;");
|
|
5094
|
+
const label = el("span", "width:26px;display:inline-flex;align-items:center;gap:2px;color:#334155;", String(r));
|
|
5095
|
+
label.appendChild(miniStar());
|
|
5096
|
+
row.appendChild(label);
|
|
5097
|
+
const track = el("div", "flex:1;height:6px;background:#f1f5f9;border-radius:999px;overflow:hidden;");
|
|
5098
|
+
track.appendChild(el("div", `width:${pct}%;height:100%;background:#f59e0b;`));
|
|
5099
|
+
row.appendChild(track);
|
|
5100
|
+
row.appendChild(el("span", "width:28px;text-align:right;", String(n)));
|
|
5101
|
+
box.appendChild(row);
|
|
5102
|
+
}
|
|
5103
|
+
return box;
|
|
5104
|
+
}
|
|
5105
|
+
function injectJsonLd(target, data, productId) {
|
|
5106
|
+
if (!data.aggregate.count || data.aggregate.avg_rating == null) return;
|
|
5107
|
+
const ld = {
|
|
5108
|
+
"@context": "https://schema.org",
|
|
5109
|
+
"@type": "Product",
|
|
5110
|
+
...productId ? { sku: productId } : {},
|
|
5111
|
+
aggregateRating: {
|
|
5112
|
+
"@type": "AggregateRating",
|
|
5113
|
+
ratingValue: data.aggregate.avg_rating,
|
|
5114
|
+
reviewCount: data.aggregate.count
|
|
5115
|
+
},
|
|
5116
|
+
review: data.items.slice(0, 10).map((r) => {
|
|
5117
|
+
var _a;
|
|
5118
|
+
return {
|
|
5119
|
+
"@type": "Review",
|
|
5120
|
+
reviewRating: { "@type": "Rating", ratingValue: r.rating ?? 0 },
|
|
5121
|
+
author: { "@type": "Person", name: ((_a = r.reviewer_snapshot) == null ? void 0 : _a.name) ?? "Customer" },
|
|
5122
|
+
...r.review_text ? { reviewBody: r.review_text } : {}
|
|
5123
|
+
};
|
|
5124
|
+
})
|
|
5125
|
+
};
|
|
5126
|
+
const script = document.createElement("script");
|
|
5127
|
+
script.type = "application/ld+json";
|
|
5128
|
+
script.textContent = JSON.stringify(ld);
|
|
5129
|
+
target.appendChild(script);
|
|
5130
|
+
}
|
|
5131
|
+
function thumbSvg(up) {
|
|
5132
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5133
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5134
|
+
svg.setAttribute("width", "14");
|
|
5135
|
+
svg.setAttribute("height", "14");
|
|
5136
|
+
if (!up) svg.style.cssText = "transform:rotate(180deg);";
|
|
5137
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5138
|
+
p.setAttribute(
|
|
5139
|
+
"d",
|
|
5140
|
+
"M2 21h4V9H2v12zM23 10a2 2 0 0 0-2-2h-6.31l.95-4.57.03-.32a1.5 1.5 0 0 0-.44-1.06L14.17 1 7.59 7.59A2 2 0 0 0 7 9v10a2 2 0 0 0 2 2h9a2 2 0 0 0 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1z"
|
|
5141
|
+
);
|
|
5142
|
+
p.setAttribute("fill", "currentColor");
|
|
5143
|
+
svg.appendChild(p);
|
|
5144
|
+
return svg;
|
|
5145
|
+
}
|
|
5146
|
+
function helpfulButton(reviewId, up, count, creds) {
|
|
5147
|
+
const btn = el(
|
|
5148
|
+
"button",
|
|
5149
|
+
"display:inline-flex;align-items:center;gap:4px;font-size:12px;color:#64748b;background:none;border:none;cursor:pointer;padding:2px 4px;"
|
|
5150
|
+
);
|
|
5151
|
+
btn.appendChild(thumbSvg(up));
|
|
5152
|
+
const countEl = el("span", "", String(count));
|
|
5153
|
+
btn.appendChild(countEl);
|
|
5154
|
+
const voteKey = `aegis_rv_voted_${reviewId}`;
|
|
5155
|
+
const already = (() => {
|
|
5156
|
+
try {
|
|
5157
|
+
return typeof localStorage !== "undefined" && localStorage.getItem(voteKey) != null;
|
|
5158
|
+
} catch {
|
|
5159
|
+
return false;
|
|
5160
|
+
}
|
|
5161
|
+
})();
|
|
5162
|
+
if (already) btn.style.opacity = "0.5";
|
|
5163
|
+
btn.addEventListener("click", () => {
|
|
5164
|
+
try {
|
|
5165
|
+
if (localStorage.getItem(voteKey) != null) return;
|
|
5166
|
+
localStorage.setItem(voteKey, up ? "up" : "down");
|
|
5167
|
+
} catch {
|
|
5168
|
+
}
|
|
5169
|
+
countEl.textContent = String(count + 1);
|
|
5170
|
+
btn.style.opacity = "0.5";
|
|
5171
|
+
const url = new URL(`/v1/reviews/${reviewId}/helpful`, creds.apiHost);
|
|
5172
|
+
void fetch(url.toString(), {
|
|
5173
|
+
method: "POST",
|
|
5174
|
+
headers: { "X-Aegis-Write-Key": creds.writeKey, "Content-Type": "application/json" },
|
|
5175
|
+
body: JSON.stringify({ direction: up ? "up" : "down" })
|
|
5176
|
+
}).catch(() => {
|
|
5177
|
+
});
|
|
5178
|
+
});
|
|
5179
|
+
return btn;
|
|
5180
|
+
}
|
|
5181
|
+
function reviewCard(ctx, r, creds) {
|
|
5182
|
+
var _a, _b;
|
|
5183
|
+
const li = el("li", "padding:14px 0;border-top:1px solid #e2e8f0;");
|
|
5184
|
+
const meta = el("div", "display:flex;flex-wrap:wrap;align-items:center;gap:8px;");
|
|
5185
|
+
meta.appendChild(stars(r.rating ?? 0));
|
|
5186
|
+
meta.appendChild(el("span", "font-size:14px;font-weight:600;", ((_a = r.reviewer_snapshot) == null ? void 0 : _a.name) ?? "Customer"));
|
|
5187
|
+
if (r.verified_purchase) meta.appendChild(chip("Verified purchase", "verified"));
|
|
5188
|
+
if (r.is_incentivized) meta.appendChild(chip("Reward included", "reward"));
|
|
5189
|
+
if (r.created_at) {
|
|
5190
|
+
const d = new Date(r.created_at);
|
|
5191
|
+
if (!Number.isNaN(d.getTime())) {
|
|
5192
|
+
meta.appendChild(el("span", "margin-left:auto;font-size:12px;color:#94a3b8;", d.toLocaleDateString()));
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
5195
|
+
li.appendChild(meta);
|
|
5196
|
+
if (r.review_text) {
|
|
5197
|
+
li.appendChild(el("p", "margin:6px 0 0;font-size:14px;line-height:1.5;color:#334155;", r.review_text));
|
|
5198
|
+
}
|
|
5199
|
+
if (r.media && r.media.length > 0) {
|
|
5200
|
+
const gallery = el("div", "display:flex;gap:6px;margin-top:8px;");
|
|
5201
|
+
for (const m2 of r.media.slice(0, 6)) {
|
|
5202
|
+
const safe = ctx.sanitizeUrl(m2.url);
|
|
5203
|
+
if (!safe) continue;
|
|
5204
|
+
const img = document.createElement("img");
|
|
5205
|
+
img.src = safe;
|
|
5206
|
+
img.loading = "lazy";
|
|
5207
|
+
img.alt = "";
|
|
5208
|
+
img.style.cssText = "width:56px;height:56px;object-fit:cover;border-radius:8px;";
|
|
5209
|
+
gallery.appendChild(img);
|
|
5210
|
+
}
|
|
5211
|
+
if (gallery.childElementCount) li.appendChild(gallery);
|
|
5212
|
+
}
|
|
5213
|
+
if ((_b = r.operator_reply) == null ? void 0 : _b.text) {
|
|
5214
|
+
const reply = el(
|
|
5215
|
+
"div",
|
|
5216
|
+
"margin-top:8px;padding:8px 10px;background:#f8fafc;border-radius:8px;font-size:13px;color:#475569;"
|
|
5217
|
+
);
|
|
5218
|
+
reply.appendChild(el("span", "font-weight:600;margin-right:6px;", "Reply"));
|
|
5219
|
+
reply.appendChild(el("span", "", r.operator_reply.text));
|
|
5220
|
+
li.appendChild(reply);
|
|
5221
|
+
}
|
|
5222
|
+
const votes = el("div", "display:flex;align-items:center;gap:10px;margin-top:8px;");
|
|
5223
|
+
votes.appendChild(el("span", "font-size:12px;color:#94a3b8;", "Helpful?"));
|
|
5224
|
+
votes.appendChild(helpfulButton(r.id, true, r.helpful_count ?? 0, creds));
|
|
5225
|
+
votes.appendChild(helpfulButton(r.id, false, r.not_helpful_count ?? 0, creds));
|
|
5226
|
+
li.appendChild(votes);
|
|
5227
|
+
return li;
|
|
5228
|
+
}
|
|
5229
|
+
const SORTS = [
|
|
5230
|
+
{ key: "recent", label: "Most recent" },
|
|
5231
|
+
{ key: "helpful", label: "Most helpful" },
|
|
5232
|
+
{ key: "rating", label: "Highest rated" }
|
|
5233
|
+
];
|
|
5234
|
+
function renderReviewsInline(ctx, target, creds) {
|
|
5235
|
+
var _a;
|
|
5236
|
+
if (typeof document === "undefined" || !(creds == null ? void 0 : creds.apiHost) || !(creds == null ? void 0 : creds.writeKey)) return false;
|
|
5237
|
+
const productId = target.getAttribute("data-product-id") || ctx.campaign.product_id || null;
|
|
5238
|
+
const state = { sort: "recent", withPhotos: false };
|
|
5239
|
+
target.innerHTML = "";
|
|
5240
|
+
target.appendChild(el("div", "font-size:13px;color:#94a3b8;padding:8px 0;", "Loading reviews…"));
|
|
5241
|
+
function buildUrl() {
|
|
5242
|
+
const url = new URL("/v1/reviews/public", creds.apiHost);
|
|
5243
|
+
if (productId) url.searchParams.set("product_id", productId);
|
|
5244
|
+
url.searchParams.set("sort", state.sort);
|
|
5245
|
+
if (state.withPhotos) url.searchParams.set("with_photos", "true");
|
|
5246
|
+
url.searchParams.set("limit", "20");
|
|
5247
|
+
return url.toString();
|
|
5248
|
+
}
|
|
5249
|
+
function fetchReviews() {
|
|
5250
|
+
return fetch(buildUrl(), { method: "GET", headers: { "X-Aegis-Write-Key": creds.writeKey } }).then((r) => r.ok ? r.json() : null).catch(() => null);
|
|
5251
|
+
}
|
|
5252
|
+
let listContainer = null;
|
|
5253
|
+
function renderList(items) {
|
|
5254
|
+
if (!listContainer) return;
|
|
5255
|
+
listContainer.innerHTML = "";
|
|
5256
|
+
if (items.length === 0) {
|
|
5257
|
+
listContainer.appendChild(el("p", "padding:14px 0;font-size:13px;color:#94a3b8;", "No reviews match this filter."));
|
|
5258
|
+
return;
|
|
5259
|
+
}
|
|
5260
|
+
const ul = el("ul", "list-style:none;margin:0;padding:0;");
|
|
5261
|
+
for (const r of items) ul.appendChild(reviewCard(ctx, r, creds));
|
|
5262
|
+
listContainer.appendChild(ul);
|
|
5263
|
+
}
|
|
5264
|
+
function controls(onChange) {
|
|
5265
|
+
const bar = el("div", "display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:10px 0;");
|
|
5266
|
+
const sel = document.createElement("select");
|
|
5267
|
+
sel.style.cssText = "font-size:13px;padding:4px 8px;border:1px solid #e2e8f0;border-radius:999px;background:#fff;color:#334155;";
|
|
5268
|
+
for (const s of SORTS) {
|
|
5269
|
+
const opt = document.createElement("option");
|
|
5270
|
+
opt.value = s.key;
|
|
5271
|
+
opt.textContent = s.label;
|
|
5272
|
+
sel.appendChild(opt);
|
|
5273
|
+
}
|
|
5274
|
+
sel.value = state.sort;
|
|
5275
|
+
sel.addEventListener("change", () => {
|
|
5276
|
+
state.sort = sel.value;
|
|
5277
|
+
onChange();
|
|
5278
|
+
});
|
|
5279
|
+
bar.appendChild(sel);
|
|
5280
|
+
const photos = el(
|
|
5281
|
+
"button",
|
|
5282
|
+
"font-size:13px;padding:4px 12px;border:1px solid #e2e8f0;border-radius:999px;background:#fff;color:#334155;cursor:pointer;",
|
|
5283
|
+
"With photos"
|
|
5284
|
+
);
|
|
5285
|
+
photos.addEventListener("click", () => {
|
|
5286
|
+
state.withPhotos = !state.withPhotos;
|
|
5287
|
+
photos.style.cssText = "font-size:13px;padding:4px 12px;border-radius:999px;cursor:pointer;" + (state.withPhotos ? "background:#4169e1;color:#fff;border:1px solid #4169e1;" : "background:#fff;color:#334155;border:1px solid #e2e8f0;");
|
|
5288
|
+
onChange();
|
|
5289
|
+
});
|
|
5290
|
+
bar.appendChild(photos);
|
|
5291
|
+
return bar;
|
|
5292
|
+
}
|
|
5293
|
+
function renderWall(data) {
|
|
5294
|
+
target.innerHTML = "";
|
|
5295
|
+
const root = el(
|
|
5296
|
+
"section",
|
|
5297
|
+
"font-family:Inter,system-ui,-apple-system,sans-serif;color:#0f172a;max-width:760px;"
|
|
5298
|
+
);
|
|
5299
|
+
root.setAttribute("data-aegis-reviews", "true");
|
|
5300
|
+
const summary = data.aggregate.ai_summary;
|
|
5301
|
+
if (summary && summary.text) {
|
|
5302
|
+
const card = el(
|
|
5303
|
+
"div",
|
|
5304
|
+
"border:1px solid #ede9fe;background:#faf5ff;border-radius:12px;padding:12px 14px;margin-bottom:14px;"
|
|
5305
|
+
);
|
|
5306
|
+
const h = el("div", "display:flex;align-items:center;gap:6px;margin-bottom:6px;");
|
|
5307
|
+
h.appendChild(sparkles());
|
|
5308
|
+
h.appendChild(el("span", "font-size:12px;font-weight:700;color:#7c3aed;text-transform:uppercase;letter-spacing:.04em;", "AI summary"));
|
|
5309
|
+
card.appendChild(h);
|
|
5310
|
+
card.appendChild(el("p", "margin:0;font-size:14px;line-height:1.5;color:#334155;", summary.text));
|
|
5311
|
+
card.appendChild(
|
|
5312
|
+
el("p", "margin:6px 0 0;font-size:11px;color:#a78bda;text-align:right;", `summarized from ${summary.review_count} reviews`)
|
|
5313
|
+
);
|
|
5314
|
+
root.appendChild(card);
|
|
5315
|
+
}
|
|
5316
|
+
const head = el("div", "display:flex;align-items:center;gap:8px;");
|
|
5317
|
+
const avg = data.aggregate.avg_rating ?? 0;
|
|
5318
|
+
head.appendChild(stars(Math.round(avg), 18));
|
|
5319
|
+
head.appendChild(el("span", "font-size:20px;font-weight:700;", avg ? avg.toFixed(1) : "—"));
|
|
5320
|
+
head.appendChild(
|
|
5321
|
+
el("span", "font-size:13px;color:#64748b;", `${data.aggregate.count} review${data.aggregate.count === 1 ? "" : "s"}`)
|
|
5322
|
+
);
|
|
5323
|
+
root.appendChild(head);
|
|
5324
|
+
if (data.aggregate.count === 0) {
|
|
5325
|
+
root.appendChild(el("p", "margin-top:8px;font-size:14px;color:#94a3b8;", "No reviews yet."));
|
|
5326
|
+
target.appendChild(root);
|
|
5327
|
+
return;
|
|
5328
|
+
}
|
|
5329
|
+
root.appendChild(distributionRows(data.aggregate.distribution, data.aggregate.count));
|
|
5330
|
+
root.appendChild(
|
|
5331
|
+
controls(() => {
|
|
5332
|
+
void fetchReviews().then((d) => renderList((d == null ? void 0 : d.items) ?? []));
|
|
5333
|
+
})
|
|
5334
|
+
);
|
|
5335
|
+
listContainer = el("div");
|
|
5336
|
+
root.appendChild(listContainer);
|
|
5337
|
+
renderList(data.items);
|
|
5338
|
+
target.appendChild(root);
|
|
5339
|
+
injectJsonLd(target, data, productId);
|
|
5340
|
+
ctx.trackEvent(ctx.campaign.id, "impression");
|
|
5341
|
+
}
|
|
5342
|
+
const displayStyle = (_a = ctx.campaign.interactive_config) == null ? void 0 : _a["display_style"];
|
|
5343
|
+
const compact = displayStyle === "compact";
|
|
5344
|
+
function renderCompact(data) {
|
|
5345
|
+
var _a2;
|
|
5346
|
+
target.innerHTML = "";
|
|
5347
|
+
if (data.aggregate.count === 0) return;
|
|
5348
|
+
const root = el(
|
|
5349
|
+
"section",
|
|
5350
|
+
"font-family:Inter,system-ui,-apple-system,sans-serif;color:#0f172a;max-width:760px;border:1px solid #e2e8f0;border-radius:12px;padding:12px 14px;"
|
|
5351
|
+
);
|
|
5352
|
+
const line = el("div", "display:flex;align-items:center;gap:8px;");
|
|
5353
|
+
const avg = data.aggregate.avg_rating ?? 0;
|
|
5354
|
+
line.appendChild(stars(Math.round(avg), 16));
|
|
5355
|
+
line.appendChild(el("span", "font-size:15px;font-weight:700;", avg ? avg.toFixed(1) : "—"));
|
|
5356
|
+
line.appendChild(el("span", "font-size:13px;color:#64748b;", `(${data.aggregate.count})`));
|
|
5357
|
+
line.appendChild(chip("Verified reviews", "verified"));
|
|
5358
|
+
root.appendChild(line);
|
|
5359
|
+
const top = data.items.find((i) => i.review_text);
|
|
5360
|
+
if (top && top.review_text) {
|
|
5361
|
+
const q = el("p", "margin:8px 0 0;font-size:14px;color:#334155;", `“${top.review_text}”`);
|
|
5362
|
+
root.appendChild(q);
|
|
5363
|
+
root.appendChild(
|
|
5364
|
+
el("span", "font-size:12px;color:#94a3b8;", `— ${((_a2 = top.reviewer_snapshot) == null ? void 0 : _a2.name) ?? "Customer"}`)
|
|
5365
|
+
);
|
|
5366
|
+
}
|
|
5367
|
+
const seeAll = el(
|
|
5368
|
+
"button",
|
|
5369
|
+
"margin-top:10px;font-size:13px;font-weight:600;color:#4169e1;background:none;border:none;cursor:pointer;padding:0;",
|
|
5370
|
+
"See all reviews"
|
|
5371
|
+
);
|
|
5372
|
+
seeAll.addEventListener("click", () => renderWall(data));
|
|
5373
|
+
root.appendChild(seeAll);
|
|
5374
|
+
target.appendChild(root);
|
|
5375
|
+
ctx.trackEvent(ctx.campaign.id, "impression");
|
|
5376
|
+
}
|
|
5377
|
+
void fetchReviews().then((data) => {
|
|
5378
|
+
if (!data || !Array.isArray(data.items)) {
|
|
5379
|
+
target.innerHTML = "";
|
|
5380
|
+
return;
|
|
5381
|
+
}
|
|
5382
|
+
if (compact) renderCompact(data);
|
|
5383
|
+
else renderWall(data);
|
|
5384
|
+
});
|
|
5385
|
+
return true;
|
|
5386
|
+
}
|
|
5387
|
+
function renderReviewsOverlay(ctx, creds) {
|
|
5388
|
+
if (typeof document === "undefined" || !(creds == null ? void 0 : creds.apiHost) || !(creds == null ? void 0 : creds.writeKey)) return;
|
|
5389
|
+
const overlay = document.createElement("div");
|
|
5390
|
+
overlay.setAttribute("data-campaign-id", ctx.campaign.id);
|
|
5391
|
+
overlay.style.cssText = "position:fixed;inset:0;background:rgba(15,23,42,0.55);display:flex;align-items:flex-end;justify-content:center;z-index:99999;";
|
|
5392
|
+
const sheet = document.createElement("div");
|
|
5393
|
+
sheet.style.cssText = "background:#fff;color:#0f172a;max-width:620px;width:100%;max-height:82vh;overflow-y:auto;border-radius:20px 20px 0 0;padding:16px 16px 24px;font-family:Inter,system-ui,-apple-system,sans-serif;box-shadow:0 -12px 30px rgba(0,0,0,0.12);";
|
|
5394
|
+
const handle = el("div", "width:36px;height:4px;border-radius:999px;background:#e2e8f0;margin:0 auto 12px;");
|
|
5395
|
+
sheet.appendChild(handle);
|
|
5396
|
+
const bar = el("div", "display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;");
|
|
5397
|
+
bar.appendChild(el("div", "font-weight:700;font-size:16px;", ctx.campaign.title || "Customer reviews"));
|
|
5398
|
+
const close = el("button", "background:none;border:none;cursor:pointer;padding:4px 8px;color:#64748b;");
|
|
5399
|
+
const xsvg = document.createElementNS(SVG_NS, "svg");
|
|
5400
|
+
xsvg.setAttribute("viewBox", "0 0 24 24");
|
|
5401
|
+
xsvg.setAttribute("width", "18");
|
|
5402
|
+
xsvg.setAttribute("height", "18");
|
|
5403
|
+
const xp = document.createElementNS(SVG_NS, "path");
|
|
5404
|
+
xp.setAttribute("d", "M18 6L6 18M6 6l12 12");
|
|
5405
|
+
xp.setAttribute("stroke", "currentColor");
|
|
5406
|
+
xp.setAttribute("stroke-width", "2");
|
|
5407
|
+
xp.setAttribute("stroke-linecap", "round");
|
|
5408
|
+
xsvg.appendChild(xp);
|
|
5409
|
+
close.appendChild(xsvg);
|
|
5410
|
+
close.setAttribute("aria-label", "Close");
|
|
5411
|
+
close.addEventListener("click", () => {
|
|
5412
|
+
ctx.trackEvent(ctx.campaign.id, "dismissed");
|
|
5413
|
+
overlay.remove();
|
|
5414
|
+
});
|
|
5415
|
+
bar.appendChild(close);
|
|
5416
|
+
sheet.appendChild(bar);
|
|
5417
|
+
const body = el("div");
|
|
5418
|
+
const pid = ctx.campaign.product_id;
|
|
5419
|
+
if (pid) body.setAttribute("data-product-id", pid);
|
|
5420
|
+
sheet.appendChild(body);
|
|
5421
|
+
overlay.appendChild(sheet);
|
|
5422
|
+
overlay.addEventListener("click", (e) => {
|
|
5423
|
+
if (e.target === overlay) {
|
|
5424
|
+
ctx.trackEvent(ctx.campaign.id, "dismissed");
|
|
5425
|
+
overlay.remove();
|
|
5426
|
+
}
|
|
5427
|
+
});
|
|
5428
|
+
document.body.appendChild(overlay);
|
|
5429
|
+
renderReviewsInline(ctx, body, creds);
|
|
5430
|
+
}
|
|
4904
5431
|
function readAnonIdFromStorage$1() {
|
|
4905
5432
|
if (typeof document === "undefined") return void 0;
|
|
4906
5433
|
try {
|
|
@@ -4922,6 +5449,7 @@ function svgNode(svg) {
|
|
|
4922
5449
|
}
|
|
4923
5450
|
const _AegisInAppManager = class _AegisInAppManager {
|
|
4924
5451
|
constructor(config) {
|
|
5452
|
+
this.productUrl = (sku) => `/p/${encodeURIComponent(sku)}`;
|
|
4925
5453
|
this.campaigns = [];
|
|
4926
5454
|
this.displayedCampaigns = /* @__PURE__ */ new Set();
|
|
4927
5455
|
this._displaySizeMul = 1;
|
|
@@ -4951,6 +5479,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
4951
5479
|
this.debugMode = config.debugMode || false;
|
|
4952
5480
|
this.enableSSE = config.enableSSE === true;
|
|
4953
5481
|
this.onInteractiveCampaign = config.onInteractiveCampaign;
|
|
5482
|
+
this.onActionHandler = config.onAction;
|
|
5483
|
+
if (config.productUrl) this.productUrl = config.productUrl;
|
|
4954
5484
|
this.getWorkspaceId = config.getWorkspaceId;
|
|
4955
5485
|
this.getCartState = config.getCartState;
|
|
4956
5486
|
}
|
|
@@ -5525,8 +6055,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5525
6055
|
m2.addedNodes.forEach((n) => {
|
|
5526
6056
|
var _a, _b;
|
|
5527
6057
|
if (sawSlot || n.nodeType !== 1) return;
|
|
5528
|
-
const
|
|
5529
|
-
if (((_a =
|
|
6058
|
+
const el2 = n;
|
|
6059
|
+
if (((_a = el2.matches) == null ? void 0 : _a.call(el2, "[data-aegis-slot]")) || ((_b = el2.querySelector) == null ? void 0 : _b.call(el2, "[data-aegis-slot]"))) {
|
|
5530
6060
|
sawSlot = true;
|
|
5531
6061
|
}
|
|
5532
6062
|
});
|
|
@@ -5733,13 +6263,13 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5733
6263
|
const anchor = ic == null ? void 0 : ic.anchor;
|
|
5734
6264
|
const selector = anchor == null ? void 0 : anchor.element_selector;
|
|
5735
6265
|
if (!selector) continue;
|
|
5736
|
-
let
|
|
6266
|
+
let el2 = null;
|
|
5737
6267
|
try {
|
|
5738
|
-
|
|
6268
|
+
el2 = document.querySelector(selector);
|
|
5739
6269
|
} catch {
|
|
5740
|
-
|
|
6270
|
+
el2 = null;
|
|
5741
6271
|
}
|
|
5742
|
-
if (!
|
|
6272
|
+
if (!el2) {
|
|
5743
6273
|
void this.trackEvent(c.id, "anchor_unresolved", {
|
|
5744
6274
|
meta: { anchor_resolved: false, anchor_selector: selector, widget_type: c.sub_type }
|
|
5745
6275
|
});
|
|
@@ -5750,9 +6280,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5750
6280
|
if (position === "before" || position === "after") {
|
|
5751
6281
|
target = document.createElement("div");
|
|
5752
6282
|
target.setAttribute("data-aegis-anchor-wrapper", c.id);
|
|
5753
|
-
(_a =
|
|
6283
|
+
(_a = el2.parentNode) == null ? void 0 : _a.insertBefore(target, position === "before" ? el2 : el2.nextSibling);
|
|
5754
6284
|
} else {
|
|
5755
|
-
target =
|
|
6285
|
+
target = el2;
|
|
5756
6286
|
if (position === "replace") {
|
|
5757
6287
|
target.querySelectorAll(":scope > [data-aegis-slot-default]").forEach((d) => d.remove());
|
|
5758
6288
|
}
|
|
@@ -5909,6 +6439,12 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5909
6439
|
case "product_recommendation":
|
|
5910
6440
|
rendered = renderProductRecommendationInline(this.buildRenderContext(campaign), target);
|
|
5911
6441
|
break;
|
|
6442
|
+
case "reviews":
|
|
6443
|
+
rendered = renderReviewsInline(this.buildRenderContext(campaign), target, {
|
|
6444
|
+
apiHost: this.apiHost,
|
|
6445
|
+
writeKey: this.writeKey
|
|
6446
|
+
});
|
|
6447
|
+
break;
|
|
5912
6448
|
case "quiz":
|
|
5913
6449
|
rendered = this.renderQuizSlot(campaign, ic, bg, text, target);
|
|
5914
6450
|
if (!rendered) {
|
|
@@ -6116,8 +6652,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6116
6652
|
void this.trackEvent(campaign.id, "clicked");
|
|
6117
6653
|
if (actionUrl) {
|
|
6118
6654
|
window.open(actionUrl, "_blank", "noopener");
|
|
6119
|
-
} else
|
|
6120
|
-
|
|
6655
|
+
} else {
|
|
6656
|
+
this.dispatchAction({ type: "open_login" }, campaign.id);
|
|
6121
6657
|
}
|
|
6122
6658
|
});
|
|
6123
6659
|
row.appendChild(btn);
|
|
@@ -6141,10 +6677,10 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6141
6677
|
cbody.appendChild(b);
|
|
6142
6678
|
}
|
|
6143
6679
|
if (couponCode) {
|
|
6144
|
-
const
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
cbody.appendChild(
|
|
6680
|
+
const chip2 = document.createElement("span");
|
|
6681
|
+
chip2.style.cssText = `align-self: flex-start; border: 1px dashed ${text}66; border-radius: 6px; padding: 2px 8px; font-family: monospace; font-size: 11px; letter-spacing: 0.04em;`;
|
|
6682
|
+
chip2.textContent = couponCode;
|
|
6683
|
+
cbody.appendChild(chip2);
|
|
6148
6684
|
}
|
|
6149
6685
|
if (buttonText) {
|
|
6150
6686
|
const btn = document.createElement("button");
|
|
@@ -6727,19 +7263,19 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6727
7263
|
ov.appendChild(eyebrow);
|
|
6728
7264
|
ov.appendChild(big);
|
|
6729
7265
|
if (r.code) {
|
|
6730
|
-
const
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
7266
|
+
const chip2 = document.createElement("button");
|
|
7267
|
+
chip2.type = "button";
|
|
7268
|
+
chip2.textContent = `${r.code} ⧉`;
|
|
7269
|
+
chip2.style.cssText = `margin-top: 4px; padding: 9px 16px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 14px; letter-spacing: 1px; cursor: pointer;`;
|
|
7270
|
+
chip2.addEventListener("click", () => {
|
|
6735
7271
|
var _a;
|
|
6736
7272
|
try {
|
|
6737
7273
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(r.code));
|
|
6738
|
-
|
|
7274
|
+
chip2.textContent = "Copied";
|
|
6739
7275
|
} catch {
|
|
6740
7276
|
}
|
|
6741
7277
|
});
|
|
6742
|
-
ov.appendChild(
|
|
7278
|
+
ov.appendChild(chip2);
|
|
6743
7279
|
} else if (r.kind === "freebie") {
|
|
6744
7280
|
const hint = document.createElement("div");
|
|
6745
7281
|
hint.textContent = "🎟️ Show this screen to claim";
|
|
@@ -6773,20 +7309,20 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6773
7309
|
result.textContent = "";
|
|
6774
7310
|
const tag = document.createElement("span");
|
|
6775
7311
|
tag.textContent = `${r.label} — `;
|
|
6776
|
-
const
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
7312
|
+
const chip2 = document.createElement("button");
|
|
7313
|
+
chip2.type = "button";
|
|
7314
|
+
chip2.textContent = `${r.code} ⧉`;
|
|
7315
|
+
chip2.style.cssText = `padding: 2px 8px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 12px; letter-spacing: 0.5px; cursor: pointer;`;
|
|
7316
|
+
chip2.addEventListener("click", () => {
|
|
6781
7317
|
var _a;
|
|
6782
7318
|
try {
|
|
6783
7319
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(r.code));
|
|
6784
|
-
|
|
7320
|
+
chip2.textContent = "Copied";
|
|
6785
7321
|
} catch {
|
|
6786
7322
|
}
|
|
6787
7323
|
});
|
|
6788
7324
|
result.appendChild(tag);
|
|
6789
|
-
result.appendChild(
|
|
7325
|
+
result.appendChild(chip2);
|
|
6790
7326
|
} else result.textContent = r.label || "Thanks for playing!";
|
|
6791
7327
|
retireCta();
|
|
6792
7328
|
};
|
|
@@ -6961,17 +7497,27 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6961
7497
|
h.textContent = campaign.title;
|
|
6962
7498
|
card.appendChild(h);
|
|
6963
7499
|
}
|
|
7500
|
+
const layout = ic.rec_layout || "row";
|
|
6964
7501
|
const strip = document.createElement("div");
|
|
6965
|
-
|
|
7502
|
+
const pad = `${st.padY ?? 12}px ${st.padX ?? 12}px`;
|
|
7503
|
+
if (layout === "grid") {
|
|
7504
|
+
strip.style.cssText = `display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; padding: ${pad};`;
|
|
7505
|
+
} else if (layout === "list") {
|
|
7506
|
+
strip.style.cssText = `display: flex; flex-direction: column; gap: 8px; padding: ${pad};`;
|
|
7507
|
+
} else {
|
|
7508
|
+
strip.style.cssText = `display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: ${pad};`;
|
|
7509
|
+
}
|
|
6966
7510
|
const template = resolveGlobalTemplate(ic);
|
|
6967
7511
|
const ctx = this.buildRenderContext(campaign);
|
|
6968
7512
|
const accent = this.sanitizeColor(campaign.background_color || text);
|
|
6969
7513
|
cards.forEach((c, i) => {
|
|
7514
|
+
const meta = c.metadata || {};
|
|
7515
|
+
const linked = !!(meta.product_id || meta.sku);
|
|
6970
7516
|
const tile = renderCardFromTemplate(c, {
|
|
6971
7517
|
template,
|
|
6972
7518
|
ctx,
|
|
6973
|
-
action: "navigate",
|
|
6974
|
-
layout
|
|
7519
|
+
action: linked ? "cart" : "navigate",
|
|
7520
|
+
layout,
|
|
6975
7521
|
layoutAccent: accent
|
|
6976
7522
|
});
|
|
6977
7523
|
tile.setAttribute("data-card-index", String(i));
|
|
@@ -6979,6 +7525,43 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6979
7525
|
});
|
|
6980
7526
|
card.appendChild(strip);
|
|
6981
7527
|
target.appendChild(card);
|
|
7528
|
+
const autoplayMs = Number(ic.autoplay_ms) || 0;
|
|
7529
|
+
if (layout === "row" && autoplayMs > 0 && cards.length > 1) {
|
|
7530
|
+
const loop = ic.loop !== false;
|
|
7531
|
+
const interval = Math.max(autoplayMs, 600);
|
|
7532
|
+
let idx = 0;
|
|
7533
|
+
let timer = null;
|
|
7534
|
+
const stop = () => {
|
|
7535
|
+
if (timer) {
|
|
7536
|
+
clearInterval(timer);
|
|
7537
|
+
timer = null;
|
|
7538
|
+
}
|
|
7539
|
+
};
|
|
7540
|
+
timer = setInterval(() => {
|
|
7541
|
+
if (!document.body.contains(strip)) {
|
|
7542
|
+
stop();
|
|
7543
|
+
return;
|
|
7544
|
+
}
|
|
7545
|
+
if (strip.scrollWidth <= strip.clientWidth + 4) return;
|
|
7546
|
+
const tiles = Array.from(strip.children);
|
|
7547
|
+
idx += 1;
|
|
7548
|
+
if (idx >= tiles.length) {
|
|
7549
|
+
if (!loop) {
|
|
7550
|
+
stop();
|
|
7551
|
+
return;
|
|
7552
|
+
}
|
|
7553
|
+
idx = 0;
|
|
7554
|
+
}
|
|
7555
|
+
const el2 = tiles[idx];
|
|
7556
|
+
if (el2) {
|
|
7557
|
+
const delta = el2.getBoundingClientRect().left - strip.getBoundingClientRect().left;
|
|
7558
|
+
strip.scrollTo({ left: strip.scrollLeft + delta, behavior: "smooth" });
|
|
7559
|
+
}
|
|
7560
|
+
}, interval);
|
|
7561
|
+
["pointerdown", "wheel", "touchstart"].forEach(
|
|
7562
|
+
(evt) => strip.addEventListener(evt, stop, { passive: true })
|
|
7563
|
+
);
|
|
7564
|
+
}
|
|
6982
7565
|
return true;
|
|
6983
7566
|
}
|
|
6984
7567
|
/** Built-in embedded COUNTDOWN — live H:M:S digits that pulse red in the
|
|
@@ -7001,10 +7584,10 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7001
7584
|
const digits = document.createElement("div");
|
|
7002
7585
|
digits.style.cssText = "display: flex; gap: 6px; justify-content: center;";
|
|
7003
7586
|
const mkDigit = () => {
|
|
7004
|
-
const
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
return
|
|
7587
|
+
const el2 = document.createElement("span");
|
|
7588
|
+
el2.style.cssText = `padding: 6px 9px; border-radius: 8px; font-size: 18px; font-weight: 700; font-family: ui-monospace, monospace; background: ${text}1a; transition: background 0.3s ease, color 0.3s ease;`;
|
|
7589
|
+
el2.textContent = "00";
|
|
7590
|
+
return el2;
|
|
7008
7591
|
};
|
|
7009
7592
|
const hEl = mkDigit();
|
|
7010
7593
|
const mEl = mkDigit();
|
|
@@ -7034,9 +7617,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7034
7617
|
sEl.textContent = String(s).padStart(2, "0");
|
|
7035
7618
|
if (diff > 0 && diff <= 6e4 && !urgent) {
|
|
7036
7619
|
urgent = true;
|
|
7037
|
-
[hEl, mEl, sEl].forEach((
|
|
7038
|
-
|
|
7039
|
-
|
|
7620
|
+
[hEl, mEl, sEl].forEach((el2) => {
|
|
7621
|
+
el2.style.boxShadow = "0 0 0 2px #ef4444";
|
|
7622
|
+
el2.style.animation = "aegisUrgencyPulse 1s ease-in-out infinite";
|
|
7040
7623
|
});
|
|
7041
7624
|
}
|
|
7042
7625
|
if (diff > 0) requestAnimationFrame(tick);
|
|
@@ -7391,19 +7974,19 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7391
7974
|
ov.appendChild(eb);
|
|
7392
7975
|
ov.appendChild(big);
|
|
7393
7976
|
if (code) {
|
|
7394
|
-
const
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7977
|
+
const chip2 = document.createElement("button");
|
|
7978
|
+
chip2.type = "button";
|
|
7979
|
+
chip2.textContent = `${code} ⧉`;
|
|
7980
|
+
chip2.style.cssText = `margin-top: 4px; padding: 8px 14px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 13px; letter-spacing: 1px; cursor: pointer;`;
|
|
7981
|
+
chip2.addEventListener("click", () => {
|
|
7399
7982
|
var _a;
|
|
7400
7983
|
try {
|
|
7401
7984
|
void ((_a = navigator.clipboard) == null ? void 0 : _a.writeText(code));
|
|
7402
|
-
|
|
7985
|
+
chip2.textContent = "Copied";
|
|
7403
7986
|
} catch {
|
|
7404
7987
|
}
|
|
7405
7988
|
});
|
|
7406
|
-
ov.appendChild(
|
|
7989
|
+
ov.appendChild(chip2);
|
|
7407
7990
|
}
|
|
7408
7991
|
card.appendChild(ov);
|
|
7409
7992
|
try {
|
|
@@ -7413,10 +7996,10 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7413
7996
|
} else {
|
|
7414
7997
|
prizeText.textContent = icoVal && !isUrl(icoVal) ? `${icoVal} ${label}` : label;
|
|
7415
7998
|
if (code) {
|
|
7416
|
-
const
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
body.appendChild(
|
|
7999
|
+
const chip2 = document.createElement("div");
|
|
8000
|
+
chip2.style.cssText = `margin-top: 6px; font-family: ui-monospace, monospace; font-size: 12px; font-weight: 700; padding: 4px 8px; border-radius: 6px; background: ${text}14; color: ${text};`;
|
|
8001
|
+
chip2.textContent = code;
|
|
8002
|
+
body.appendChild(chip2);
|
|
7420
8003
|
}
|
|
7421
8004
|
this._playReaction(body, "celebrate", "gift.json", ic);
|
|
7422
8005
|
}
|
|
@@ -7578,9 +8161,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7578
8161
|
*/
|
|
7579
8162
|
_flattenSlotCard(container) {
|
|
7580
8163
|
const cards = container.matches("[data-campaign-id]") ? [container] : Array.from(container.querySelectorAll("[data-campaign-id]"));
|
|
7581
|
-
for (const
|
|
7582
|
-
|
|
7583
|
-
|
|
8164
|
+
for (const el2 of cards) {
|
|
8165
|
+
el2.style.borderRadius = "0";
|
|
8166
|
+
el2.style.boxShadow = "none";
|
|
7584
8167
|
}
|
|
7585
8168
|
}
|
|
7586
8169
|
/**
|
|
@@ -7666,6 +8249,15 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7666
8249
|
this.emit("campaign-shown", campaign);
|
|
7667
8250
|
return;
|
|
7668
8251
|
}
|
|
8252
|
+
if (campaign.sub_type === "reviews") {
|
|
8253
|
+
renderReviewsOverlay(this.buildRenderContext(campaign), {
|
|
8254
|
+
apiHost: this.apiHost,
|
|
8255
|
+
writeKey: this.writeKey
|
|
8256
|
+
});
|
|
8257
|
+
this.trackEvent(campaign.id, "impression");
|
|
8258
|
+
this.emit("campaign-shown", campaign);
|
|
8259
|
+
return;
|
|
8260
|
+
}
|
|
7669
8261
|
{
|
|
7670
8262
|
const ic2 = campaign.interactive_config || {};
|
|
7671
8263
|
const multiCard2 = campaign.sub_type === "product_recommendation" || campaign.sub_type === "carousel_cards";
|
|
@@ -7791,8 +8383,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7791
8383
|
},
|
|
7792
8384
|
sanitizeUrl: (url) => this.sanitizeUrl(url),
|
|
7793
8385
|
navigate: (url, buttonId) => this.navigateToCampaignAction(campaign, url, buttonId),
|
|
8386
|
+
dispatchAction: (action) => this.dispatchAction(action, campaign.id),
|
|
7794
8387
|
submitResponse: (responseType, payload) => this.submitWidgetResponse(campaign, responseType, payload),
|
|
7795
|
-
playReaction: (
|
|
8388
|
+
playReaction: (el2, intent, lottieFile, scope) => this._playReaction(el2, intent, lottieFile, campaign.interactive_config, scope),
|
|
7796
8389
|
haptic: (pattern) => {
|
|
7797
8390
|
try {
|
|
7798
8391
|
if (typeof navigator !== "undefined" && typeof navigator.vibrate === "function") {
|
|
@@ -8049,9 +8642,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8049
8642
|
if (cells.s) cells.s.textContent = pad(s);
|
|
8050
8643
|
if (!urgent && diff > 0 && diff <= 6e4) {
|
|
8051
8644
|
urgent = true;
|
|
8052
|
-
Object.values(cells).forEach((
|
|
8053
|
-
if (
|
|
8054
|
-
|
|
8645
|
+
Object.values(cells).forEach((el2) => {
|
|
8646
|
+
if (el2) {
|
|
8647
|
+
el2.style.boxShadow = "0 0 0 2px #ef4444";
|
|
8055
8648
|
}
|
|
8056
8649
|
});
|
|
8057
8650
|
digits.style.animation = "aegisCountdownPulse 1.1s ease-in-out infinite";
|
|
@@ -8566,13 +9159,42 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8566
9159
|
window.location.href = safeUrl;
|
|
8567
9160
|
}
|
|
8568
9161
|
}
|
|
9162
|
+
/** Register/replace the canonical CTA-action handler after construction (the
|
|
9163
|
+
* config `onAction` is the construct-time equivalent). Idempotent. */
|
|
9164
|
+
setOnAction(handler) {
|
|
9165
|
+
this.onActionHandler = handler;
|
|
9166
|
+
}
|
|
9167
|
+
/**
|
|
9168
|
+
* Canonical CTA-action dispatcher (CANONICAL_ACTION_MODEL_TRACKER.md). ONE path
|
|
9169
|
+
* for every host-facing CTA action:
|
|
9170
|
+
* 1. give the host's `onAction` handler first refusal (return `true` = handled);
|
|
9171
|
+
* 2. ALSO fire the legacy `aegis:*` DOM event (cancelable) so existing
|
|
9172
|
+
* listeners (ACS) keep working unchanged during the migration;
|
|
9173
|
+
* 3. if STILL unhandled → canonical fallback (navigate to the product/cart
|
|
9174
|
+
* page) so a CTA is never a dead no-op (the rail-"Add" 3rd-party gap).
|
|
9175
|
+
* Both add-to-cart paths (card "Add" + the `aegis://cart-add` verb) funnel here,
|
|
9176
|
+
* so they're one behaviour delivered to the host's single `onAction` handler.
|
|
9177
|
+
* (Phase E.2 hard cutover — the legacy `aegis:*` DOM events were removed.)
|
|
9178
|
+
*/
|
|
9179
|
+
dispatchAction(action, _campaignId) {
|
|
9180
|
+
var _a;
|
|
9181
|
+
let handled = false;
|
|
9182
|
+
try {
|
|
9183
|
+
handled = ((_a = this.onActionHandler) == null ? void 0 : _a.call(this, action)) === true;
|
|
9184
|
+
} catch {
|
|
9185
|
+
}
|
|
9186
|
+
if (!handled) {
|
|
9187
|
+
const url = fallbackUrlForAction(action, this.productUrl);
|
|
9188
|
+
if (url && typeof window !== "undefined") window.location.href = url;
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
8569
9191
|
/**
|
|
8570
9192
|
* Phase-2 CTA action verbs (`aegis://<verb>?<params>`). Performs an in-app
|
|
8571
9193
|
* behaviour instead of navigating. Verbs:
|
|
8572
9194
|
* dismiss — close the message (tracked as dismissed)
|
|
8573
9195
|
* request-push — prompt for web-push permission, then close
|
|
8574
|
-
* cart-add?sku=X —
|
|
8575
|
-
*
|
|
9196
|
+
* cart-add?sku=X — canonical `add_to_cart` action via dispatchAction
|
|
9197
|
+
* (cancelable + product-page fallback)
|
|
8576
9198
|
*/
|
|
8577
9199
|
runCampaignActionVerb(campaign, url) {
|
|
8578
9200
|
const rest = url.slice("aegis://".length);
|
|
@@ -8595,14 +9217,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8595
9217
|
case "cart-add": {
|
|
8596
9218
|
const sku = params.get("sku") || "";
|
|
8597
9219
|
void this.trackEvent(campaign.id, "clicked", { meta: { verb: "cart-add", sku } });
|
|
8598
|
-
|
|
8599
|
-
detail: { sku, qty: 1, campaign_id: campaign.id },
|
|
8600
|
-
cancelable: true
|
|
8601
|
-
});
|
|
8602
|
-
const proceed = window.dispatchEvent(evt);
|
|
8603
|
-
if (proceed && !evt.defaultPrevented && sku) {
|
|
8604
|
-
window.location.href = `/p/${encodeURIComponent(sku)}`;
|
|
8605
|
-
}
|
|
9220
|
+
this.dispatchAction(parseAction(url, { sku }), campaign.id);
|
|
8606
9221
|
break;
|
|
8607
9222
|
}
|
|
8608
9223
|
default:
|
|
@@ -8612,9 +9227,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8612
9227
|
/** Remove a rendered campaign's element(s) from the DOM by campaign id. */
|
|
8613
9228
|
removeCampaignEl(campaignId) {
|
|
8614
9229
|
if (typeof document === "undefined") return;
|
|
8615
|
-
document.querySelectorAll(`[data-campaign-id="${campaignId}"]`).forEach((
|
|
9230
|
+
document.querySelectorAll(`[data-campaign-id="${campaignId}"]`).forEach((el2) => {
|
|
8616
9231
|
var _a;
|
|
8617
|
-
return (_a =
|
|
9232
|
+
return (_a = el2.parentNode) == null ? void 0 : _a.removeChild(el2);
|
|
8618
9233
|
});
|
|
8619
9234
|
}
|
|
8620
9235
|
/**
|
|
@@ -9966,7 +10581,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
9966
10581
|
this.addAnimationStyles();
|
|
9967
10582
|
const reduce = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
9968
10583
|
const viewport = scope === "viewport";
|
|
9969
|
-
const
|
|
10584
|
+
const cardAnchor = !viewport && (host == null ? void 0 : host.closest) ? host.closest("[data-aegis-reaction-anchor]") : null;
|
|
10585
|
+
const anchor = viewport ? document.body : cardAnchor || host || document.body;
|
|
9970
10586
|
const prevPos = anchor.style.position;
|
|
9971
10587
|
if (!viewport && (!prevPos || prevPos === "static")) anchor.style.position = "relative";
|
|
9972
10588
|
const layer = document.createElement("div");
|
|
@@ -10005,7 +10621,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
10005
10621
|
g.style.cssText = `position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: ${px}px; height: ${px}px; display: flex; align-items: center; justify-content: center; line-height: 0; filter: drop-shadow(0 8px 16px rgba(0,0,0,0.30)); ${motion}`;
|
|
10006
10622
|
layer.appendChild(g);
|
|
10007
10623
|
anchor.appendChild(layer);
|
|
10008
|
-
if (festive && !reduce) this._fireConfetti(host);
|
|
10624
|
+
if (festive && !reduce) this._fireConfetti(cardAnchor || host);
|
|
10009
10625
|
const ra = ic && typeof ic === "object" ? ic.reaction_animations : void 0;
|
|
10010
10626
|
const custom = ra && typeof ra[intent] === "string" ? ra[intent] : void 0;
|
|
10011
10627
|
const file = custom || lottieFile || spec.file;
|
|
@@ -10340,9 +10956,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
10340
10956
|
if (typeof document !== "undefined") {
|
|
10341
10957
|
document.querySelectorAll(
|
|
10342
10958
|
".aegis-in-app-banner, .aegis-in-app-modal-overlay, .aegis-in-app-fullscreen-overlay, .aegis-in-app-half-interstitial-overlay, .aegis-in-app-alert-overlay, .aegis-in-app-pip, .aegis-in-app-nps-overlay, .aegis-in-app-countdown-overlay, .aegis-in-app-rating-overlay, .aegis-in-app-poll-overlay, .aegis-in-app-quiz-overlay, .aegis-in-app-rating-card, .aegis-in-app-nps-card"
|
|
10343
|
-
).forEach((
|
|
10344
|
-
if (
|
|
10345
|
-
|
|
10959
|
+
).forEach((el2) => {
|
|
10960
|
+
if (el2.parentNode) {
|
|
10961
|
+
el2.parentNode.removeChild(el2);
|
|
10346
10962
|
}
|
|
10347
10963
|
});
|
|
10348
10964
|
const styles = document.getElementById("aegis-in-app-styles");
|
|
@@ -10374,9 +10990,9 @@ let AegisInAppManager = _AegisInAppManager;
|
|
|
10374
10990
|
function renderPreview(config, opts) {
|
|
10375
10991
|
document.querySelectorAll(
|
|
10376
10992
|
'[class^="aegis-in-app-"]'
|
|
10377
|
-
).forEach((
|
|
10378
|
-
if (
|
|
10379
|
-
|
|
10993
|
+
).forEach((el2) => {
|
|
10994
|
+
if (el2.parentNode) {
|
|
10995
|
+
el2.parentNode.removeChild(el2);
|
|
10380
10996
|
}
|
|
10381
10997
|
});
|
|
10382
10998
|
try {
|
|
@@ -10412,7 +11028,7 @@ function renderPreview(config, opts) {
|
|
|
10412
11028
|
if (anchors.length > 0) {
|
|
10413
11029
|
try {
|
|
10414
11030
|
anchors.forEach((slot) => {
|
|
10415
|
-
slot.querySelectorAll(":scope > :not([data-aegis-slot-default])").forEach((
|
|
11031
|
+
slot.querySelectorAll(":scope > :not([data-aegis-slot-default])").forEach((el2) => el2.remove());
|
|
10416
11032
|
});
|
|
10417
11033
|
const mm = manager;
|
|
10418
11034
|
mm.campaigns = (inline ? [config, ...coGroup] : coGroup).map((c) => ({ ...c, surface: void 0, target_screens: void 0 })).sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
@@ -10433,17 +11049,17 @@ function renderPreview(config, opts) {
|
|
|
10433
11049
|
m2.displayCampaign(config);
|
|
10434
11050
|
}
|
|
10435
11051
|
const MAX_NODES = 400;
|
|
10436
|
-
function selectorFor(
|
|
10437
|
-
if (
|
|
11052
|
+
function selectorFor(el2) {
|
|
11053
|
+
if (el2.id) return `#${CSS.escape(el2.id)}`;
|
|
10438
11054
|
for (const attr of ["data-testid", "data-test", "data-aegis-anchor", "data-qa", "name"]) {
|
|
10439
|
-
const v =
|
|
11055
|
+
const v = el2.getAttribute(attr);
|
|
10440
11056
|
if (v) {
|
|
10441
|
-
const sel = `${
|
|
11057
|
+
const sel = `${el2.tagName.toLowerCase()}[${attr}="${CSS.escape(v)}"]`;
|
|
10442
11058
|
if (document.querySelectorAll(sel).length === 1) return sel;
|
|
10443
11059
|
}
|
|
10444
11060
|
}
|
|
10445
11061
|
const parts = [];
|
|
10446
|
-
let node =
|
|
11062
|
+
let node = el2;
|
|
10447
11063
|
while (node && node !== document.body && parts.length < 6) {
|
|
10448
11064
|
if (node.id) {
|
|
10449
11065
|
parts.unshift(`#${CSS.escape(node.id)}`);
|
|
@@ -10467,15 +11083,15 @@ function captureWebScreen(screenName) {
|
|
|
10467
11083
|
const candidates = document.querySelectorAll(
|
|
10468
11084
|
"a,button,input,select,textarea,[role],[data-aegis-anchor],[data-testid],h1,h2,h3,img,[data-aegis-slot]"
|
|
10469
11085
|
);
|
|
10470
|
-
for (const
|
|
11086
|
+
for (const el2 of Array.from(candidates)) {
|
|
10471
11087
|
if (nodes.length >= MAX_NODES) break;
|
|
10472
|
-
const rect =
|
|
11088
|
+
const rect = el2.getBoundingClientRect();
|
|
10473
11089
|
if (rect.width <= 0 || rect.height <= 0) continue;
|
|
10474
|
-
const slotKey =
|
|
10475
|
-
const role = slotKey ? `slot:${slotKey}` :
|
|
10476
|
-
const text = (
|
|
11090
|
+
const slotKey = el2.getAttribute("data-aegis-slot");
|
|
11091
|
+
const role = slotKey ? `slot:${slotKey}` : el2.getAttribute("role") || el2.tagName.toLowerCase();
|
|
11092
|
+
const text = (el2.textContent || el2.getAttribute("aria-label") || "").trim().slice(0, 80);
|
|
10477
11093
|
nodes.push({
|
|
10478
|
-
selector: selectorFor(
|
|
11094
|
+
selector: selectorFor(el2),
|
|
10479
11095
|
role,
|
|
10480
11096
|
...text ? { text } : {},
|
|
10481
11097
|
bounds: {
|
|
@@ -13636,7 +14252,13 @@ class AegisMessageRuntime {
|
|
|
13636
14252
|
getWorkspaceId: config.getWorkspaceId,
|
|
13637
14253
|
// First-party cart reader — renderers (progress-bar) read live cart
|
|
13638
14254
|
// state from here instead of `window.*` cart globals. See setCartState().
|
|
13639
|
-
getCartState: () => this.deriveCartState()
|
|
14255
|
+
getCartState: () => this.deriveCartState(),
|
|
14256
|
+
// Canonical CTA-action handler + platform product-URL resolver
|
|
14257
|
+
// (CANONICAL_ACTION_MODEL_TRACKER.md). A host (ACS / Shopify-Woo plugin /
|
|
14258
|
+
// native) registers ONE `onAction` to handle add_to_cart/open_product/…;
|
|
14259
|
+
// legacy `aegis:*` DOM events still fire for back-compat.
|
|
14260
|
+
onAction: config.onAction,
|
|
14261
|
+
productUrl: config.productUrl
|
|
13640
14262
|
});
|
|
13641
14263
|
this.intentRuleEvaluator = new IntentRuleEvaluator();
|
|
13642
14264
|
if (config.governance) {
|
|
@@ -13788,6 +14410,17 @@ class AegisMessageRuntime {
|
|
|
13788
14410
|
setCartState(state) {
|
|
13789
14411
|
this.applyCart(state);
|
|
13790
14412
|
}
|
|
14413
|
+
/**
|
|
14414
|
+
* Register the canonical CTA-action handler — the CEP-standard single callback
|
|
14415
|
+
* that receives every in-app intent (add_to_cart / open_product / open_cart /
|
|
14416
|
+
* open_login / navigate / custom). Return `true` when handled; otherwise the SDK
|
|
14417
|
+
* applies the graceful fallback. The construct-time `onAction` config is the
|
|
14418
|
+
* equivalent; this lets a host register/replace it once it holds the runtime.
|
|
14419
|
+
* See CANONICAL_ACTION_MODEL_TRACKER.md.
|
|
14420
|
+
*/
|
|
14421
|
+
onAction(handler) {
|
|
14422
|
+
this.inApp.setOnAction(handler);
|
|
14423
|
+
}
|
|
13791
14424
|
/**
|
|
13792
14425
|
* The ONE cart writer. Normalizes any cart-ish shape and funnels it into the
|
|
13793
14426
|
* single `cart` context namespace (read by the Free-Delivery progress card,
|
|
@@ -13995,9 +14628,11 @@ export {
|
|
|
13995
14628
|
debounce,
|
|
13996
14629
|
aegis as default,
|
|
13997
14630
|
deriveDeviceFingerprint,
|
|
14631
|
+
fallbackUrlForAction,
|
|
13998
14632
|
getCurrentLauncher,
|
|
13999
14633
|
m as murmurhash3_x86_32,
|
|
14000
14634
|
openChat,
|
|
14635
|
+
parseAction,
|
|
14001
14636
|
readFirstPartyCookie,
|
|
14002
14637
|
renderPreview,
|
|
14003
14638
|
throttle,
|