@thg-agentic/hyper-personalisation-web 3.22.2 → 3.24.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.
@@ -0,0 +1,97 @@
1
+ /**
2
+ * `./onsite/preview`: the console's preview of a creative, drawn by the shoppers' own renderer
3
+ * inside the console's box instead of over the page. It makes no request, sends no event and counts
4
+ * nothing: its buttons only move between steps, and closing does nothing. A popup, sheet, bar or
5
+ * teaser sits inside `host` as it would in the viewport (the host contains its fixed layers), and
6
+ * `device` picks the small-screen layout whatever the console's own width.
7
+ */
8
+
9
+ import { answerFields, answerOf } from './answers.js';
10
+ import { mountForm } from './render.js';
11
+ import { readCreative } from './rules.js';
12
+ import { mountWheel } from './wheel.js';
13
+
14
+ export { CALLING_CODES } from './rules.js';
15
+
16
+ const SAMPLE_CONSENT = 'Your consent text appears here.';
17
+ const SAMPLE_SMS_CONSENT = 'Your SMS consent text appears here.';
18
+ const noop = () => {};
19
+ const silent = { analytics: () => false };
20
+ const inert = {
21
+ submitted: noop,
22
+ closed: noop,
23
+ shown: noop,
24
+ tab: noop,
25
+ code: noop,
26
+ };
27
+ /** A basket to show a progress block against, when the console gives none. */
28
+ const SAMPLE_BASKET = 32;
29
+
30
+ /**
31
+ * Render `creative` into `host`.
32
+ *
33
+ * @param {HTMLElement} host The console's element; the preview fills it.
34
+ * @param {unknown} creative The arm's payload.
35
+ * @param {{ step?: string, device?: 'desktop'|'mobile', consentText?: string, smsConsentText?: string, locale?: string,
36
+ * questions?: Array<{ key: string, type?: 'one'|'many'|'date'|'number', label?: string, options?: Array<{ value: string, label?: string }>, format?: object }>,
37
+ * prizes?: Array<{ key: string, label: string }>, basketValue?: number }} [options]
38
+ * @returns {{ update(creative: unknown, options?: object): void, destroy(): void, step(): string|null }}
39
+ */
40
+ export function mountPreview(host, creative, options = {}) {
41
+ let mounted = null;
42
+ let last = options;
43
+
44
+ const render = (doc, opts) => {
45
+ const read = readCreative(doc);
46
+ mounted?.destroy();
47
+ mounted = null;
48
+ if (!read) return;
49
+ const format = read.format ?? 'popup';
50
+ mounted = mountForm({
51
+ form: {
52
+ slot: 'preview',
53
+ format,
54
+ // The settings' `locale`, so the preview orders a birthday and picks a phone's
55
+ // country as shoppers see them, not by the console's own language.
56
+ ...(opts.locale ? { locale: opts.locale } : {}),
57
+ consent_text: { text: opts.consentText ?? SAMPLE_CONSENT },
58
+ sms_consent_text: { text: opts.smsConsentText ?? SAMPLE_SMS_CONSENT },
59
+ questions: Array.isArray(opts.questions) ? opts.questions : [],
60
+ prizes: Array.isArray(opts.prizes) ? opts.prizes : [],
61
+ },
62
+ creative: read,
63
+ decision: { slot: 'preview' },
64
+ access: silent,
65
+ client: null,
66
+ api: null,
67
+ counters: inert,
68
+ loadWheel: () => Promise.resolve({ mountWheel }),
69
+ loadAnswers: () => Promise.resolve({ answerFields, answerOf }),
70
+ basket: () =>
71
+ Number.isFinite(opts.basketValue) ? opts.basketValue : SAMPLE_BASKET,
72
+ container: host,
73
+ preview: {
74
+ device: opts.device === 'mobile' ? 'mobile' : 'desktop',
75
+ step: opts.step,
76
+ },
77
+ });
78
+ };
79
+
80
+ render(creative, options);
81
+ return {
82
+ /** Re-render, on the step shown unless `options.step` names another. */
83
+ update(next, opts = {}) {
84
+ last = {
85
+ ...last,
86
+ ...opts,
87
+ step: opts.step ?? mounted?.step() ?? undefined,
88
+ };
89
+ render(next, last);
90
+ },
91
+ destroy() {
92
+ mounted?.destroy();
93
+ mounted = null;
94
+ },
95
+ step: () => mounted?.step() ?? null,
96
+ };
97
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The renderer, only once a form is to show: a bundler splits this import out of ./onsite, and the
3
+ * CDN build swaps this module for cdn/render-loader.js, which loads dist/onsite-render.min.js.
4
+ */
5
+ export const loadRender = () => import('./render.js');