@mrrocket/sdk 0.16.0 → 0.18.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/CHANGELOG.md +25 -0
- package/README.md +11 -2
- package/dist/api-client.d.ts +7 -1
- package/dist/api-client.js.map +1 -1
- package/dist/browser/mrrocket-flows.js +16 -2
- package/dist/browser/mrrocket-messenger.js +43 -44
- package/dist/browser/mrrocket.js +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/client.d.ts +23 -3
- package/dist/client.js +15 -1
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +3 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/finish-web.d.ts +18 -0
- package/dist/finish-web.js +139 -0
- package/dist/finish-web.js.map +1 -0
- package/dist/flows-ui.d.ts +1 -10
- package/dist/flows-ui.js +165 -16
- package/dist/flows-ui.js.map +1 -1
- package/dist/flows-web.d.ts +8 -1
- package/dist/flows-web.js +8 -0
- package/dist/flows-web.js.map +1 -1
- package/dist/flows.d.ts +203 -5
- package/dist/flows.js +306 -15
- package/dist/flows.js.map +1 -1
- package/dist/icons.d.ts +24 -0
- package/dist/icons.js +61 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +10 -2
- package/dist/messenger-ui.js +134 -98
- package/dist/messenger-ui.js.map +1 -1
- package/dist/onboarding-state.d.ts +23 -0
- package/dist/onboarding-state.js +43 -0
- package/dist/onboarding-state.js.map +1 -0
- package/dist/react-native/index.d.cts +216 -15
- package/dist/react-native/index.d.ts +216 -15
- package/dist/react-native/index.js +880 -270
- package/dist/react-native/index.js.map +1 -1
- package/dist/styles-css.d.ts +1 -1
- package/dist/styles-css.js +40 -41
- package/dist/styles-css.js.map +1 -1
- package/package.json +1 -1
package/dist/flows.js
CHANGED
|
@@ -22,6 +22,41 @@ var matchesTrigger = (trigger, event) => {
|
|
|
22
22
|
return t === e || SIGNUP.has(t) && SIGNUP.has(e);
|
|
23
23
|
};
|
|
24
24
|
var startsOnLoad = (trigger) => /^(first (launch|visit|open|session|login|sign ?in|app open)|app (opened|launched)|on load|every visit|always)?$/i.test(trigger.trim());
|
|
25
|
+
var FROM_CHECKLIST = "From a checklist";
|
|
26
|
+
var isPageTrigger = (trigger) => trigger.trim().startsWith("/");
|
|
27
|
+
var FROM_CODE = "From your code";
|
|
28
|
+
var NEEDS_NEWER = "Needs tracking code 0.18.0";
|
|
29
|
+
var momentOf = (f) => f.when ?? f.trigger;
|
|
30
|
+
var manual = (trigger) => eventSlug(trigger) === "from_a_checklist" || eventSlug(trigger) === "from_your_code" || eventSlug(trigger) === eventSlug(NEEDS_NEWER);
|
|
31
|
+
var AFTER_PREFIX = "after:";
|
|
32
|
+
var afterOf = (trigger) => {
|
|
33
|
+
const t = (trigger ?? "").trim();
|
|
34
|
+
return t.toLowerCase().startsWith(AFTER_PREFIX) ? t.slice(AFTER_PREFIX.length).trim() || null : null;
|
|
35
|
+
};
|
|
36
|
+
var opensOf = (step) => step.opens ?? (step.startsTour ? { kind: "tour", id: step.startsTour } : void 0);
|
|
37
|
+
var answerOk = (q, value) => {
|
|
38
|
+
if (!q || value == null) return false;
|
|
39
|
+
if (q.type === "choice") return (q.options ?? []).some((o) => o.id === value);
|
|
40
|
+
return value.trim().length > 0 && value.length <= 500;
|
|
41
|
+
};
|
|
42
|
+
var answerLabel = (q, value) => q?.type === "choice" ? q.options?.find((o) => o.id === value)?.label ?? value : value.trim();
|
|
43
|
+
var videoEmbed = (url) => {
|
|
44
|
+
const u = (url ?? "").trim();
|
|
45
|
+
if (!/^https?:\/\//i.test(u)) return null;
|
|
46
|
+
let m = u.match(/^https?:\/\/(?:www\.|m\.)?(?:youtube\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/|live\/)|youtu\.be\/|youtube-nocookie\.com\/embed\/)([\w-]{6,20})/i);
|
|
47
|
+
if (m) return { kind: "iframe", src: `https://www.youtube-nocookie.com/embed/${m[1]}?rel=0` };
|
|
48
|
+
m = u.match(/^https?:\/\/(?:www\.|player\.)?vimeo\.com\/(?:video\/)?(\d{4,12})/i);
|
|
49
|
+
if (m) return { kind: "iframe", src: `https://player.vimeo.com/video/${m[1]}?dnt=1` };
|
|
50
|
+
m = u.match(/^https?:\/\/(?:www\.)?loom\.com\/(?:share|embed)\/([\w-]{8,64})/i);
|
|
51
|
+
if (m) return { kind: "iframe", src: `https://www.loom.com/embed/${m[1]}` };
|
|
52
|
+
if (/\.(mp4|webm|mov|m4v)(\?|#|$)/i.test(u) || /\/media\/uploads\//.test(u)) return { kind: "file", src: u };
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
var mediaOf = (step) => {
|
|
56
|
+
const m = step.media;
|
|
57
|
+
if (!m || m.kind !== "image" && m.kind !== "video" || !/^https?:\/\//i.test(m.url ?? "")) return void 0;
|
|
58
|
+
return m.kind === "video" && !videoEmbed(m.url) ? void 0 : m;
|
|
59
|
+
};
|
|
25
60
|
var runId = () => `cf_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
|
|
26
61
|
var discounted = (amount, percent) => Math.round(amount * (1 - percent / 100) * 100) / 100;
|
|
27
62
|
var money = (amount, currency) => {
|
|
@@ -69,7 +104,13 @@ var createFlows = (env) => {
|
|
|
69
104
|
const seenEvents = /* @__PURE__ */ new Set();
|
|
70
105
|
const now = () => env.now?.() ?? Date.now();
|
|
71
106
|
let timer = null;
|
|
107
|
+
let returnTo = null;
|
|
108
|
+
const answers = /* @__PURE__ */ new Map();
|
|
109
|
+
const drafts = /* @__PURE__ */ new Map();
|
|
110
|
+
const celebrated = /* @__PURE__ */ new Set();
|
|
111
|
+
let finaleNow = null;
|
|
72
112
|
const flows = () => config?.onboarding ?? [];
|
|
113
|
+
const drawn = () => flows().filter((f) => f.shownBy !== "code");
|
|
73
114
|
const flowById = (id) => id ? flows().find((f) => f.id === id) : void 0;
|
|
74
115
|
const prog = (id) => {
|
|
75
116
|
let p = progress.get(id);
|
|
@@ -143,6 +184,14 @@ var createFlows = (env) => {
|
|
|
143
184
|
};
|
|
144
185
|
const keyOf = (pid) => `${PROGRESS_KEY}:${pid ?? "visitor"}`;
|
|
145
186
|
const eventsKeyOf = (pid) => `${PROGRESS_KEY}:events:${pid ?? "visitor"}`;
|
|
187
|
+
const answersKeyOf = (pid) => `${PROGRESS_KEY}:answers:${pid ?? "visitor"}`;
|
|
188
|
+
const celebrate = (f) => {
|
|
189
|
+
if (!f.finish || f.finish === "none" || f.shownBy === "code" || celebrated.has(f.id)) return;
|
|
190
|
+
const p = progress.get(f.id);
|
|
191
|
+
if (!p || p.dismissed || walkLine(f, nodesOf(f), p, false).at !== "end") return;
|
|
192
|
+
celebrated.add(f.id);
|
|
193
|
+
finaleNow = { kind: f.finish, key: `${f.id}:${now()}` };
|
|
194
|
+
};
|
|
146
195
|
const save = () => {
|
|
147
196
|
dirty = false;
|
|
148
197
|
const store = env.storage?.();
|
|
@@ -158,6 +207,7 @@ var createFlows = (env) => {
|
|
|
158
207
|
};
|
|
159
208
|
try {
|
|
160
209
|
store.set(keyOf(env.personId()), JSON.stringify(out));
|
|
210
|
+
if (answers.size) store.set(answersKeyOf(env.personId()), JSON.stringify(Object.fromEntries(answers)));
|
|
161
211
|
if (seenEvents.size) store.set(eventsKeyOf(env.personId()), JSON.stringify([...seenEvents].slice(-200)));
|
|
162
212
|
} catch {
|
|
163
213
|
}
|
|
@@ -206,7 +256,23 @@ var createFlows = (env) => {
|
|
|
206
256
|
shown.add(`s:${i.id}`);
|
|
207
257
|
env.track(ONBOARDING_EVENT, { flow: flow.id, step: i.id, kind: "checklist", action: "shown" });
|
|
208
258
|
}
|
|
209
|
-
return {
|
|
259
|
+
return {
|
|
260
|
+
type: "checklist",
|
|
261
|
+
flow,
|
|
262
|
+
items: items.map((s) => {
|
|
263
|
+
const o = opensOf(s);
|
|
264
|
+
const t = o && (o.kind === "tour" || o.kind === "modal") && o.id !== flow.id ? flowById(o.id) : void 0;
|
|
265
|
+
const target = t && t.shownBy !== "code" && nodesOf(t).length ? t : void 0;
|
|
266
|
+
const opens = o && (o.kind === "page" ? !!o.target.trim() : o.kind === "code" || !!target) ? o : void 0;
|
|
267
|
+
return {
|
|
268
|
+
step: s,
|
|
269
|
+
done: p.done.has(s.id),
|
|
270
|
+
...target && o?.kind === "tour" ? { tour: target } : {},
|
|
271
|
+
...opens ? { opens } : {},
|
|
272
|
+
...target ? { target } : {}
|
|
273
|
+
};
|
|
274
|
+
})
|
|
275
|
+
};
|
|
210
276
|
}
|
|
211
277
|
if (!shown.has(`s:${step.id}`)) {
|
|
212
278
|
shown.add(`s:${step.id}`);
|
|
@@ -215,7 +281,16 @@ var createFlows = (env) => {
|
|
|
215
281
|
const rest = line.slice(index + 1);
|
|
216
282
|
const fork = rest.findIndex((n) => n.kind === "condition");
|
|
217
283
|
const ahead = (fork < 0 ? rest : rest.slice(0, fork)).filter(isStep).length;
|
|
218
|
-
return {
|
|
284
|
+
return {
|
|
285
|
+
type: "step",
|
|
286
|
+
flow,
|
|
287
|
+
step,
|
|
288
|
+
index: w.before,
|
|
289
|
+
total: w.before + 1 + ahead,
|
|
290
|
+
last: !ahead && fork < 0,
|
|
291
|
+
// 0.18.0: a question's answer so far, and whether there is one before it to go back to.
|
|
292
|
+
...step.kind === "question" ? { answer: drafts.get(step.id) ?? (step.question ? answers.get(step.question.key) : void 0), back: w.before > 0 } : {}
|
|
293
|
+
};
|
|
219
294
|
};
|
|
220
295
|
const view = () => {
|
|
221
296
|
if (cancel) {
|
|
@@ -240,7 +315,30 @@ var createFlows = (env) => {
|
|
|
240
315
|
}
|
|
241
316
|
const ob = onboardingView();
|
|
242
317
|
if (ob) return ob;
|
|
243
|
-
if (active && !holding)
|
|
318
|
+
if (active && !holding) {
|
|
319
|
+
const back = returnTo;
|
|
320
|
+
const ended2 = active;
|
|
321
|
+
returnTo = null;
|
|
322
|
+
active = null;
|
|
323
|
+
const list = back ? flowById(back.flow) : void 0;
|
|
324
|
+
if (back && list) {
|
|
325
|
+
const item = stepsIn(nodesOf(list)).find((s) => s.id === back.step);
|
|
326
|
+
const p = prog(list.id);
|
|
327
|
+
if (item && !item.event && !progress.get(ended2)?.dismissed && !p.done.has(item.id)) {
|
|
328
|
+
markDone(p, item.id);
|
|
329
|
+
record({ flow: list.id, step: item.id, kind: "checklist", action: "completed" });
|
|
330
|
+
celebrate(list);
|
|
331
|
+
}
|
|
332
|
+
active = list.id;
|
|
333
|
+
const again = onboardingView();
|
|
334
|
+
if (again) return again;
|
|
335
|
+
if (!holding) active = null;
|
|
336
|
+
} else if (known) {
|
|
337
|
+
const was = flowById(ended2);
|
|
338
|
+
const after = was ? momentOf(was) : void 0;
|
|
339
|
+
Promise.resolve().then(() => autoStart(after));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
244
342
|
const m = messages.find((x) => !handled.has(x.id));
|
|
245
343
|
return m ? { type: "message", message: m } : null;
|
|
246
344
|
};
|
|
@@ -265,19 +363,67 @@ var createFlows = (env) => {
|
|
|
265
363
|
emit();
|
|
266
364
|
return true;
|
|
267
365
|
};
|
|
268
|
-
const
|
|
366
|
+
const allowed = (f) => f.audience === "answered" ? !!f.answered && answers.get(f.answered.question) === f.answered.option : f.audience !== "signed_in" || !!env.personId();
|
|
367
|
+
const predecessorEnded = (id) => {
|
|
368
|
+
const g = flowById(id);
|
|
369
|
+
return !g || finished(g);
|
|
370
|
+
};
|
|
371
|
+
const due = (f, trigger = momentOf(f)) => {
|
|
372
|
+
const path = env.path?.();
|
|
373
|
+
const pred = afterOf(trigger);
|
|
374
|
+
if (pred) return predecessorEnded(pred);
|
|
375
|
+
if (manual(trigger)) return false;
|
|
376
|
+
if (isPageTrigger(trigger)) return path !== void 0 && pageMatches(trigger, path);
|
|
377
|
+
if (startsOnLoad(trigger)) return true;
|
|
378
|
+
for (const e of seenEvents) if (matchesTrigger(trigger, e)) return true;
|
|
379
|
+
return false;
|
|
380
|
+
};
|
|
381
|
+
const autoStart = (after) => {
|
|
269
382
|
if (!auto || active || !known) return;
|
|
270
383
|
if (!env.personId() && !env.storage?.()) return;
|
|
271
|
-
const
|
|
384
|
+
const path = env.path?.();
|
|
385
|
+
const same = after && !manual(after) ? eventSlug(after) : "";
|
|
386
|
+
const next = drawn().find(
|
|
387
|
+
(f) => (afterOf(momentOf(f)) ? predecessorEnded(afterOf(momentOf(f))) : isPageTrigger(momentOf(f)) ? path !== void 0 && pageMatches(momentOf(f), path) : startsOnLoad(momentOf(f)) || !!same && eventSlug(momentOf(f)) === same) && allowed(f) && nodesOf(f).length && !finished(f)
|
|
388
|
+
);
|
|
272
389
|
if (next) start(next);
|
|
273
390
|
};
|
|
391
|
+
const openItem = (list, stepId, target) => {
|
|
392
|
+
const p = prog(target.id);
|
|
393
|
+
p.done.clear();
|
|
394
|
+
p.at.clear();
|
|
395
|
+
p.dismissed = false;
|
|
396
|
+
returnTo = { flow: list.id, step: stepId };
|
|
397
|
+
active = target.id;
|
|
398
|
+
env.track(ONBOARDING_EVENT, { flow: target.id, action: "started", from: list.id });
|
|
399
|
+
save();
|
|
400
|
+
emit();
|
|
401
|
+
};
|
|
402
|
+
const answerStep = (flow, step, raw) => {
|
|
403
|
+
const q = step.question;
|
|
404
|
+
const value = q.type === "text" ? raw.trim().slice(0, 500) : raw;
|
|
405
|
+
answers.set(q.key, value);
|
|
406
|
+
drafts.delete(step.id);
|
|
407
|
+
markDone(prog(flow.id), step.id);
|
|
408
|
+
env.track(ONBOARDING_EVENT, { flow: flow.id, step: step.id, kind: "question", action: "completed", question: q.key, answer: value, label: answerLabel(q, value) });
|
|
409
|
+
celebrate(flow);
|
|
410
|
+
save();
|
|
411
|
+
};
|
|
412
|
+
const ended = (f) => {
|
|
413
|
+
save();
|
|
414
|
+
if (finished(f)) Promise.resolve().then(() => autoStart());
|
|
415
|
+
emit();
|
|
416
|
+
};
|
|
274
417
|
const refresh = () => {
|
|
275
418
|
const pid = env.personId();
|
|
276
419
|
if (progressFor !== null && progressFor !== pid) {
|
|
277
420
|
progress.clear();
|
|
278
421
|
seenEvents.clear();
|
|
422
|
+
answers.clear();
|
|
423
|
+
drafts.clear();
|
|
279
424
|
handled.clear();
|
|
280
425
|
active = null;
|
|
426
|
+
returnTo = null;
|
|
281
427
|
loadedFor = void 0;
|
|
282
428
|
}
|
|
283
429
|
progressFor = pid;
|
|
@@ -291,6 +437,10 @@ var createFlows = (env) => {
|
|
|
291
437
|
if (seen) {
|
|
292
438
|
for (const e of JSON.parse(seen)) if (typeof e === "string") seenEvents.add(e);
|
|
293
439
|
}
|
|
440
|
+
const said = await store.get(answersKeyOf(pid));
|
|
441
|
+
if (said) {
|
|
442
|
+
for (const [k, v] of Object.entries(JSON.parse(said))) if (typeof v === "string") answers.set(k, v);
|
|
443
|
+
}
|
|
294
444
|
} catch {
|
|
295
445
|
}
|
|
296
446
|
}
|
|
@@ -301,6 +451,7 @@ var createFlows = (env) => {
|
|
|
301
451
|
if (state && env.personId() === pid) {
|
|
302
452
|
merge(state.onboarding);
|
|
303
453
|
for (const e of state.events ?? []) if (typeof e === "string") seenEvents.add(eventSlug(e));
|
|
454
|
+
for (const [k, v] of Object.entries(state.answers ?? {})) if (typeof v === "string" && !answers.has(k)) answers.set(k, v);
|
|
304
455
|
messages = (state.messages ?? []).filter((m) => m && m.id && m.title);
|
|
305
456
|
}
|
|
306
457
|
}
|
|
@@ -387,33 +538,40 @@ var createFlows = (env) => {
|
|
|
387
538
|
},
|
|
388
539
|
refresh,
|
|
389
540
|
onEvent: (name) => {
|
|
541
|
+
if (name === "$pageview") autoStart();
|
|
390
542
|
if (!name || name.startsWith("$")) return;
|
|
391
543
|
const slug = eventSlug(name);
|
|
392
544
|
const fresh = !!slug && !seenEvents.has(slug);
|
|
393
545
|
if (fresh) seenEvents.add(slug);
|
|
394
546
|
const flow = flowById(active);
|
|
395
547
|
let ticked = false;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
548
|
+
const lists = [...flow ? [flow] : [], ...flows().filter((f) => f.shownBy === "code" && f.id !== flow?.id)];
|
|
549
|
+
for (const l of lists) {
|
|
550
|
+
const p = prog(l.id);
|
|
551
|
+
let here = false;
|
|
552
|
+
for (const s of stepsIn(nodesOf(l)))
|
|
399
553
|
if (s.kind === "checklist" && s.event && !p.done.has(s.id) && matchesTrigger(s.event, name)) {
|
|
400
554
|
markDone(p, s.id);
|
|
401
|
-
|
|
402
|
-
env.track(ONBOARDING_EVENT, { flow:
|
|
555
|
+
here = true;
|
|
556
|
+
env.track(ONBOARDING_EVENT, { flow: l.id, step: s.id, kind: s.kind, action: "completed" });
|
|
403
557
|
}
|
|
558
|
+
if (here) {
|
|
559
|
+
ticked = true;
|
|
560
|
+
celebrate(l);
|
|
561
|
+
}
|
|
404
562
|
}
|
|
405
|
-
if (ticked || fresh && flow) {
|
|
563
|
+
if (ticked || fresh && (flow || lists.length)) {
|
|
406
564
|
save();
|
|
407
565
|
emit();
|
|
408
566
|
} else if (fresh) save();
|
|
409
567
|
if (!auto || !env.personId() && !env.storage?.()) return;
|
|
410
|
-
const next =
|
|
568
|
+
const next = drawn().find((f) => nodesOf(f).length && !manual(momentOf(f)) && matchesTrigger(momentOf(f), name) && allowed(f) && !finished(f));
|
|
411
569
|
if (next) start(next);
|
|
412
570
|
},
|
|
413
571
|
openCancelFlow,
|
|
414
572
|
startOnboarding: (id) => {
|
|
415
|
-
const f = id ? flowById(id) :
|
|
416
|
-
if (!f || !nodesOf(f).length) return false;
|
|
573
|
+
const f = id ? flowById(id) : drawn().find((x) => nodesOf(x).length && !manual(momentOf(x)) && !afterOf(momentOf(x)) && !finished(x));
|
|
574
|
+
if (!f || !nodesOf(f).length || f.shownBy === "code") return false;
|
|
417
575
|
const p = prog(f.id);
|
|
418
576
|
p.dismissed = false;
|
|
419
577
|
return start(f);
|
|
@@ -504,10 +662,21 @@ var createFlows = (env) => {
|
|
|
504
662
|
next: () => {
|
|
505
663
|
const v = onboardingView();
|
|
506
664
|
if (v?.type !== "step") return;
|
|
665
|
+
if (v.step.kind === "question") {
|
|
666
|
+
const q = v.step.question;
|
|
667
|
+
const a = drafts.get(v.step.id) ?? (q ? answers.get(q.key) : void 0);
|
|
668
|
+
if (!q || !answerOk(q, a)) return;
|
|
669
|
+
answerStep(v.flow, v.step, a);
|
|
670
|
+
emit();
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
507
673
|
markDone(prog(v.flow.id), v.step.id);
|
|
508
674
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "completed" });
|
|
675
|
+
celebrate(v.flow);
|
|
509
676
|
save();
|
|
510
677
|
emit();
|
|
678
|
+
const url = v.step.kind === "modal" ? safeUrl(v.step.url) : void 0;
|
|
679
|
+
if (url) env.openUrl?.(url);
|
|
511
680
|
},
|
|
512
681
|
check: (stepId) => {
|
|
513
682
|
const v = onboardingView();
|
|
@@ -516,6 +685,7 @@ var createFlows = (env) => {
|
|
|
516
685
|
if (!item || item.done) return;
|
|
517
686
|
markDone(prog(v.flow.id), stepId);
|
|
518
687
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
688
|
+
celebrate(v.flow);
|
|
519
689
|
save();
|
|
520
690
|
emit();
|
|
521
691
|
},
|
|
@@ -524,11 +694,120 @@ var createFlows = (env) => {
|
|
|
524
694
|
if (!v || v.type !== "step" && v.type !== "checklist") return;
|
|
525
695
|
prog(v.flow.id).dismissed = true;
|
|
526
696
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, ...v.type === "step" ? { step: v.step.id } : {}, action: "dismissed" });
|
|
527
|
-
active = null;
|
|
697
|
+
active = returnTo && returnTo.flow !== v.flow.id && flowById(returnTo.flow) ? returnTo.flow : null;
|
|
698
|
+
returnTo = null;
|
|
699
|
+
save();
|
|
700
|
+
emit();
|
|
701
|
+
},
|
|
702
|
+
startTour: (stepId) => {
|
|
703
|
+
const v = onboardingView();
|
|
704
|
+
if (v?.type !== "checklist") return false;
|
|
705
|
+
const target = v.items.find((i) => i.step.id === stepId)?.target;
|
|
706
|
+
if (!target) return false;
|
|
707
|
+
openItem(v.flow, stepId, target);
|
|
708
|
+
return true;
|
|
709
|
+
},
|
|
710
|
+
open: (stepId) => {
|
|
711
|
+
const v = onboardingView();
|
|
712
|
+
if (v?.type !== "checklist") return false;
|
|
713
|
+
const it = v.items.find((i) => i.step.id === stepId);
|
|
714
|
+
const o = it?.opens;
|
|
715
|
+
if (!it || !o) return false;
|
|
716
|
+
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "opened", opens: o.kind });
|
|
717
|
+
if ((o.kind === "tour" || o.kind === "modal") && it.target) {
|
|
718
|
+
openItem(v.flow, stepId, it.target);
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
if (!it.done && !it.step.event) {
|
|
722
|
+
markDone(prog(v.flow.id), stepId);
|
|
723
|
+
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
724
|
+
celebrate(v.flow);
|
|
725
|
+
}
|
|
726
|
+
save();
|
|
727
|
+
emit();
|
|
728
|
+
if (o.kind === "page") env.navigate?.(o.target.trim());
|
|
729
|
+
else env.task?.(stepId, v.flow);
|
|
730
|
+
return true;
|
|
731
|
+
},
|
|
732
|
+
answer: (value) => {
|
|
733
|
+
const v = onboardingView();
|
|
734
|
+
if (v?.type !== "step" || v.step.kind !== "question") return;
|
|
735
|
+
drafts.set(v.step.id, String(value).slice(0, 500));
|
|
736
|
+
emit();
|
|
737
|
+
},
|
|
738
|
+
back: () => {
|
|
739
|
+
const v = onboardingView();
|
|
740
|
+
if (v?.type !== "step" || v.step.kind !== "question" || !v.back) return;
|
|
741
|
+
const line = stepsIn(nodesOf(v.flow));
|
|
742
|
+
const at = line.findIndex((s) => s.id === v.step.id);
|
|
743
|
+
const p = prog(v.flow.id);
|
|
744
|
+
for (let i = at - 1; i >= 0; i--)
|
|
745
|
+
if (p.done.has(line[i].id)) {
|
|
746
|
+
p.done.delete(line[i].id);
|
|
747
|
+
p.at.delete(line[i].id);
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
528
750
|
save();
|
|
529
751
|
emit();
|
|
752
|
+
},
|
|
753
|
+
item: (id) => {
|
|
754
|
+
const f = flowById(id);
|
|
755
|
+
if (!f) return null;
|
|
756
|
+
const p = progress.get(f.id);
|
|
757
|
+
const steps = stepsIn(nodesOf(f)).map((s) => {
|
|
758
|
+
const a = s.question ? answers.get(s.question.key) : void 0;
|
|
759
|
+
return { ...s, done: !!p?.done.has(s.id), ...a !== void 0 ? { answer: a } : {} };
|
|
760
|
+
});
|
|
761
|
+
const done = steps.length > 0 && steps.every((s) => s.done);
|
|
762
|
+
const dismissed = !!p?.dismissed;
|
|
763
|
+
return { item: f, steps, done, dismissed, eligible: !done && !dismissed && allowed(f) && due(f) };
|
|
764
|
+
},
|
|
765
|
+
seen: (id) => {
|
|
766
|
+
const f = flowById(id);
|
|
767
|
+
if (!f || f.shownBy !== "code" || !known) return;
|
|
768
|
+
if (!shown.has(`f:${f.id}`)) {
|
|
769
|
+
shown.add(`f:${f.id}`);
|
|
770
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, action: "started" });
|
|
771
|
+
}
|
|
772
|
+
const p = progress.get(f.id);
|
|
773
|
+
for (const s of stepsIn(nodesOf(f)))
|
|
774
|
+
if (!p?.done.has(s.id) && !shown.has(`s:${s.id}`)) {
|
|
775
|
+
shown.add(`s:${s.id}`);
|
|
776
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, step: s.id, kind: s.kind, action: "shown" });
|
|
777
|
+
if (s.kind !== "checklist") break;
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
complete: (id, stepId) => {
|
|
781
|
+
const f = flowById(id);
|
|
782
|
+
const s = f && stepsIn(nodesOf(f)).find((x) => x.id === stepId);
|
|
783
|
+
if (!f || !s || s.kind === "question") return;
|
|
784
|
+
const p = prog(f.id);
|
|
785
|
+
if (p.done.has(s.id)) return;
|
|
786
|
+
markDone(p, s.id);
|
|
787
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, step: s.id, kind: s.kind, action: "completed" });
|
|
788
|
+
ended(f);
|
|
789
|
+
},
|
|
790
|
+
dismissItem: (id) => {
|
|
791
|
+
const f = flowById(id);
|
|
792
|
+
if (!f) return;
|
|
793
|
+
const p = prog(f.id);
|
|
794
|
+
if (p.dismissed) return;
|
|
795
|
+
p.dismissed = true;
|
|
796
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, action: "dismissed" });
|
|
797
|
+
if (active === f.id) active = null;
|
|
798
|
+
ended(f);
|
|
799
|
+
},
|
|
800
|
+
answerItem: (id, question, value) => {
|
|
801
|
+
const f = flowById(id);
|
|
802
|
+
const s = f && stepsIn(nodesOf(f)).find((x) => x.kind === "question" && (x.id === question || x.question?.key === question));
|
|
803
|
+
if (!f || !s?.question || !answerOk(s.question, value)) return;
|
|
804
|
+
answerStep(f, s, value);
|
|
805
|
+
ended(f);
|
|
530
806
|
}
|
|
531
807
|
},
|
|
808
|
+
finale: () => finaleNow,
|
|
809
|
+
accent: () => config?.onboardingAccent,
|
|
810
|
+
answers: () => Object.fromEntries(answers),
|
|
532
811
|
message: {
|
|
533
812
|
click: () => {
|
|
534
813
|
const v = view();
|
|
@@ -551,24 +830,36 @@ var createFlows = (env) => {
|
|
|
551
830
|
return controller;
|
|
552
831
|
};
|
|
553
832
|
export {
|
|
833
|
+
AFTER_PREFIX,
|
|
554
834
|
CANCEL_EVENT,
|
|
835
|
+
FROM_CHECKLIST,
|
|
836
|
+
FROM_CODE,
|
|
555
837
|
INAPP_EVENT,
|
|
838
|
+
NEEDS_NEWER,
|
|
556
839
|
ONBOARDING_EVENT,
|
|
557
840
|
PLAIN_CANCEL,
|
|
558
841
|
REVIEW_EVENT,
|
|
842
|
+
afterOf,
|
|
843
|
+
answerLabel,
|
|
844
|
+
answerOk,
|
|
559
845
|
createFlows,
|
|
560
846
|
discounted,
|
|
561
847
|
eventSlug,
|
|
848
|
+
isPageTrigger,
|
|
562
849
|
matchesTrigger,
|
|
850
|
+
mediaOf,
|
|
851
|
+
momentOf,
|
|
563
852
|
money,
|
|
564
853
|
monthsSince,
|
|
565
854
|
nodesOf,
|
|
566
855
|
offerButton,
|
|
856
|
+
opensOf,
|
|
567
857
|
pageMatches,
|
|
568
858
|
ruleMatches,
|
|
569
859
|
runId,
|
|
570
860
|
safeUrl,
|
|
571
861
|
startsOnLoad,
|
|
862
|
+
videoEmbed,
|
|
572
863
|
waitMs
|
|
573
864
|
};
|
|
574
865
|
//# sourceMappingURL=flows.js.map
|