@active-reach/web-sdk 1.29.0 → 1.31.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 +4 -7
- package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
- package/dist/inapp/actions.d.ts +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/index.js +729 -267
- 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/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -311,12 +311,12 @@ const ICONS = {
|
|
|
311
311
|
function escapeAttr(value) {
|
|
312
312
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
313
313
|
}
|
|
314
|
-
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
314
|
+
const SVG_NS$1 = "http://www.w3.org/2000/svg";
|
|
315
315
|
function lucideSvgEl(name, opts = {}) {
|
|
316
316
|
const node = ICONS[name];
|
|
317
317
|
if (!node || typeof document === "undefined") return null;
|
|
318
318
|
const size = opts.size ?? 24;
|
|
319
|
-
const svg = document.createElementNS(SVG_NS, "svg");
|
|
319
|
+
const svg = document.createElementNS(SVG_NS$1, "svg");
|
|
320
320
|
svg.setAttribute("width", String(size));
|
|
321
321
|
svg.setAttribute("height", String(size));
|
|
322
322
|
svg.setAttribute("viewBox", "0 0 24 24");
|
|
@@ -333,7 +333,7 @@ function lucideSvgEl(name, opts = {}) {
|
|
|
333
333
|
svg.setAttribute("aria-hidden", "true");
|
|
334
334
|
}
|
|
335
335
|
for (const [tag, attrs] of node) {
|
|
336
|
-
const child = document.createElementNS(SVG_NS, tag);
|
|
336
|
+
const child = document.createElementNS(SVG_NS$1, tag);
|
|
337
337
|
for (const [k, v] of Object.entries(attrs)) child.setAttribute(k, String(v));
|
|
338
338
|
svg.appendChild(child);
|
|
339
339
|
}
|
|
@@ -525,6 +525,16 @@ function applyPerCardOverride(tpl, look) {
|
|
|
525
525
|
if (look.hide_cta) drop("cta");
|
|
526
526
|
if (look.hide_rating) drop("rating");
|
|
527
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
|
+
}
|
|
528
538
|
if (look.badge) {
|
|
529
539
|
const badgeEl = { type: "badge", text: look.badge, color: look.badge_color };
|
|
530
540
|
elements = elements.some((e) => e.type === "badge") ? elements.map((e) => e.type === "badge" ? badgeEl : e) : [elements[0], badgeEl, ...elements.slice(1)].filter(Boolean);
|
|
@@ -538,7 +548,7 @@ function priceText(card) {
|
|
|
538
548
|
if (card.body && /\d/.test(card.body)) return card.body;
|
|
539
549
|
return void 0;
|
|
540
550
|
}
|
|
541
|
-
function paintPrice(card,
|
|
551
|
+
function paintPrice(card, el2, accent, ctx) {
|
|
542
552
|
const price = priceText(card);
|
|
543
553
|
if (price === void 0) return null;
|
|
544
554
|
const meta = card.metadata || {};
|
|
@@ -547,10 +557,10 @@ function paintPrice(card, el, accent, ctx) {
|
|
|
547
557
|
row.style.cssText = "display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;";
|
|
548
558
|
const p = document.createElement("span");
|
|
549
559
|
p.textContent = price;
|
|
550
|
-
if (
|
|
560
|
+
if (el2.variant === "plain") {
|
|
551
561
|
p.style.cssText = `color:${accent};font-weight:700;font-size:13px;`;
|
|
552
562
|
} else {
|
|
553
|
-
const pillBg =
|
|
563
|
+
const pillBg = el2.color ? ctx.sanitizeColor(el2.color) : "#059669";
|
|
554
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);`;
|
|
555
565
|
}
|
|
556
566
|
row.appendChild(p);
|
|
@@ -575,13 +585,13 @@ function paintRating(card) {
|
|
|
575
585
|
const count = Number(meta.review_count ?? 0);
|
|
576
586
|
const rr = document.createElement("div");
|
|
577
587
|
rr.style.cssText = "display:flex;align-items:center;gap:3px;font-size:11px;line-height:1;";
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
588
|
+
const star2 = document.createElement("span");
|
|
589
|
+
star2.textContent = "★";
|
|
590
|
+
star2.style.cssText = "color:#059669;";
|
|
581
591
|
const val = document.createElement("span");
|
|
582
592
|
val.textContent = avg.toFixed(1);
|
|
583
593
|
val.style.cssText = "color:#059669;font-weight:700;";
|
|
584
|
-
rr.appendChild(
|
|
594
|
+
rr.appendChild(star2);
|
|
585
595
|
rr.appendChild(val);
|
|
586
596
|
if (count > 0) {
|
|
587
597
|
const c = document.createElement("span");
|
|
@@ -602,14 +612,14 @@ function contrastFg(bg) {
|
|
|
602
612
|
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
603
613
|
return lum < 0.5 ? "#ffffff" : "#1f2937";
|
|
604
614
|
}
|
|
605
|
-
function buildCountdownElement(
|
|
606
|
-
const targetStr = typeof
|
|
615
|
+
function buildCountdownElement(el2, fg, muted) {
|
|
616
|
+
const targetStr = typeof el2.countdown_target === "string" ? el2.countdown_target : "";
|
|
607
617
|
const target = targetStr ? Date.parse(targetStr) : NaN;
|
|
608
618
|
if (!targetStr || isNaN(target)) return null;
|
|
609
619
|
const wrap = document.createElement("div");
|
|
610
620
|
wrap.style.cssText = "display:flex;align-items:baseline;gap:8px;font-variant-numeric:tabular-nums;margin:2px 0;";
|
|
611
621
|
const label = document.createElement("span");
|
|
612
|
-
label.textContent = typeof
|
|
622
|
+
label.textContent = typeof el2.countdown_label === "string" && el2.countdown_label || "Ends in";
|
|
613
623
|
label.style.cssText = `font-size:12px;color:${muted};`;
|
|
614
624
|
const time = document.createElement("span");
|
|
615
625
|
time.style.cssText = `font-size:15px;font-weight:700;color:${fg};letter-spacing:0.2px;`;
|
|
@@ -631,13 +641,13 @@ function buildCountdownElement(el, fg, muted) {
|
|
|
631
641
|
timer = setInterval(tick, 1e3);
|
|
632
642
|
return wrap;
|
|
633
643
|
}
|
|
634
|
-
function appendRatingThanks(wrap,
|
|
635
|
-
appendThanks(wrap,
|
|
636
|
-
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) : "";
|
|
637
647
|
if (url) {
|
|
638
648
|
const cta = document.createElement("button");
|
|
639
649
|
cta.type = "button";
|
|
640
|
-
cta.textContent =
|
|
650
|
+
cta.textContent = el2.rating_high_cta || "Leave a review";
|
|
641
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;`;
|
|
642
652
|
cta.addEventListener("click", () => {
|
|
643
653
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "rating_input", cta: "high_review" } });
|
|
@@ -647,10 +657,10 @@ function appendRatingThanks(wrap, el, ctx, fg, accent, isHigh) {
|
|
|
647
657
|
wrap.appendChild(cta);
|
|
648
658
|
}
|
|
649
659
|
}
|
|
650
|
-
function renderRatingFollowupStep(wrap,
|
|
660
|
+
function renderRatingFollowupStep(wrap, el2, ctx, stars2, fg, accent) {
|
|
651
661
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
652
662
|
const heading = document.createElement("div");
|
|
653
|
-
heading.textContent =
|
|
663
|
+
heading.textContent = el2.rating_followup_prompt || "Sorry to hear that — what went wrong?";
|
|
654
664
|
heading.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin-bottom:8px;`;
|
|
655
665
|
wrap.appendChild(heading);
|
|
656
666
|
const ta = document.createElement("textarea");
|
|
@@ -664,9 +674,9 @@ function renderRatingFollowupStep(wrap, el, ctx, stars, fg, accent) {
|
|
|
664
674
|
if (done) return;
|
|
665
675
|
done = true;
|
|
666
676
|
const comment = withComment ? ta.value.trim() : "";
|
|
667
|
-
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 }));
|
|
668
678
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, "acknowledge");
|
|
669
|
-
appendThanks(wrap,
|
|
679
|
+
appendThanks(wrap, el2, fg, "Thanks — we’ll do better.");
|
|
670
680
|
};
|
|
671
681
|
const btnRow = document.createElement("div");
|
|
672
682
|
btnRow.style.cssText = "display:flex;gap:8px;justify-content:center;";
|
|
@@ -685,23 +695,23 @@ function renderRatingFollowupStep(wrap, el, ctx, stars, fg, accent) {
|
|
|
685
695
|
wrap.appendChild(btnRow);
|
|
686
696
|
ta.focus();
|
|
687
697
|
}
|
|
688
|
-
function buildRatingInputElement(
|
|
698
|
+
function buildRatingInputElement(el2, ctx, fg) {
|
|
689
699
|
const accent = ctx.sanitizeColor(ctx.campaign.background_color || "#4169e1");
|
|
690
700
|
const wrap = document.createElement("div");
|
|
691
701
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
692
|
-
if (
|
|
702
|
+
if (el2.content) {
|
|
693
703
|
const q = document.createElement("div");
|
|
694
|
-
q.textContent =
|
|
704
|
+
q.textContent = el2.content;
|
|
695
705
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
696
706
|
wrap.appendChild(q);
|
|
697
707
|
}
|
|
698
|
-
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;
|
|
699
709
|
const row = document.createElement("div");
|
|
700
710
|
row.style.cssText = "display:flex;gap:6px;";
|
|
701
|
-
const
|
|
711
|
+
const stars2 = [];
|
|
702
712
|
let submitted = false;
|
|
703
713
|
const paint = (upto) => {
|
|
704
|
-
|
|
714
|
+
stars2.forEach((s, idx) => {
|
|
705
715
|
const on = idx < upto;
|
|
706
716
|
s.setAttribute("stroke", on ? "#f59e0b" : "#d1d5db");
|
|
707
717
|
s.setAttribute("fill", on ? "#f59e0b" : "none");
|
|
@@ -715,7 +725,7 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
715
725
|
const svg = lucideSvgEl("star", { size: 26, color: "#d1d5db" });
|
|
716
726
|
if (svg) {
|
|
717
727
|
btn.appendChild(svg);
|
|
718
|
-
|
|
728
|
+
stars2.push(svg);
|
|
719
729
|
}
|
|
720
730
|
btn.addEventListener("mouseenter", () => {
|
|
721
731
|
if (!submitted) paint(i);
|
|
@@ -729,13 +739,13 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
729
739
|
submitted = true;
|
|
730
740
|
paint(i);
|
|
731
741
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "rating_input", stars: i } });
|
|
732
|
-
const lowThreshold = typeof
|
|
733
|
-
if (
|
|
734
|
-
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);
|
|
735
745
|
} else {
|
|
736
746
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "rating", { stars: i }));
|
|
737
747
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, i >= Math.ceil(scale * 0.6) ? "affirm" : "acknowledge");
|
|
738
|
-
appendRatingThanks(wrap,
|
|
748
|
+
appendRatingThanks(wrap, el2, ctx, fg, accent, i >= Math.ceil(scale * 0.6));
|
|
739
749
|
}
|
|
740
750
|
});
|
|
741
751
|
row.appendChild(btn);
|
|
@@ -743,8 +753,8 @@ function buildRatingInputElement(el, ctx, fg) {
|
|
|
743
753
|
wrap.appendChild(row);
|
|
744
754
|
return wrap;
|
|
745
755
|
}
|
|
746
|
-
function appendThanks(wrap,
|
|
747
|
-
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;
|
|
748
758
|
if (!msg) return;
|
|
749
759
|
const note = document.createElement("div");
|
|
750
760
|
note.textContent = msg;
|
|
@@ -752,14 +762,14 @@ function appendThanks(wrap, el, fg, fallback) {
|
|
|
752
762
|
note.style.cssText = `font-size:12px;font-weight:600;color:${fg};opacity:0.85;margin-top:4px;`;
|
|
753
763
|
wrap.appendChild(note);
|
|
754
764
|
}
|
|
755
|
-
function buildPollElement(
|
|
756
|
-
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) : [];
|
|
757
767
|
if (opts.length < 2) return null;
|
|
758
768
|
const wrap = document.createElement("div");
|
|
759
769
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
760
|
-
if (
|
|
770
|
+
if (el2.content) {
|
|
761
771
|
const q = document.createElement("div");
|
|
762
|
-
q.textContent =
|
|
772
|
+
q.textContent = el2.content;
|
|
763
773
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
764
774
|
wrap.appendChild(q);
|
|
765
775
|
}
|
|
@@ -789,24 +799,24 @@ function buildPollElement(el, ctx, fg, accent) {
|
|
|
789
799
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "poll", option_index: idx, option_label: label } });
|
|
790
800
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "poll", { option_index: idx, option_label: label }));
|
|
791
801
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, "affirm");
|
|
792
|
-
appendThanks(wrap,
|
|
802
|
+
appendThanks(wrap, el2, fg, "Thanks for your answer!");
|
|
793
803
|
});
|
|
794
804
|
wrap.appendChild(btn);
|
|
795
805
|
});
|
|
796
806
|
return wrap;
|
|
797
807
|
}
|
|
798
|
-
function appendNpsThanks(wrap,
|
|
808
|
+
function appendNpsThanks(wrap, el2, ctx, fg, accent, isPromoter) {
|
|
799
809
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
800
810
|
const note = document.createElement("div");
|
|
801
811
|
note.setAttribute("role", "status");
|
|
802
|
-
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.");
|
|
803
813
|
note.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin:6px 0;`;
|
|
804
814
|
wrap.appendChild(note);
|
|
805
|
-
const url = isPromoter && typeof
|
|
815
|
+
const url = isPromoter && typeof el2.nps_promoter_url === "string" ? ctx.sanitizeUrl(el2.nps_promoter_url) : "";
|
|
806
816
|
if (url) {
|
|
807
817
|
const cta = document.createElement("button");
|
|
808
818
|
cta.type = "button";
|
|
809
|
-
cta.textContent =
|
|
819
|
+
cta.textContent = el2.nps_promoter_cta || "Leave a review";
|
|
810
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;`;
|
|
811
821
|
cta.addEventListener("click", () => {
|
|
812
822
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "nps", cta: "promoter_review" } });
|
|
@@ -816,17 +826,17 @@ function appendNpsThanks(wrap, el, ctx, fg, accent, isPromoter) {
|
|
|
816
826
|
wrap.appendChild(cta);
|
|
817
827
|
}
|
|
818
828
|
}
|
|
819
|
-
function renderNpsReasonStep(wrap,
|
|
820
|
-
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;
|
|
821
831
|
const band = npsBandFromScore(score);
|
|
822
|
-
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?";
|
|
823
833
|
while (wrap.firstChild) wrap.removeChild(wrap.firstChild);
|
|
824
834
|
const heading = document.createElement("div");
|
|
825
835
|
heading.textContent = prompt;
|
|
826
836
|
heading.style.cssText = `font-size:13px;font-weight:700;color:${fg};text-align:center;margin-bottom:8px;`;
|
|
827
837
|
wrap.appendChild(heading);
|
|
828
838
|
const ta = document.createElement("textarea");
|
|
829
|
-
const chips = Array.isArray(
|
|
839
|
+
const chips = Array.isArray(el2.nps_reason_chips) ? el2.nps_reason_chips : [];
|
|
830
840
|
if (chips.length) {
|
|
831
841
|
const chipRow = document.createElement("div");
|
|
832
842
|
chipRow.style.cssText = "display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-bottom:8px;";
|
|
@@ -855,7 +865,7 @@ function renderNpsReasonStep(wrap, el, ctx, score, fg, accent) {
|
|
|
855
865
|
const comment = withComment ? ta.value.trim() : "";
|
|
856
866
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "nps", comment ? { score, band, comment } : { score, band }));
|
|
857
867
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, score >= promoterThreshold ? "affirm" : score <= 6 ? "empathize" : "acknowledge");
|
|
858
|
-
appendNpsThanks(wrap,
|
|
868
|
+
appendNpsThanks(wrap, el2, ctx, fg, accent, score >= promoterThreshold);
|
|
859
869
|
};
|
|
860
870
|
const btnRow = document.createElement("div");
|
|
861
871
|
btnRow.style.cssText = "display:flex;gap:8px;justify-content:center;";
|
|
@@ -874,12 +884,12 @@ function renderNpsReasonStep(wrap, el, ctx, score, fg, accent) {
|
|
|
874
884
|
wrap.appendChild(btnRow);
|
|
875
885
|
ta.focus();
|
|
876
886
|
}
|
|
877
|
-
function buildNpsElement(
|
|
887
|
+
function buildNpsElement(el2, ctx, fg, accent, muted) {
|
|
878
888
|
const wrap = document.createElement("div");
|
|
879
889
|
wrap.style.cssText = "display:flex;flex-direction:column;gap:6px;margin:2px 0;";
|
|
880
|
-
if (
|
|
890
|
+
if (el2.content) {
|
|
881
891
|
const q = document.createElement("div");
|
|
882
|
-
q.textContent =
|
|
892
|
+
q.textContent = el2.content;
|
|
883
893
|
q.style.cssText = `font-size:13px;font-weight:600;color:${fg};`;
|
|
884
894
|
wrap.appendChild(q);
|
|
885
895
|
}
|
|
@@ -911,12 +921,12 @@ function buildNpsElement(el, ctx, fg, accent, muted) {
|
|
|
911
921
|
btn.style.opacity = "1";
|
|
912
922
|
const npsPayload = { score: n, band: npsBandFromScore(n) };
|
|
913
923
|
ctx.trackEvent(ctx.campaign.id, "clicked", { meta: { element: "nps", score: n, band: npsPayload.band } });
|
|
914
|
-
if (
|
|
915
|
-
renderNpsReasonStep(wrap,
|
|
924
|
+
if (el2.nps_followup_enabled === true) {
|
|
925
|
+
renderNpsReasonStep(wrap, el2, ctx, n, fg, accent);
|
|
916
926
|
} else {
|
|
917
927
|
void ((_a = ctx.submitResponse) == null ? void 0 : _a.call(ctx, "nps", { ...npsPayload }));
|
|
918
928
|
(_b = ctx.playReaction) == null ? void 0 : _b.call(ctx, wrap, n >= 9 ? "affirm" : n >= 7 ? "acknowledge" : "empathize");
|
|
919
|
-
appendThanks(wrap,
|
|
929
|
+
appendThanks(wrap, el2, fg, "Thanks for your feedback!");
|
|
920
930
|
}
|
|
921
931
|
});
|
|
922
932
|
row.appendChild(btn);
|
|
@@ -933,22 +943,22 @@ function buildNpsElement(el, ctx, fg, accent, muted) {
|
|
|
933
943
|
wrap.appendChild(scale);
|
|
934
944
|
return wrap;
|
|
935
945
|
}
|
|
936
|
-
function buildProgressElement(
|
|
946
|
+
function buildProgressElement(el2, ctx, accent, muted) {
|
|
937
947
|
const { trackEvent, campaign, sanitizeColor } = ctx;
|
|
938
|
-
const goal =
|
|
948
|
+
const goal = el2.goal_type || "cart_total";
|
|
939
949
|
const moneyGoal = goal === "cart_total";
|
|
940
|
-
const fill =
|
|
950
|
+
const fill = el2.fill ? sanitizeColor(el2.fill) : accent;
|
|
941
951
|
const props = () => ctx.properties && ctx.properties() || {};
|
|
942
952
|
const sym = () => {
|
|
943
953
|
var _a;
|
|
944
|
-
if (
|
|
954
|
+
if (el2.currency_symbol) return el2.currency_symbol;
|
|
945
955
|
const code = ctx.getCartState && ((_a = ctx.getCartState()) == null ? void 0 : _a.currency);
|
|
946
956
|
const M = { INR: "₹", USD: "$", EUR: "€", GBP: "£" };
|
|
947
957
|
return code && M[code] || "";
|
|
948
958
|
};
|
|
949
959
|
const threshold = () => {
|
|
950
|
-
if (typeof
|
|
951
|
-
if (
|
|
960
|
+
if (typeof el2.threshold === "number" && el2.threshold > 0) return el2.threshold;
|
|
961
|
+
if (el2.threshold_source === "free_delivery_setting") {
|
|
952
962
|
const v = Number(props()["cart.free_delivery_above"]);
|
|
953
963
|
if (v > 0) return v;
|
|
954
964
|
}
|
|
@@ -989,9 +999,9 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
989
999
|
goalType: goal,
|
|
990
1000
|
threshold: th,
|
|
991
1001
|
current: cur,
|
|
992
|
-
rewardText:
|
|
1002
|
+
rewardText: el2.reward_text,
|
|
993
1003
|
currencySymbol: moneyGoal ? sym() : "",
|
|
994
|
-
showPct:
|
|
1004
|
+
showPct: el2.show_pct
|
|
995
1005
|
});
|
|
996
1006
|
sub.textContent = labeled.text;
|
|
997
1007
|
if (complete) {
|
|
@@ -1000,8 +1010,8 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
1000
1010
|
if (!firedUnlock) {
|
|
1001
1011
|
firedUnlock = true;
|
|
1002
1012
|
if (seenIncomplete) {
|
|
1003
|
-
trackEvent(campaign.id, "clicked", { stepId:
|
|
1004
|
-
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");
|
|
1005
1015
|
}
|
|
1006
1016
|
}
|
|
1007
1017
|
} else {
|
|
@@ -1019,6 +1029,40 @@ function buildProgressElement(el, ctx, accent, muted) {
|
|
|
1019
1029
|
}
|
|
1020
1030
|
return wrap;
|
|
1021
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
|
+
}
|
|
1022
1066
|
function renderCardFromTemplate(card, opts) {
|
|
1023
1067
|
const { ctx, action, layout, layoutAccent } = opts;
|
|
1024
1068
|
const inline = action === "cart";
|
|
@@ -1038,7 +1082,7 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1038
1082
|
const fLayout = frame.layout;
|
|
1039
1083
|
const dir = fLayout === "row" ? "row" : "column";
|
|
1040
1084
|
const tileGap = frame.gap != null ? frame.gap : 6;
|
|
1041
|
-
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;";
|
|
1042
1086
|
tile.style.cssText = `
|
|
1043
1087
|
box-sizing:border-box; display:flex; flex-direction:${dir}; ${fLayout === "row" ? "align-items:center;" : ""} gap:${tileGap}px; position:relative;
|
|
1044
1088
|
color:${fg};
|
|
@@ -1055,11 +1099,11 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1055
1099
|
const elements = tpl.elements && tpl.elements.length ? tpl.elements : DEFAULT_CARD_TEMPLATE.elements;
|
|
1056
1100
|
let imageWrap = null;
|
|
1057
1101
|
const paintInto = (container, els) => {
|
|
1058
|
-
for (const
|
|
1059
|
-
switch (
|
|
1102
|
+
for (const el2 of els) {
|
|
1103
|
+
switch (el2.type) {
|
|
1060
1104
|
case "image": {
|
|
1061
1105
|
const wrap = document.createElement("div");
|
|
1062
|
-
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;`;
|
|
1063
1107
|
const safeVideo = card.video_url ? sanitizeUrl(card.video_url) : "";
|
|
1064
1108
|
if (safeVideo) {
|
|
1065
1109
|
const v = document.createElement("video");
|
|
@@ -1087,17 +1131,17 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1087
1131
|
break;
|
|
1088
1132
|
}
|
|
1089
1133
|
case "badge": {
|
|
1090
|
-
const text =
|
|
1134
|
+
const text = el2.text;
|
|
1091
1135
|
if (!text) break;
|
|
1092
1136
|
const badge = document.createElement("span");
|
|
1093
1137
|
badge.textContent = text;
|
|
1094
|
-
const bg =
|
|
1138
|
+
const bg = el2.color ? sanitizeColor(el2.color) : brand;
|
|
1095
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;`;
|
|
1096
1140
|
(imageWrap || container).appendChild(badge);
|
|
1097
1141
|
break;
|
|
1098
1142
|
}
|
|
1099
1143
|
case "price": {
|
|
1100
|
-
const node = paintPrice(card,
|
|
1144
|
+
const node = paintPrice(card, el2, accent, ctx);
|
|
1101
1145
|
if (node) container.appendChild(node);
|
|
1102
1146
|
break;
|
|
1103
1147
|
}
|
|
@@ -1105,8 +1149,8 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1105
1149
|
if (!card.title) break;
|
|
1106
1150
|
const t = document.createElement("div");
|
|
1107
1151
|
t.textContent = card.title;
|
|
1108
|
-
const lines =
|
|
1109
|
-
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;`;
|
|
1110
1154
|
container.appendChild(t);
|
|
1111
1155
|
break;
|
|
1112
1156
|
}
|
|
@@ -1114,8 +1158,8 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1114
1158
|
if (!card.body) break;
|
|
1115
1159
|
const s = document.createElement("div");
|
|
1116
1160
|
s.textContent = card.body;
|
|
1117
|
-
const lines =
|
|
1118
|
-
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;`;
|
|
1119
1163
|
container.appendChild(s);
|
|
1120
1164
|
break;
|
|
1121
1165
|
}
|
|
@@ -1135,17 +1179,17 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1135
1179
|
}
|
|
1136
1180
|
// ── rich-card-editor elements (P0) ──────────────────────────────────
|
|
1137
1181
|
case "icon": {
|
|
1138
|
-
const px = ICON_PX[
|
|
1182
|
+
const px = ICON_PX[el2.size || "md"] || 30;
|
|
1139
1183
|
const node = document.createElement("div");
|
|
1140
|
-
const iconColor =
|
|
1141
|
-
if (
|
|
1142
|
-
const bubbleTint =
|
|
1184
|
+
const iconColor = el2.color ? sanitizeColor(el2.color) : fg;
|
|
1185
|
+
if (el2.bubble) {
|
|
1186
|
+
const bubbleTint = el2.color ? sanitizeColor(el2.color) : brand;
|
|
1143
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);`;
|
|
1144
1188
|
} else {
|
|
1145
1189
|
node.style.cssText = "flex:0 0 auto;display:flex;align-items:center;";
|
|
1146
1190
|
}
|
|
1147
|
-
const svg = lucideSvgEl(
|
|
1148
|
-
size:
|
|
1191
|
+
const svg = lucideSvgEl(el2.icon_name || "circle-check", {
|
|
1192
|
+
size: el2.bubble ? Math.round(px * 0.55) : Math.round(px * 0.7),
|
|
1149
1193
|
color: iconColor,
|
|
1150
1194
|
strokeWidth: 2
|
|
1151
1195
|
});
|
|
@@ -1155,99 +1199,64 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1155
1199
|
}
|
|
1156
1200
|
case "text": {
|
|
1157
1201
|
const t = document.createElement("div");
|
|
1158
|
-
const fs = TEXT_PX[
|
|
1159
|
-
t.style.cssText = `font-size:${fs}px;font-weight:${WEIGHT[
|
|
1160
|
-
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);
|
|
1161
1205
|
container.appendChild(t);
|
|
1162
1206
|
break;
|
|
1163
1207
|
}
|
|
1164
1208
|
case "spacer": {
|
|
1165
1209
|
const sp = document.createElement("div");
|
|
1166
|
-
sp.style.height = `${
|
|
1210
|
+
sp.style.height = `${el2.height ?? 8}px`;
|
|
1167
1211
|
container.appendChild(sp);
|
|
1168
1212
|
break;
|
|
1169
1213
|
}
|
|
1170
1214
|
case "progress": {
|
|
1171
|
-
container.appendChild(buildProgressElement(
|
|
1215
|
+
container.appendChild(buildProgressElement(el2, ctx, brand, muted));
|
|
1172
1216
|
break;
|
|
1173
1217
|
}
|
|
1174
1218
|
case "countdown": {
|
|
1175
|
-
const cd = buildCountdownElement(
|
|
1219
|
+
const cd = buildCountdownElement(el2, fg, muted);
|
|
1176
1220
|
if (cd) container.appendChild(cd);
|
|
1177
1221
|
break;
|
|
1178
1222
|
}
|
|
1179
1223
|
case "rating_input": {
|
|
1180
|
-
container.appendChild(buildRatingInputElement(
|
|
1224
|
+
container.appendChild(buildRatingInputElement(el2, ctx, fg));
|
|
1181
1225
|
break;
|
|
1182
1226
|
}
|
|
1183
1227
|
case "poll": {
|
|
1184
|
-
const p = buildPollElement(
|
|
1228
|
+
const p = buildPollElement(el2, ctx, fg, brand);
|
|
1185
1229
|
if (p) container.appendChild(p);
|
|
1186
1230
|
break;
|
|
1187
1231
|
}
|
|
1188
1232
|
case "nps": {
|
|
1189
|
-
container.appendChild(buildNpsElement(
|
|
1233
|
+
container.appendChild(buildNpsElement(el2, ctx, fg, brand, muted));
|
|
1190
1234
|
break;
|
|
1191
1235
|
}
|
|
1192
1236
|
case "group": {
|
|
1193
1237
|
const g = document.createElement("div");
|
|
1194
|
-
const gdir =
|
|
1195
|
-
g.style.cssText = `display:flex;flex-direction:${gdir};${
|
|
1196
|
-
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 || []);
|
|
1197
1241
|
container.appendChild(g);
|
|
1198
1242
|
break;
|
|
1199
1243
|
}
|
|
1200
1244
|
case "cta": {
|
|
1201
|
-
const label =
|
|
1245
|
+
const label = el2.text || card.cta_text || (inline ? "Add" : "Shop");
|
|
1202
1246
|
const cta = document.createElement("button");
|
|
1203
1247
|
cta.className = "aegis-cta";
|
|
1204
1248
|
cta.textContent = label;
|
|
1205
|
-
const overlayOnImage = !!
|
|
1249
|
+
const overlayOnImage = !!el2.overlay && !!imageWrap;
|
|
1206
1250
|
if (overlayOnImage) {
|
|
1207
|
-
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);`;
|
|
1208
1252
|
} else {
|
|
1209
|
-
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;`;
|
|
1210
1254
|
}
|
|
1211
1255
|
cta.addEventListener("click", (e) => {
|
|
1256
|
+
var _a;
|
|
1212
1257
|
e.stopPropagation();
|
|
1213
|
-
trackEvent(campaign.id, "clicked", { stepId:
|
|
1214
|
-
|
|
1215
|
-
const m2 = meta;
|
|
1216
|
-
if (ctx.dispatchAction) {
|
|
1217
|
-
ctx.dispatchAction({
|
|
1218
|
-
type: "add_to_cart",
|
|
1219
|
-
productId: m2.product_id,
|
|
1220
|
-
sku: m2.sku,
|
|
1221
|
-
// Platform-native id (catalog-sync C.2) — plugins use this for a
|
|
1222
|
-
// native add; undefined today → graceful product-search fallback.
|
|
1223
|
-
platformProductId: m2.platform_product_id,
|
|
1224
|
-
title: card.title,
|
|
1225
|
-
price: m2.price ?? card.body,
|
|
1226
|
-
imageUrl: card.image_url,
|
|
1227
|
-
url: m2.platform_url || card.cta_url,
|
|
1228
|
-
qty: 1
|
|
1229
|
-
});
|
|
1230
|
-
} else if (typeof window !== "undefined") {
|
|
1231
|
-
window.dispatchEvent(
|
|
1232
|
-
new CustomEvent("aegis:add-to-cart", {
|
|
1233
|
-
detail: {
|
|
1234
|
-
campaign_id: campaign.id,
|
|
1235
|
-
product_id: m2.product_id,
|
|
1236
|
-
sku: m2.sku,
|
|
1237
|
-
title: card.title,
|
|
1238
|
-
price: m2.price ?? card.body,
|
|
1239
|
-
image_url: card.image_url,
|
|
1240
|
-
cta_url: card.cta_url
|
|
1241
|
-
}
|
|
1242
|
-
})
|
|
1243
|
-
);
|
|
1244
|
-
}
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
if (card.cta_url) {
|
|
1248
|
-
const safe = sanitizeUrl(card.cta_url);
|
|
1249
|
-
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
1250
|
-
}
|
|
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));
|
|
1251
1260
|
});
|
|
1252
1261
|
(overlayOnImage ? imageWrap : container).appendChild(cta);
|
|
1253
1262
|
break;
|
|
@@ -1257,37 +1266,20 @@ function renderCardFromTemplate(card, opts) {
|
|
|
1257
1266
|
};
|
|
1258
1267
|
paintInto(tile, elements);
|
|
1259
1268
|
const open = (e) => {
|
|
1269
|
+
var _a;
|
|
1260
1270
|
e.stopPropagation();
|
|
1261
1271
|
trackEvent(campaign.id, "clicked");
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
} else if (typeof window !== "undefined") {
|
|
1274
|
-
window.dispatchEvent(
|
|
1275
|
-
new CustomEvent("aegis:open-product", {
|
|
1276
|
-
detail: {
|
|
1277
|
-
campaign_id: campaign.id,
|
|
1278
|
-
product_id: bm.product_id,
|
|
1279
|
-
sku: bm.sku,
|
|
1280
|
-
cta_url: card.cta_url
|
|
1281
|
-
}
|
|
1282
|
-
})
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
return;
|
|
1286
|
-
}
|
|
1287
|
-
if (card.cta_url) {
|
|
1288
|
-
const safe = sanitizeUrl(card.cta_url);
|
|
1289
|
-
if (safe) ctx.navigate ? ctx.navigate(safe) : window.location.href = safe;
|
|
1290
|
-
}
|
|
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);
|
|
1291
1283
|
};
|
|
1292
1284
|
if (inline || card.cta_url) tile.addEventListener("click", open);
|
|
1293
1285
|
if (frame.celebrate_on_show === true && ctx.playReaction) {
|
|
@@ -1320,6 +1312,7 @@ function renderCarouselCards(ctx) {
|
|
|
1320
1312
|
}
|
|
1321
1313
|
const autoplay = Number(ic.autoplay_ms) || 0;
|
|
1322
1314
|
const loop = ic.loop !== false;
|
|
1315
|
+
const layout = ic.rec_layout || "row";
|
|
1323
1316
|
addAnimationStyles();
|
|
1324
1317
|
ensureInAppFont();
|
|
1325
1318
|
const bg = "#ffffff";
|
|
@@ -1367,20 +1360,26 @@ function renderCarouselCards(ctx) {
|
|
|
1367
1360
|
header.appendChild(closeBtn);
|
|
1368
1361
|
card.appendChild(header);
|
|
1369
1362
|
const track = document.createElement("div");
|
|
1370
|
-
|
|
1371
|
-
display:
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
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
|
+
}
|
|
1377
1376
|
const template = resolveGlobalTemplate(ic);
|
|
1378
1377
|
cards.forEach((c, i) => {
|
|
1379
1378
|
const tile = renderCardFromTemplate(c, {
|
|
1380
1379
|
template,
|
|
1381
1380
|
ctx,
|
|
1382
1381
|
action: "navigate",
|
|
1383
|
-
layout
|
|
1382
|
+
layout,
|
|
1384
1383
|
layoutAccent: accent
|
|
1385
1384
|
});
|
|
1386
1385
|
tile.setAttribute("data-card-index", String(i));
|
|
@@ -1390,6 +1389,12 @@ function renderCarouselCards(ctx) {
|
|
|
1390
1389
|
track.appendChild(tile);
|
|
1391
1390
|
});
|
|
1392
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
|
+
}
|
|
1393
1398
|
const dots = document.createElement("div");
|
|
1394
1399
|
dots.style.cssText = "display: flex; justify-content: center; gap: 6px; margin-top: 10px;";
|
|
1395
1400
|
const dotEls = [];
|
|
@@ -1419,9 +1424,9 @@ function renderCarouselCards(ctx) {
|
|
|
1419
1424
|
const tiles = track.querySelectorAll("[data-card-index]");
|
|
1420
1425
|
const goto = (idx) => {
|
|
1421
1426
|
activeIdx = (idx % cards.length + cards.length) % cards.length;
|
|
1422
|
-
const
|
|
1423
|
-
if (
|
|
1424
|
-
const delta =
|
|
1427
|
+
const el2 = tiles[activeIdx];
|
|
1428
|
+
if (el2) {
|
|
1429
|
+
const delta = el2.getBoundingClientRect().left - track.getBoundingClientRect().left;
|
|
1425
1430
|
track.scrollTo({ left: track.scrollLeft + delta, behavior: "smooth" });
|
|
1426
1431
|
setActive(activeIdx);
|
|
1427
1432
|
}
|
|
@@ -2038,6 +2043,10 @@ function renderProductRecommendation(ctx) {
|
|
|
2038
2043
|
display: flex; gap: 10px; overflow-x: auto;
|
|
2039
2044
|
scroll-snap-type: x mandatory; padding: 14px 2px 18px;
|
|
2040
2045
|
`;
|
|
2046
|
+
} else if (layout === "list") {
|
|
2047
|
+
grid.style.cssText = `
|
|
2048
|
+
display: flex; flex-direction: column; gap: 10px; padding: 14px 2px 6px;
|
|
2049
|
+
`;
|
|
2041
2050
|
} else {
|
|
2042
2051
|
grid.style.cssText = `
|
|
2043
2052
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
|
|
@@ -2094,9 +2103,11 @@ function renderProductRecommendationInline(ctx, target) {
|
|
|
2094
2103
|
section.appendChild(body);
|
|
2095
2104
|
}
|
|
2096
2105
|
const grid = document.createElement("div");
|
|
2097
|
-
const isRow = layout !== "grid";
|
|
2106
|
+
const isRow = layout === "row" || layout !== "grid" && layout !== "list";
|
|
2098
2107
|
if (layout === "grid") {
|
|
2099
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;";
|
|
2100
2111
|
} else {
|
|
2101
2112
|
grid.style.cssText = `
|
|
2102
2113
|
display: flex; gap: 10px; overflow-x: auto;
|
|
@@ -2639,10 +2650,10 @@ function brandAccent(ctx) {
|
|
|
2639
2650
|
function injectGameStyles() {
|
|
2640
2651
|
if (typeof document === "undefined" || document.getElementById("aegis-game-styles")) return;
|
|
2641
2652
|
if (typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
2642
|
-
const
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
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);
|
|
2646
2657
|
}
|
|
2647
2658
|
function openGameModal(ctx, className, maxWidth = 360) {
|
|
2648
2659
|
const { campaign, trackEvent, addAnimationStyles } = ctx;
|
|
@@ -4150,8 +4161,8 @@ class AegisChat {
|
|
|
4150
4161
|
}
|
|
4151
4162
|
if (msg.interactive && Array.isArray(msg.interactive)) {
|
|
4152
4163
|
for (const inter of msg.interactive) {
|
|
4153
|
-
const
|
|
4154
|
-
if (
|
|
4164
|
+
const el2 = this.renderInteractive(inter);
|
|
4165
|
+
if (el2) row.appendChild(el2);
|
|
4155
4166
|
}
|
|
4156
4167
|
}
|
|
4157
4168
|
this.thread.appendChild(row);
|
|
@@ -5015,6 +5026,432 @@ function disposeActiveWebChat() {
|
|
|
5015
5026
|
activeInstance == null ? void 0 : activeInstance.destroy();
|
|
5016
5027
|
activeInstance = null;
|
|
5017
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 star(filled, size) {
|
|
5037
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5038
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5039
|
+
svg.setAttribute("width", String(size));
|
|
5040
|
+
svg.setAttribute("height", String(size));
|
|
5041
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5042
|
+
p.setAttribute(
|
|
5043
|
+
"d",
|
|
5044
|
+
"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"
|
|
5045
|
+
);
|
|
5046
|
+
p.setAttribute("fill", filled ? "#f59e0b" : "#e5e7eb");
|
|
5047
|
+
svg.appendChild(p);
|
|
5048
|
+
return svg;
|
|
5049
|
+
}
|
|
5050
|
+
function stars(rating, size = 15) {
|
|
5051
|
+
const wrap = el("span", "display:inline-flex;gap:2px;vertical-align:middle;");
|
|
5052
|
+
wrap.setAttribute("aria-label", `${rating} out of 5`);
|
|
5053
|
+
for (let i = 1; i <= 5; i++) wrap.appendChild(star(i <= rating, size));
|
|
5054
|
+
return wrap;
|
|
5055
|
+
}
|
|
5056
|
+
function verifiedBadge() {
|
|
5057
|
+
const b = el(
|
|
5058
|
+
"span",
|
|
5059
|
+
"display:inline-flex;align-items:center;gap:3px;font-size:12px;font-weight:600;color:#059669;"
|
|
5060
|
+
);
|
|
5061
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5062
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5063
|
+
svg.setAttribute("width", "13");
|
|
5064
|
+
svg.setAttribute("height", "13");
|
|
5065
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5066
|
+
p.setAttribute("d", "M9 12l2 2 4-4M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0z");
|
|
5067
|
+
p.setAttribute("fill", "none");
|
|
5068
|
+
p.setAttribute("stroke", "#059669");
|
|
5069
|
+
p.setAttribute("stroke-width", "2");
|
|
5070
|
+
p.setAttribute("stroke-linecap", "round");
|
|
5071
|
+
p.setAttribute("stroke-linejoin", "round");
|
|
5072
|
+
svg.appendChild(p);
|
|
5073
|
+
b.appendChild(svg);
|
|
5074
|
+
b.appendChild(el("span", "", "Verified purchase"));
|
|
5075
|
+
return b;
|
|
5076
|
+
}
|
|
5077
|
+
function avatar(name, accent) {
|
|
5078
|
+
const initial = (name.trim()[0] || "?").toUpperCase();
|
|
5079
|
+
const a = el(
|
|
5080
|
+
"span",
|
|
5081
|
+
`flex:0 0 auto;width:34px;height:34px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:${accent};background:${accent}1a;`,
|
|
5082
|
+
initial
|
|
5083
|
+
);
|
|
5084
|
+
return a;
|
|
5085
|
+
}
|
|
5086
|
+
function thumbBtn(up, count, reviewId, creds) {
|
|
5087
|
+
const btn = el(
|
|
5088
|
+
"button",
|
|
5089
|
+
"display:inline-flex;align-items:center;gap:5px;font-size:13px;color:#6b7280;background:none;border:none;cursor:pointer;padding:4px 6px;border-radius:8px;font-family:inherit;"
|
|
5090
|
+
);
|
|
5091
|
+
const svg = document.createElementNS(SVG_NS, "svg");
|
|
5092
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
5093
|
+
svg.setAttribute("width", "15");
|
|
5094
|
+
svg.setAttribute("height", "15");
|
|
5095
|
+
if (!up) svg.style.cssText = "transform:rotate(180deg);";
|
|
5096
|
+
const p = document.createElementNS(SVG_NS, "path");
|
|
5097
|
+
p.setAttribute(
|
|
5098
|
+
"d",
|
|
5099
|
+
"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"
|
|
5100
|
+
);
|
|
5101
|
+
p.setAttribute("fill", "currentColor");
|
|
5102
|
+
svg.appendChild(p);
|
|
5103
|
+
btn.appendChild(svg);
|
|
5104
|
+
const c = el("span", "", String(count));
|
|
5105
|
+
btn.appendChild(c);
|
|
5106
|
+
const key = `aegis_rv_voted_${reviewId}`;
|
|
5107
|
+
let voted = false;
|
|
5108
|
+
try {
|
|
5109
|
+
voted = typeof localStorage !== "undefined" && localStorage.getItem(key) != null;
|
|
5110
|
+
} catch {
|
|
5111
|
+
}
|
|
5112
|
+
if (voted) btn.style.opacity = "0.5";
|
|
5113
|
+
btn.addEventListener("mouseenter", () => {
|
|
5114
|
+
if (!voted) btn.style.color = "#111827";
|
|
5115
|
+
});
|
|
5116
|
+
btn.addEventListener("mouseleave", () => {
|
|
5117
|
+
btn.style.color = "#6b7280";
|
|
5118
|
+
});
|
|
5119
|
+
btn.addEventListener("click", () => {
|
|
5120
|
+
try {
|
|
5121
|
+
if (localStorage.getItem(key) != null) return;
|
|
5122
|
+
localStorage.setItem(key, up ? "up" : "down");
|
|
5123
|
+
} catch {
|
|
5124
|
+
}
|
|
5125
|
+
voted = true;
|
|
5126
|
+
c.textContent = String(count + 1);
|
|
5127
|
+
btn.style.opacity = "0.5";
|
|
5128
|
+
const url = new URL(`/v1/reviews/${reviewId}/helpful`, creds.apiHost);
|
|
5129
|
+
void fetch(url.toString(), {
|
|
5130
|
+
method: "POST",
|
|
5131
|
+
headers: { "X-Aegis-Write-Key": creds.writeKey, "Content-Type": "application/json" },
|
|
5132
|
+
body: JSON.stringify({ direction: up ? "up" : "down" })
|
|
5133
|
+
}).catch(() => {
|
|
5134
|
+
});
|
|
5135
|
+
});
|
|
5136
|
+
return btn;
|
|
5137
|
+
}
|
|
5138
|
+
function injectJsonLd(target, data, productId) {
|
|
5139
|
+
if (!data.aggregate.count || data.aggregate.avg_rating == null) return;
|
|
5140
|
+
const ld = {
|
|
5141
|
+
"@context": "https://schema.org",
|
|
5142
|
+
"@type": "Product",
|
|
5143
|
+
...productId ? { sku: productId } : {},
|
|
5144
|
+
aggregateRating: {
|
|
5145
|
+
"@type": "AggregateRating",
|
|
5146
|
+
ratingValue: data.aggregate.avg_rating,
|
|
5147
|
+
reviewCount: data.aggregate.count
|
|
5148
|
+
},
|
|
5149
|
+
review: data.items.slice(0, 10).map((r) => {
|
|
5150
|
+
var _a;
|
|
5151
|
+
return {
|
|
5152
|
+
"@type": "Review",
|
|
5153
|
+
reviewRating: { "@type": "Rating", ratingValue: r.rating ?? 0 },
|
|
5154
|
+
author: { "@type": "Person", name: ((_a = r.reviewer_snapshot) == null ? void 0 : _a.name) ?? "Customer" },
|
|
5155
|
+
...r.review_text ? { reviewBody: r.review_text } : {}
|
|
5156
|
+
};
|
|
5157
|
+
})
|
|
5158
|
+
};
|
|
5159
|
+
const script = document.createElement("script");
|
|
5160
|
+
script.type = "application/ld+json";
|
|
5161
|
+
script.textContent = JSON.stringify(ld);
|
|
5162
|
+
target.appendChild(script);
|
|
5163
|
+
}
|
|
5164
|
+
const SORTS = [
|
|
5165
|
+
{ key: "recent", label: "Most recent" },
|
|
5166
|
+
{ key: "helpful", label: "Most helpful" },
|
|
5167
|
+
{ key: "rating", label: "Highest rated" }
|
|
5168
|
+
];
|
|
5169
|
+
function renderReviewsInline(ctx, target, creds) {
|
|
5170
|
+
if (typeof document === "undefined" || !(creds == null ? void 0 : creds.apiHost) || !(creds == null ? void 0 : creds.writeKey)) return false;
|
|
5171
|
+
ensureInAppFont();
|
|
5172
|
+
const ic = ctx.campaign.interactive_config || {};
|
|
5173
|
+
const accent = ctx.sanitizeColor(ctx.campaign.background_color || "#4169e1");
|
|
5174
|
+
const brand = String(ic.brand_name || "").trim() || "The store";
|
|
5175
|
+
const productId = target.getAttribute("data-product-id") || ctx.campaign.product_id || null;
|
|
5176
|
+
const state = { sort: "recent", withPhotos: false };
|
|
5177
|
+
target.innerHTML = "";
|
|
5178
|
+
target.appendChild(el("div", `font-family:${IN_APP_FONT_STACK};font-size:13px;color:#9ca3af;padding:10px 0;`, "Loading reviews…"));
|
|
5179
|
+
function buildUrl() {
|
|
5180
|
+
const url = new URL("/v1/reviews/public", creds.apiHost);
|
|
5181
|
+
if (productId) url.searchParams.set("product_id", productId);
|
|
5182
|
+
url.searchParams.set("sort", state.sort);
|
|
5183
|
+
if (state.withPhotos) url.searchParams.set("with_photos", "true");
|
|
5184
|
+
url.searchParams.set("limit", "20");
|
|
5185
|
+
return url.toString();
|
|
5186
|
+
}
|
|
5187
|
+
function fetchReviews() {
|
|
5188
|
+
return fetch(buildUrl(), { method: "GET", headers: { "X-Aegis-Write-Key": creds.writeKey } }).then((r) => r.ok ? r.json() : null).catch(() => null);
|
|
5189
|
+
}
|
|
5190
|
+
let listContainer = null;
|
|
5191
|
+
function reviewCard(r) {
|
|
5192
|
+
var _a, _b, _c;
|
|
5193
|
+
const li = el("li", "padding:22px 0;border-top:1px solid #f0f1f3;");
|
|
5194
|
+
const head = el("div", "display:flex;align-items:center;gap:10px;");
|
|
5195
|
+
head.appendChild(avatar(((_a = r.reviewer_snapshot) == null ? void 0 : _a.name) ?? "Customer", accent));
|
|
5196
|
+
const idn = el("div", "display:flex;flex-direction:column;gap:2px;min-width:0;");
|
|
5197
|
+
const nameRow = el("div", "display:flex;flex-wrap:wrap;align-items:center;gap:8px;");
|
|
5198
|
+
nameRow.appendChild(el("span", "font-size:15px;font-weight:700;color:#111827;", ((_b = r.reviewer_snapshot) == null ? void 0 : _b.name) ?? "Customer"));
|
|
5199
|
+
if (r.verified_purchase) nameRow.appendChild(verifiedBadge());
|
|
5200
|
+
idn.appendChild(nameRow);
|
|
5201
|
+
idn.appendChild(stars(r.rating ?? 0, 14));
|
|
5202
|
+
head.appendChild(idn);
|
|
5203
|
+
if (r.created_at) {
|
|
5204
|
+
const d = new Date(r.created_at);
|
|
5205
|
+
if (!Number.isNaN(d.getTime())) {
|
|
5206
|
+
head.appendChild(el(
|
|
5207
|
+
"span",
|
|
5208
|
+
"margin-left:auto;font-size:12px;color:#9ca3af;white-space:nowrap;",
|
|
5209
|
+
d.toLocaleDateString(void 0, { day: "numeric", month: "short", year: "numeric" })
|
|
5210
|
+
));
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
li.appendChild(head);
|
|
5214
|
+
if (r.review_text) {
|
|
5215
|
+
li.appendChild(el("p", "margin:12px 0 0;font-size:15px;line-height:1.6;color:#374151;", r.review_text));
|
|
5216
|
+
}
|
|
5217
|
+
if (r.media && r.media.length > 0) {
|
|
5218
|
+
const gallery = el("div", "display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;");
|
|
5219
|
+
for (const m2 of r.media.slice(0, 6)) {
|
|
5220
|
+
const safe = ctx.sanitizeUrl(m2.url);
|
|
5221
|
+
if (!safe) continue;
|
|
5222
|
+
const img = document.createElement("img");
|
|
5223
|
+
img.src = safe;
|
|
5224
|
+
img.loading = "lazy";
|
|
5225
|
+
img.alt = "";
|
|
5226
|
+
img.style.cssText = "width:72px;height:72px;object-fit:cover;border-radius:12px;border:1px solid #f0f1f3;";
|
|
5227
|
+
gallery.appendChild(img);
|
|
5228
|
+
}
|
|
5229
|
+
if (gallery.childElementCount) li.appendChild(gallery);
|
|
5230
|
+
}
|
|
5231
|
+
const foot = el("div", "display:flex;align-items:center;gap:6px;margin-top:12px;");
|
|
5232
|
+
foot.appendChild(el("span", "font-size:13px;color:#9ca3af;margin-right:2px;", "Was this helpful?"));
|
|
5233
|
+
foot.appendChild(thumbBtn(true, r.helpful_count ?? 0, r.id, creds));
|
|
5234
|
+
foot.appendChild(thumbBtn(false, r.not_helpful_count ?? 0, r.id, creds));
|
|
5235
|
+
li.appendChild(foot);
|
|
5236
|
+
if ((_c = r.operator_reply) == null ? void 0 : _c.text) {
|
|
5237
|
+
const reply = el(
|
|
5238
|
+
"div",
|
|
5239
|
+
`margin-top:14px;margin-left:44px;border-left:3px solid ${accent};background:${accent}0d;border-radius:0 12px 12px 0;padding:12px 14px;`
|
|
5240
|
+
);
|
|
5241
|
+
const rlabel = el("div", "display:flex;align-items:center;gap:6px;margin-bottom:5px;");
|
|
5242
|
+
rlabel.appendChild(el("span", `width:7px;height:7px;border-radius:999px;background:${accent};display:inline-block;`));
|
|
5243
|
+
rlabel.appendChild(el("span", `font-size:12px;font-weight:700;color:${accent};`, brand));
|
|
5244
|
+
rlabel.appendChild(el("span", "font-size:12px;color:#9ca3af;", "· replied"));
|
|
5245
|
+
reply.appendChild(rlabel);
|
|
5246
|
+
reply.appendChild(el("p", "margin:0;font-size:14px;line-height:1.55;color:#4b5563;", r.operator_reply.text));
|
|
5247
|
+
li.appendChild(reply);
|
|
5248
|
+
}
|
|
5249
|
+
return li;
|
|
5250
|
+
}
|
|
5251
|
+
function renderList(items) {
|
|
5252
|
+
if (!listContainer) return;
|
|
5253
|
+
listContainer.innerHTML = "";
|
|
5254
|
+
if (items.length === 0) {
|
|
5255
|
+
listContainer.appendChild(el("p", "padding:20px 0;font-size:14px;color:#9ca3af;text-align:center;", "No reviews match this filter."));
|
|
5256
|
+
return;
|
|
5257
|
+
}
|
|
5258
|
+
const ul = el("ul", "list-style:none;margin:0;padding:0;");
|
|
5259
|
+
for (const r of items) ul.appendChild(reviewCard(r));
|
|
5260
|
+
listContainer.appendChild(ul);
|
|
5261
|
+
}
|
|
5262
|
+
function pill(label, active, onClick) {
|
|
5263
|
+
const b = el(
|
|
5264
|
+
"button",
|
|
5265
|
+
`font-size:13px;font-weight:600;padding:7px 16px;border-radius:999px;cursor:pointer;font-family:inherit;` + (active ? `background:${accent};color:#fff;border:1px solid ${accent};` : "background:#fff;color:#374151;border:1px solid #e5e7eb;"),
|
|
5266
|
+
label
|
|
5267
|
+
);
|
|
5268
|
+
b.addEventListener("click", onClick);
|
|
5269
|
+
return b;
|
|
5270
|
+
}
|
|
5271
|
+
function controls(rerender) {
|
|
5272
|
+
const bar = el("div", "display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:18px 0 4px;");
|
|
5273
|
+
const sel = document.createElement("select");
|
|
5274
|
+
sel.style.cssText = `font-size:13px;font-weight:600;padding:7px 30px 7px 14px;border:1px solid #e5e7eb;border-radius:999px;background:#fff;color:#374151;cursor:pointer;font-family:inherit;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;`;
|
|
5275
|
+
for (const s of SORTS) {
|
|
5276
|
+
const o = document.createElement("option");
|
|
5277
|
+
o.value = s.key;
|
|
5278
|
+
o.textContent = s.label;
|
|
5279
|
+
sel.appendChild(o);
|
|
5280
|
+
}
|
|
5281
|
+
sel.value = state.sort;
|
|
5282
|
+
sel.addEventListener("change", () => {
|
|
5283
|
+
state.sort = sel.value;
|
|
5284
|
+
rerender();
|
|
5285
|
+
});
|
|
5286
|
+
bar.appendChild(sel);
|
|
5287
|
+
let photosBtn = null;
|
|
5288
|
+
photosBtn = pill("With photos", state.withPhotos, () => {
|
|
5289
|
+
state.withPhotos = !state.withPhotos;
|
|
5290
|
+
if (photosBtn) {
|
|
5291
|
+
photosBtn.style.cssText = `font-size:13px;font-weight:600;padding:7px 16px;border-radius:999px;cursor:pointer;font-family:inherit;` + (state.withPhotos ? `background:${accent};color:#fff;border:1px solid ${accent};` : "background:#fff;color:#374151;border:1px solid #e5e7eb;");
|
|
5292
|
+
}
|
|
5293
|
+
rerender();
|
|
5294
|
+
});
|
|
5295
|
+
bar.appendChild(photosBtn);
|
|
5296
|
+
return bar;
|
|
5297
|
+
}
|
|
5298
|
+
function distributionPanel(dist, total) {
|
|
5299
|
+
const box = el("div", "flex:1 1 260px;max-width:340px;display:flex;flex-direction:column;gap:7px;");
|
|
5300
|
+
for (let r = 5; r >= 1; r--) {
|
|
5301
|
+
const n = dist[String(r)] ?? 0;
|
|
5302
|
+
const pct = total > 0 ? Math.round(n / total * 100) : 0;
|
|
5303
|
+
const row = el("div", "display:flex;align-items:center;gap:10px;font-size:13px;color:#6b7280;");
|
|
5304
|
+
const lbl = el("span", "width:30px;display:inline-flex;align-items:center;gap:3px;color:#374151;font-weight:600;", String(r));
|
|
5305
|
+
lbl.appendChild(star(true, 11));
|
|
5306
|
+
row.appendChild(lbl);
|
|
5307
|
+
const track = el("div", "flex:1;height:8px;background:#f0f1f3;border-radius:999px;overflow:hidden;");
|
|
5308
|
+
track.appendChild(el("div", `width:${pct}%;height:100%;background:${accent};border-radius:999px;`));
|
|
5309
|
+
row.appendChild(track);
|
|
5310
|
+
row.appendChild(el("span", "width:24px;text-align:right;font-variant-numeric:tabular-nums;", String(n)));
|
|
5311
|
+
box.appendChild(row);
|
|
5312
|
+
}
|
|
5313
|
+
return box;
|
|
5314
|
+
}
|
|
5315
|
+
function aiSummaryCard(summary) {
|
|
5316
|
+
const card = el(
|
|
5317
|
+
"div",
|
|
5318
|
+
"position:relative;border-radius:18px;padding:18px 20px;margin-bottom:24px;background:linear-gradient(135deg,#faf5ff 0%,#f5f3ff 100%);border:1px solid #ede9fe;"
|
|
5319
|
+
);
|
|
5320
|
+
const head = el("div", "display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;");
|
|
5321
|
+
const left = el("div", "display:flex;align-items:center;gap:7px;");
|
|
5322
|
+
const sp = document.createElementNS(SVG_NS, "svg");
|
|
5323
|
+
sp.setAttribute("viewBox", "0 0 24 24");
|
|
5324
|
+
sp.setAttribute("width", "16");
|
|
5325
|
+
sp.setAttribute("height", "16");
|
|
5326
|
+
const spp = document.createElementNS(SVG_NS, "path");
|
|
5327
|
+
spp.setAttribute("d", "M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6L12 3z");
|
|
5328
|
+
spp.setAttribute("fill", "#7c3aed");
|
|
5329
|
+
sp.appendChild(spp);
|
|
5330
|
+
left.appendChild(sp);
|
|
5331
|
+
left.appendChild(el("span", "font-size:12px;font-weight:800;letter-spacing:.07em;color:#6d28d9;text-transform:uppercase;", "What customers say"));
|
|
5332
|
+
head.appendChild(left);
|
|
5333
|
+
head.appendChild(el("span", "font-size:11px;font-weight:600;color:#a78bda;", "AI-generated"));
|
|
5334
|
+
card.appendChild(head);
|
|
5335
|
+
card.appendChild(el("p", "margin:0;font-size:15px;line-height:1.6;color:#3b2a63;", summary.text));
|
|
5336
|
+
card.appendChild(el("p", "margin:8px 0 0;font-size:12px;color:#a78bda;text-align:right;", `from ${summary.review_count} reviews`));
|
|
5337
|
+
return card;
|
|
5338
|
+
}
|
|
5339
|
+
function renderWall(data) {
|
|
5340
|
+
target.innerHTML = "";
|
|
5341
|
+
const root = el(
|
|
5342
|
+
"section",
|
|
5343
|
+
`font-family:${IN_APP_FONT_STACK};color:#111827;max-width:860px;margin:0 auto;-webkit-font-smoothing:antialiased;`
|
|
5344
|
+
);
|
|
5345
|
+
root.setAttribute("data-aegis-reviews", "true");
|
|
5346
|
+
const summary = data.aggregate.ai_summary;
|
|
5347
|
+
if (summary && summary.text) root.appendChild(aiSummaryCard(summary));
|
|
5348
|
+
if (data.aggregate.count === 0) {
|
|
5349
|
+
root.appendChild(el("p", "font-size:15px;color:#9ca3af;padding:6px 0;", "No reviews yet — be the first to share your experience."));
|
|
5350
|
+
target.appendChild(root);
|
|
5351
|
+
return;
|
|
5352
|
+
}
|
|
5353
|
+
const header = el("div", "display:flex;flex-wrap:wrap;align-items:center;gap:24px 40px;padding-bottom:4px;");
|
|
5354
|
+
const ratingBlock = el("div", "display:flex;flex-direction:column;gap:4px;");
|
|
5355
|
+
const topRow = el("div", "display:flex;align-items:center;gap:12px;");
|
|
5356
|
+
const avg = data.aggregate.avg_rating ?? 0;
|
|
5357
|
+
topRow.appendChild(stars(Math.round(avg), 20));
|
|
5358
|
+
topRow.appendChild(el("span", "font-size:32px;font-weight:800;line-height:1;letter-spacing:-0.02em;", avg ? avg.toFixed(1) : "—"));
|
|
5359
|
+
ratingBlock.appendChild(topRow);
|
|
5360
|
+
ratingBlock.appendChild(el("span", "font-size:13px;color:#6b7280;", `${data.aggregate.count} review${data.aggregate.count === 1 ? "" : "s"} · 100% verified`));
|
|
5361
|
+
header.appendChild(ratingBlock);
|
|
5362
|
+
header.appendChild(distributionPanel(data.aggregate.distribution, data.aggregate.count));
|
|
5363
|
+
root.appendChild(header);
|
|
5364
|
+
root.appendChild(controls(() => {
|
|
5365
|
+
void fetchReviews().then((d) => renderList((d == null ? void 0 : d.items) ?? []));
|
|
5366
|
+
}));
|
|
5367
|
+
listContainer = el("div", "margin-top:2px;");
|
|
5368
|
+
root.appendChild(listContainer);
|
|
5369
|
+
renderList(data.items);
|
|
5370
|
+
target.appendChild(root);
|
|
5371
|
+
injectJsonLd(target, data, productId);
|
|
5372
|
+
ctx.trackEvent(ctx.campaign.id, "impression");
|
|
5373
|
+
}
|
|
5374
|
+
const compact = ic.display_style === "compact";
|
|
5375
|
+
function renderCompact(data) {
|
|
5376
|
+
var _a;
|
|
5377
|
+
target.innerHTML = "";
|
|
5378
|
+
if (data.aggregate.count === 0) return;
|
|
5379
|
+
const root = el(
|
|
5380
|
+
"section",
|
|
5381
|
+
`font-family:${IN_APP_FONT_STACK};color:#111827;max-width:860px;margin:0 auto;border:1px solid #f0f1f3;border-radius:16px;padding:16px 18px;`
|
|
5382
|
+
);
|
|
5383
|
+
const line = el("div", "display:flex;align-items:center;gap:8px;");
|
|
5384
|
+
const avg = data.aggregate.avg_rating ?? 0;
|
|
5385
|
+
line.appendChild(stars(Math.round(avg), 16));
|
|
5386
|
+
line.appendChild(el("span", "font-size:16px;font-weight:700;", avg ? avg.toFixed(1) : "—"));
|
|
5387
|
+
line.appendChild(el("span", "font-size:13px;color:#6b7280;", `(${data.aggregate.count})`));
|
|
5388
|
+
line.appendChild(verifiedBadge());
|
|
5389
|
+
root.appendChild(line);
|
|
5390
|
+
const top = data.items.find((i) => i.review_text);
|
|
5391
|
+
if (top && top.review_text) {
|
|
5392
|
+
root.appendChild(el("p", "margin:10px 0 0;font-size:15px;color:#374151;line-height:1.5;", `“${top.review_text}”`));
|
|
5393
|
+
root.appendChild(el("span", "font-size:13px;color:#9ca3af;", `— ${((_a = top.reviewer_snapshot) == null ? void 0 : _a.name) ?? "Customer"}`));
|
|
5394
|
+
}
|
|
5395
|
+
const seeAll = el("button", `margin-top:12px;font-size:14px;font-weight:700;color:${accent};background:none;border:none;cursor:pointer;padding:0;font-family:inherit;`, "See all reviews →");
|
|
5396
|
+
seeAll.addEventListener("click", () => renderWall(data));
|
|
5397
|
+
root.appendChild(seeAll);
|
|
5398
|
+
target.appendChild(root);
|
|
5399
|
+
ctx.trackEvent(ctx.campaign.id, "impression");
|
|
5400
|
+
}
|
|
5401
|
+
void fetchReviews().then((data) => {
|
|
5402
|
+
if (!data || !Array.isArray(data.items)) {
|
|
5403
|
+
target.innerHTML = "";
|
|
5404
|
+
return;
|
|
5405
|
+
}
|
|
5406
|
+
if (compact) renderCompact(data);
|
|
5407
|
+
else renderWall(data);
|
|
5408
|
+
});
|
|
5409
|
+
return true;
|
|
5410
|
+
}
|
|
5411
|
+
function renderReviewsOverlay(ctx, creds) {
|
|
5412
|
+
if (typeof document === "undefined" || !(creds == null ? void 0 : creds.apiHost) || !(creds == null ? void 0 : creds.writeKey)) return;
|
|
5413
|
+
ensureInAppFont();
|
|
5414
|
+
const overlay = document.createElement("div");
|
|
5415
|
+
overlay.setAttribute("data-campaign-id", ctx.campaign.id);
|
|
5416
|
+
overlay.style.cssText = "position:fixed;inset:0;background:rgba(17,24,39,0.5);display:flex;align-items:flex-end;justify-content:center;z-index:99999;";
|
|
5417
|
+
const sheet = document.createElement("div");
|
|
5418
|
+
sheet.style.cssText = `background:#fff;color:#111827;max-width:680px;width:100%;max-height:84vh;overflow-y:auto;border-radius:24px 24px 0 0;padding:18px 18px 28px;font-family:${IN_APP_FONT_STACK};box-shadow:0 -16px 40px rgba(0,0,0,0.14);`;
|
|
5419
|
+
sheet.appendChild(el("div", "width:38px;height:4px;border-radius:999px;background:#e5e7eb;margin:0 auto 14px;"));
|
|
5420
|
+
const bar = el("div", "display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;");
|
|
5421
|
+
bar.appendChild(el("div", "font-weight:800;font-size:17px;", ctx.campaign.title || "Customer reviews"));
|
|
5422
|
+
const close = el("button", "background:none;border:none;cursor:pointer;padding:4px 8px;color:#6b7280;");
|
|
5423
|
+
const x = document.createElementNS(SVG_NS, "svg");
|
|
5424
|
+
x.setAttribute("viewBox", "0 0 24 24");
|
|
5425
|
+
x.setAttribute("width", "20");
|
|
5426
|
+
x.setAttribute("height", "20");
|
|
5427
|
+
const xp = document.createElementNS(SVG_NS, "path");
|
|
5428
|
+
xp.setAttribute("d", "M18 6L6 18M6 6l12 12");
|
|
5429
|
+
xp.setAttribute("stroke", "currentColor");
|
|
5430
|
+
xp.setAttribute("stroke-width", "2");
|
|
5431
|
+
xp.setAttribute("stroke-linecap", "round");
|
|
5432
|
+
x.appendChild(xp);
|
|
5433
|
+
close.appendChild(x);
|
|
5434
|
+
close.setAttribute("aria-label", "Close");
|
|
5435
|
+
close.addEventListener("click", () => {
|
|
5436
|
+
ctx.trackEvent(ctx.campaign.id, "dismissed");
|
|
5437
|
+
overlay.remove();
|
|
5438
|
+
});
|
|
5439
|
+
bar.appendChild(close);
|
|
5440
|
+
sheet.appendChild(bar);
|
|
5441
|
+
const body = el("div");
|
|
5442
|
+
const pid = ctx.campaign.product_id;
|
|
5443
|
+
if (pid) body.setAttribute("data-product-id", pid);
|
|
5444
|
+
sheet.appendChild(body);
|
|
5445
|
+
overlay.appendChild(sheet);
|
|
5446
|
+
overlay.addEventListener("click", (e) => {
|
|
5447
|
+
if (e.target === overlay) {
|
|
5448
|
+
ctx.trackEvent(ctx.campaign.id, "dismissed");
|
|
5449
|
+
overlay.remove();
|
|
5450
|
+
}
|
|
5451
|
+
});
|
|
5452
|
+
document.body.appendChild(overlay);
|
|
5453
|
+
renderReviewsInline(ctx, body, creds);
|
|
5454
|
+
}
|
|
5018
5455
|
function readAnonIdFromStorage$1() {
|
|
5019
5456
|
if (typeof document === "undefined") return void 0;
|
|
5020
5457
|
try {
|
|
@@ -5642,8 +6079,8 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5642
6079
|
m2.addedNodes.forEach((n) => {
|
|
5643
6080
|
var _a, _b;
|
|
5644
6081
|
if (sawSlot || n.nodeType !== 1) return;
|
|
5645
|
-
const
|
|
5646
|
-
if (((_a =
|
|
6082
|
+
const el2 = n;
|
|
6083
|
+
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]"))) {
|
|
5647
6084
|
sawSlot = true;
|
|
5648
6085
|
}
|
|
5649
6086
|
});
|
|
@@ -5850,13 +6287,13 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5850
6287
|
const anchor = ic == null ? void 0 : ic.anchor;
|
|
5851
6288
|
const selector = anchor == null ? void 0 : anchor.element_selector;
|
|
5852
6289
|
if (!selector) continue;
|
|
5853
|
-
let
|
|
6290
|
+
let el2 = null;
|
|
5854
6291
|
try {
|
|
5855
|
-
|
|
6292
|
+
el2 = document.querySelector(selector);
|
|
5856
6293
|
} catch {
|
|
5857
|
-
|
|
6294
|
+
el2 = null;
|
|
5858
6295
|
}
|
|
5859
|
-
if (!
|
|
6296
|
+
if (!el2) {
|
|
5860
6297
|
void this.trackEvent(c.id, "anchor_unresolved", {
|
|
5861
6298
|
meta: { anchor_resolved: false, anchor_selector: selector, widget_type: c.sub_type }
|
|
5862
6299
|
});
|
|
@@ -5867,9 +6304,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
5867
6304
|
if (position === "before" || position === "after") {
|
|
5868
6305
|
target = document.createElement("div");
|
|
5869
6306
|
target.setAttribute("data-aegis-anchor-wrapper", c.id);
|
|
5870
|
-
(_a =
|
|
6307
|
+
(_a = el2.parentNode) == null ? void 0 : _a.insertBefore(target, position === "before" ? el2 : el2.nextSibling);
|
|
5871
6308
|
} else {
|
|
5872
|
-
target =
|
|
6309
|
+
target = el2;
|
|
5873
6310
|
if (position === "replace") {
|
|
5874
6311
|
target.querySelectorAll(":scope > [data-aegis-slot-default]").forEach((d) => d.remove());
|
|
5875
6312
|
}
|
|
@@ -6026,6 +6463,12 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
6026
6463
|
case "product_recommendation":
|
|
6027
6464
|
rendered = renderProductRecommendationInline(this.buildRenderContext(campaign), target);
|
|
6028
6465
|
break;
|
|
6466
|
+
case "reviews":
|
|
6467
|
+
rendered = renderReviewsInline(this.buildRenderContext(campaign), target, {
|
|
6468
|
+
apiHost: this.apiHost,
|
|
6469
|
+
writeKey: this.writeKey
|
|
6470
|
+
});
|
|
6471
|
+
break;
|
|
6029
6472
|
case "quiz":
|
|
6030
6473
|
rendered = this.renderQuizSlot(campaign, ic, bg, text, target);
|
|
6031
6474
|
if (!rendered) {
|
|
@@ -7078,17 +7521,27 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7078
7521
|
h.textContent = campaign.title;
|
|
7079
7522
|
card.appendChild(h);
|
|
7080
7523
|
}
|
|
7524
|
+
const layout = ic.rec_layout || "row";
|
|
7081
7525
|
const strip = document.createElement("div");
|
|
7082
|
-
|
|
7526
|
+
const pad = `${st.padY ?? 12}px ${st.padX ?? 12}px`;
|
|
7527
|
+
if (layout === "grid") {
|
|
7528
|
+
strip.style.cssText = `display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; padding: ${pad};`;
|
|
7529
|
+
} else if (layout === "list") {
|
|
7530
|
+
strip.style.cssText = `display: flex; flex-direction: column; gap: 8px; padding: ${pad};`;
|
|
7531
|
+
} else {
|
|
7532
|
+
strip.style.cssText = `display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: ${pad};`;
|
|
7533
|
+
}
|
|
7083
7534
|
const template = resolveGlobalTemplate(ic);
|
|
7084
7535
|
const ctx = this.buildRenderContext(campaign);
|
|
7085
7536
|
const accent = this.sanitizeColor(campaign.background_color || text);
|
|
7086
7537
|
cards.forEach((c, i) => {
|
|
7538
|
+
const meta = c.metadata || {};
|
|
7539
|
+
const linked = !!(meta.product_id || meta.sku);
|
|
7087
7540
|
const tile = renderCardFromTemplate(c, {
|
|
7088
7541
|
template,
|
|
7089
7542
|
ctx,
|
|
7090
|
-
action: "navigate",
|
|
7091
|
-
layout
|
|
7543
|
+
action: linked ? "cart" : "navigate",
|
|
7544
|
+
layout,
|
|
7092
7545
|
layoutAccent: accent
|
|
7093
7546
|
});
|
|
7094
7547
|
tile.setAttribute("data-card-index", String(i));
|
|
@@ -7096,6 +7549,43 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7096
7549
|
});
|
|
7097
7550
|
card.appendChild(strip);
|
|
7098
7551
|
target.appendChild(card);
|
|
7552
|
+
const autoplayMs = Number(ic.autoplay_ms) || 0;
|
|
7553
|
+
if (layout === "row" && autoplayMs > 0 && cards.length > 1) {
|
|
7554
|
+
const loop = ic.loop !== false;
|
|
7555
|
+
const interval = Math.max(autoplayMs, 600);
|
|
7556
|
+
let idx = 0;
|
|
7557
|
+
let timer = null;
|
|
7558
|
+
const stop = () => {
|
|
7559
|
+
if (timer) {
|
|
7560
|
+
clearInterval(timer);
|
|
7561
|
+
timer = null;
|
|
7562
|
+
}
|
|
7563
|
+
};
|
|
7564
|
+
timer = setInterval(() => {
|
|
7565
|
+
if (!document.body.contains(strip)) {
|
|
7566
|
+
stop();
|
|
7567
|
+
return;
|
|
7568
|
+
}
|
|
7569
|
+
if (strip.scrollWidth <= strip.clientWidth + 4) return;
|
|
7570
|
+
const tiles = Array.from(strip.children);
|
|
7571
|
+
idx += 1;
|
|
7572
|
+
if (idx >= tiles.length) {
|
|
7573
|
+
if (!loop) {
|
|
7574
|
+
stop();
|
|
7575
|
+
return;
|
|
7576
|
+
}
|
|
7577
|
+
idx = 0;
|
|
7578
|
+
}
|
|
7579
|
+
const el2 = tiles[idx];
|
|
7580
|
+
if (el2) {
|
|
7581
|
+
const delta = el2.getBoundingClientRect().left - strip.getBoundingClientRect().left;
|
|
7582
|
+
strip.scrollTo({ left: strip.scrollLeft + delta, behavior: "smooth" });
|
|
7583
|
+
}
|
|
7584
|
+
}, interval);
|
|
7585
|
+
["pointerdown", "wheel", "touchstart"].forEach(
|
|
7586
|
+
(evt) => strip.addEventListener(evt, stop, { passive: true })
|
|
7587
|
+
);
|
|
7588
|
+
}
|
|
7099
7589
|
return true;
|
|
7100
7590
|
}
|
|
7101
7591
|
/** Built-in embedded COUNTDOWN — live H:M:S digits that pulse red in the
|
|
@@ -7118,10 +7608,10 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7118
7608
|
const digits = document.createElement("div");
|
|
7119
7609
|
digits.style.cssText = "display: flex; gap: 6px; justify-content: center;";
|
|
7120
7610
|
const mkDigit = () => {
|
|
7121
|
-
const
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
return
|
|
7611
|
+
const el2 = document.createElement("span");
|
|
7612
|
+
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;`;
|
|
7613
|
+
el2.textContent = "00";
|
|
7614
|
+
return el2;
|
|
7125
7615
|
};
|
|
7126
7616
|
const hEl = mkDigit();
|
|
7127
7617
|
const mEl = mkDigit();
|
|
@@ -7151,9 +7641,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7151
7641
|
sEl.textContent = String(s).padStart(2, "0");
|
|
7152
7642
|
if (diff > 0 && diff <= 6e4 && !urgent) {
|
|
7153
7643
|
urgent = true;
|
|
7154
|
-
[hEl, mEl, sEl].forEach((
|
|
7155
|
-
|
|
7156
|
-
|
|
7644
|
+
[hEl, mEl, sEl].forEach((el2) => {
|
|
7645
|
+
el2.style.boxShadow = "0 0 0 2px #ef4444";
|
|
7646
|
+
el2.style.animation = "aegisUrgencyPulse 1s ease-in-out infinite";
|
|
7157
7647
|
});
|
|
7158
7648
|
}
|
|
7159
7649
|
if (diff > 0) requestAnimationFrame(tick);
|
|
@@ -7695,9 +8185,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7695
8185
|
*/
|
|
7696
8186
|
_flattenSlotCard(container) {
|
|
7697
8187
|
const cards = container.matches("[data-campaign-id]") ? [container] : Array.from(container.querySelectorAll("[data-campaign-id]"));
|
|
7698
|
-
for (const
|
|
7699
|
-
|
|
7700
|
-
|
|
8188
|
+
for (const el2 of cards) {
|
|
8189
|
+
el2.style.borderRadius = "0";
|
|
8190
|
+
el2.style.boxShadow = "none";
|
|
7701
8191
|
}
|
|
7702
8192
|
}
|
|
7703
8193
|
/**
|
|
@@ -7783,6 +8273,15 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7783
8273
|
this.emit("campaign-shown", campaign);
|
|
7784
8274
|
return;
|
|
7785
8275
|
}
|
|
8276
|
+
if (campaign.sub_type === "reviews") {
|
|
8277
|
+
renderReviewsOverlay(this.buildRenderContext(campaign), {
|
|
8278
|
+
apiHost: this.apiHost,
|
|
8279
|
+
writeKey: this.writeKey
|
|
8280
|
+
});
|
|
8281
|
+
this.trackEvent(campaign.id, "impression");
|
|
8282
|
+
this.emit("campaign-shown", campaign);
|
|
8283
|
+
return;
|
|
8284
|
+
}
|
|
7786
8285
|
{
|
|
7787
8286
|
const ic2 = campaign.interactive_config || {};
|
|
7788
8287
|
const multiCard2 = campaign.sub_type === "product_recommendation" || campaign.sub_type === "carousel_cards";
|
|
@@ -7910,7 +8409,7 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
7910
8409
|
navigate: (url, buttonId) => this.navigateToCampaignAction(campaign, url, buttonId),
|
|
7911
8410
|
dispatchAction: (action) => this.dispatchAction(action, campaign.id),
|
|
7912
8411
|
submitResponse: (responseType, payload) => this.submitWidgetResponse(campaign, responseType, payload),
|
|
7913
|
-
playReaction: (
|
|
8412
|
+
playReaction: (el2, intent, lottieFile, scope) => this._playReaction(el2, intent, lottieFile, campaign.interactive_config, scope),
|
|
7914
8413
|
haptic: (pattern) => {
|
|
7915
8414
|
try {
|
|
7916
8415
|
if (typeof navigator !== "undefined" && typeof navigator.vibrate === "function") {
|
|
@@ -8167,9 +8666,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8167
8666
|
if (cells.s) cells.s.textContent = pad(s);
|
|
8168
8667
|
if (!urgent && diff > 0 && diff <= 6e4) {
|
|
8169
8668
|
urgent = true;
|
|
8170
|
-
Object.values(cells).forEach((
|
|
8171
|
-
if (
|
|
8172
|
-
|
|
8669
|
+
Object.values(cells).forEach((el2) => {
|
|
8670
|
+
if (el2) {
|
|
8671
|
+
el2.style.boxShadow = "0 0 0 2px #ef4444";
|
|
8173
8672
|
}
|
|
8174
8673
|
});
|
|
8175
8674
|
digits.style.animation = "aegisCountdownPulse 1.1s ease-in-out infinite";
|
|
@@ -8698,58 +9197,21 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8698
9197
|
* 3. if STILL unhandled → canonical fallback (navigate to the product/cart
|
|
8699
9198
|
* page) so a CTA is never a dead no-op (the rail-"Add" 3rd-party gap).
|
|
8700
9199
|
* Both add-to-cart paths (card "Add" + the `aegis://cart-add` verb) funnel here,
|
|
8701
|
-
* so they're one behaviour
|
|
9200
|
+
* so they're one behaviour delivered to the host's single `onAction` handler.
|
|
9201
|
+
* (Phase E.2 hard cutover — the legacy `aegis:*` DOM events were removed.)
|
|
8702
9202
|
*/
|
|
8703
|
-
dispatchAction(action,
|
|
9203
|
+
dispatchAction(action, _campaignId) {
|
|
8704
9204
|
var _a;
|
|
8705
9205
|
let handled = false;
|
|
8706
9206
|
try {
|
|
8707
9207
|
handled = ((_a = this.onActionHandler) == null ? void 0 : _a.call(this, action)) === true;
|
|
8708
9208
|
} catch {
|
|
8709
9209
|
}
|
|
8710
|
-
if (typeof window !== "undefined") {
|
|
8711
|
-
const legacy = this._legacyEventFor(action, campaignId);
|
|
8712
|
-
if (legacy) {
|
|
8713
|
-
const evt = new CustomEvent(legacy.name, { detail: legacy.detail, cancelable: true });
|
|
8714
|
-
const proceed = window.dispatchEvent(evt);
|
|
8715
|
-
if (!proceed || evt.defaultPrevented) handled = true;
|
|
8716
|
-
}
|
|
8717
|
-
}
|
|
8718
9210
|
if (!handled) {
|
|
8719
9211
|
const url = fallbackUrlForAction(action, this.productUrl);
|
|
8720
9212
|
if (url && typeof window !== "undefined") window.location.href = url;
|
|
8721
9213
|
}
|
|
8722
9214
|
}
|
|
8723
|
-
/** Back-compat mapping: canonical action → the legacy DOM event hosts listen
|
|
8724
|
-
* for today. `add_to_cart` always emits `aegis:add-to-cart` (the one ACS
|
|
8725
|
-
* handles), collapsing the old `aegis:cart-add` divergence. */
|
|
8726
|
-
_legacyEventFor(a, campaignId) {
|
|
8727
|
-
const base = { campaign_id: campaignId };
|
|
8728
|
-
switch (a.type) {
|
|
8729
|
-
case "add_to_cart":
|
|
8730
|
-
return {
|
|
8731
|
-
name: "aegis:add-to-cart",
|
|
8732
|
-
detail: {
|
|
8733
|
-
...base,
|
|
8734
|
-
product_id: a.productId,
|
|
8735
|
-
sku: a.sku,
|
|
8736
|
-
title: a.title,
|
|
8737
|
-
price: a.price,
|
|
8738
|
-
image_url: a.imageUrl,
|
|
8739
|
-
cta_url: a.url,
|
|
8740
|
-
qty: a.qty ?? 1
|
|
8741
|
-
}
|
|
8742
|
-
};
|
|
8743
|
-
case "open_product":
|
|
8744
|
-
return { name: "aegis:open-product", detail: { ...base, sku: a.sku, product_id: a.productId, url: a.url } };
|
|
8745
|
-
case "open_cart":
|
|
8746
|
-
return { name: "aegis:open-cart", detail: base };
|
|
8747
|
-
case "open_login":
|
|
8748
|
-
return { name: "aegis:open-login", detail: base };
|
|
8749
|
-
default:
|
|
8750
|
-
return null;
|
|
8751
|
-
}
|
|
8752
|
-
}
|
|
8753
9215
|
/**
|
|
8754
9216
|
* Phase-2 CTA action verbs (`aegis://<verb>?<params>`). Performs an in-app
|
|
8755
9217
|
* behaviour instead of navigating. Verbs:
|
|
@@ -8789,9 +9251,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
8789
9251
|
/** Remove a rendered campaign's element(s) from the DOM by campaign id. */
|
|
8790
9252
|
removeCampaignEl(campaignId) {
|
|
8791
9253
|
if (typeof document === "undefined") return;
|
|
8792
|
-
document.querySelectorAll(`[data-campaign-id="${campaignId}"]`).forEach((
|
|
9254
|
+
document.querySelectorAll(`[data-campaign-id="${campaignId}"]`).forEach((el2) => {
|
|
8793
9255
|
var _a;
|
|
8794
|
-
return (_a =
|
|
9256
|
+
return (_a = el2.parentNode) == null ? void 0 : _a.removeChild(el2);
|
|
8795
9257
|
});
|
|
8796
9258
|
}
|
|
8797
9259
|
/**
|
|
@@ -10518,9 +10980,9 @@ const _AegisInAppManager = class _AegisInAppManager {
|
|
|
10518
10980
|
if (typeof document !== "undefined") {
|
|
10519
10981
|
document.querySelectorAll(
|
|
10520
10982
|
".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"
|
|
10521
|
-
).forEach((
|
|
10522
|
-
if (
|
|
10523
|
-
|
|
10983
|
+
).forEach((el2) => {
|
|
10984
|
+
if (el2.parentNode) {
|
|
10985
|
+
el2.parentNode.removeChild(el2);
|
|
10524
10986
|
}
|
|
10525
10987
|
});
|
|
10526
10988
|
const styles = document.getElementById("aegis-in-app-styles");
|
|
@@ -10552,9 +11014,9 @@ let AegisInAppManager = _AegisInAppManager;
|
|
|
10552
11014
|
function renderPreview(config, opts) {
|
|
10553
11015
|
document.querySelectorAll(
|
|
10554
11016
|
'[class^="aegis-in-app-"]'
|
|
10555
|
-
).forEach((
|
|
10556
|
-
if (
|
|
10557
|
-
|
|
11017
|
+
).forEach((el2) => {
|
|
11018
|
+
if (el2.parentNode) {
|
|
11019
|
+
el2.parentNode.removeChild(el2);
|
|
10558
11020
|
}
|
|
10559
11021
|
});
|
|
10560
11022
|
try {
|
|
@@ -10590,7 +11052,7 @@ function renderPreview(config, opts) {
|
|
|
10590
11052
|
if (anchors.length > 0) {
|
|
10591
11053
|
try {
|
|
10592
11054
|
anchors.forEach((slot) => {
|
|
10593
|
-
slot.querySelectorAll(":scope > :not([data-aegis-slot-default])").forEach((
|
|
11055
|
+
slot.querySelectorAll(":scope > :not([data-aegis-slot-default])").forEach((el2) => el2.remove());
|
|
10594
11056
|
});
|
|
10595
11057
|
const mm = manager;
|
|
10596
11058
|
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));
|
|
@@ -10611,17 +11073,17 @@ function renderPreview(config, opts) {
|
|
|
10611
11073
|
m2.displayCampaign(config);
|
|
10612
11074
|
}
|
|
10613
11075
|
const MAX_NODES = 400;
|
|
10614
|
-
function selectorFor(
|
|
10615
|
-
if (
|
|
11076
|
+
function selectorFor(el2) {
|
|
11077
|
+
if (el2.id) return `#${CSS.escape(el2.id)}`;
|
|
10616
11078
|
for (const attr of ["data-testid", "data-test", "data-aegis-anchor", "data-qa", "name"]) {
|
|
10617
|
-
const v =
|
|
11079
|
+
const v = el2.getAttribute(attr);
|
|
10618
11080
|
if (v) {
|
|
10619
|
-
const sel = `${
|
|
11081
|
+
const sel = `${el2.tagName.toLowerCase()}[${attr}="${CSS.escape(v)}"]`;
|
|
10620
11082
|
if (document.querySelectorAll(sel).length === 1) return sel;
|
|
10621
11083
|
}
|
|
10622
11084
|
}
|
|
10623
11085
|
const parts = [];
|
|
10624
|
-
let node =
|
|
11086
|
+
let node = el2;
|
|
10625
11087
|
while (node && node !== document.body && parts.length < 6) {
|
|
10626
11088
|
if (node.id) {
|
|
10627
11089
|
parts.unshift(`#${CSS.escape(node.id)}`);
|
|
@@ -10645,15 +11107,15 @@ function captureWebScreen(screenName) {
|
|
|
10645
11107
|
const candidates = document.querySelectorAll(
|
|
10646
11108
|
"a,button,input,select,textarea,[role],[data-aegis-anchor],[data-testid],h1,h2,h3,img,[data-aegis-slot]"
|
|
10647
11109
|
);
|
|
10648
|
-
for (const
|
|
11110
|
+
for (const el2 of Array.from(candidates)) {
|
|
10649
11111
|
if (nodes.length >= MAX_NODES) break;
|
|
10650
|
-
const rect =
|
|
11112
|
+
const rect = el2.getBoundingClientRect();
|
|
10651
11113
|
if (rect.width <= 0 || rect.height <= 0) continue;
|
|
10652
|
-
const slotKey =
|
|
10653
|
-
const role = slotKey ? `slot:${slotKey}` :
|
|
10654
|
-
const text = (
|
|
11114
|
+
const slotKey = el2.getAttribute("data-aegis-slot");
|
|
11115
|
+
const role = slotKey ? `slot:${slotKey}` : el2.getAttribute("role") || el2.tagName.toLowerCase();
|
|
11116
|
+
const text = (el2.textContent || el2.getAttribute("aria-label") || "").trim().slice(0, 80);
|
|
10655
11117
|
nodes.push({
|
|
10656
|
-
selector: selectorFor(
|
|
11118
|
+
selector: selectorFor(el2),
|
|
10657
11119
|
role,
|
|
10658
11120
|
...text ? { text } : {},
|
|
10659
11121
|
bounds: {
|