@mrrocket/sdk 0.17.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 +7 -1
- package/dist/browser/mrrocket-flows.js +9 -2
- package/dist/browser/mrrocket-messenger.js +3 -3
- 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 +105 -6
- 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 +159 -7
- package/dist/flows.js +240 -28
- 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 +5 -0
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.js +78 -53
- 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 +177 -15
- package/dist/react-native/index.d.ts +177 -15
- package/dist/react-native/index.js +776 -270
- package/dist/react-native/index.js.map +1 -1
- package/package.json +1 -1
package/dist/flows.js
CHANGED
|
@@ -24,7 +24,22 @@ var matchesTrigger = (trigger, event) => {
|
|
|
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
25
|
var FROM_CHECKLIST = "From a checklist";
|
|
26
26
|
var isPageTrigger = (trigger) => trigger.trim().startsWith("/");
|
|
27
|
-
var
|
|
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();
|
|
28
43
|
var videoEmbed = (url) => {
|
|
29
44
|
const u = (url ?? "").trim();
|
|
30
45
|
if (!/^https?:\/\//i.test(u)) return null;
|
|
@@ -90,7 +105,12 @@ var createFlows = (env) => {
|
|
|
90
105
|
const now = () => env.now?.() ?? Date.now();
|
|
91
106
|
let timer = null;
|
|
92
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;
|
|
93
112
|
const flows = () => config?.onboarding ?? [];
|
|
113
|
+
const drawn = () => flows().filter((f) => f.shownBy !== "code");
|
|
94
114
|
const flowById = (id) => id ? flows().find((f) => f.id === id) : void 0;
|
|
95
115
|
const prog = (id) => {
|
|
96
116
|
let p = progress.get(id);
|
|
@@ -164,6 +184,14 @@ var createFlows = (env) => {
|
|
|
164
184
|
};
|
|
165
185
|
const keyOf = (pid) => `${PROGRESS_KEY}:${pid ?? "visitor"}`;
|
|
166
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
|
+
};
|
|
167
195
|
const save = () => {
|
|
168
196
|
dirty = false;
|
|
169
197
|
const store = env.storage?.();
|
|
@@ -179,6 +207,7 @@ var createFlows = (env) => {
|
|
|
179
207
|
};
|
|
180
208
|
try {
|
|
181
209
|
store.set(keyOf(env.personId()), JSON.stringify(out));
|
|
210
|
+
if (answers.size) store.set(answersKeyOf(env.personId()), JSON.stringify(Object.fromEntries(answers)));
|
|
182
211
|
if (seenEvents.size) store.set(eventsKeyOf(env.personId()), JSON.stringify([...seenEvents].slice(-200)));
|
|
183
212
|
} catch {
|
|
184
213
|
}
|
|
@@ -231,8 +260,17 @@ var createFlows = (env) => {
|
|
|
231
260
|
type: "checklist",
|
|
232
261
|
flow,
|
|
233
262
|
items: items.map((s) => {
|
|
234
|
-
const
|
|
235
|
-
|
|
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
|
+
};
|
|
236
274
|
})
|
|
237
275
|
};
|
|
238
276
|
}
|
|
@@ -243,7 +281,16 @@ var createFlows = (env) => {
|
|
|
243
281
|
const rest = line.slice(index + 1);
|
|
244
282
|
const fork = rest.findIndex((n) => n.kind === "condition");
|
|
245
283
|
const ahead = (fork < 0 ? rest : rest.slice(0, fork)).filter(isStep).length;
|
|
246
|
-
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
|
+
};
|
|
247
294
|
};
|
|
248
295
|
const view = () => {
|
|
249
296
|
if (cancel) {
|
|
@@ -270,23 +317,25 @@ var createFlows = (env) => {
|
|
|
270
317
|
if (ob) return ob;
|
|
271
318
|
if (active && !holding) {
|
|
272
319
|
const back = returnTo;
|
|
273
|
-
const
|
|
320
|
+
const ended2 = active;
|
|
274
321
|
returnTo = null;
|
|
275
322
|
active = null;
|
|
276
323
|
const list = back ? flowById(back.flow) : void 0;
|
|
277
324
|
if (back && list) {
|
|
278
325
|
const item = stepsIn(nodesOf(list)).find((s) => s.id === back.step);
|
|
279
326
|
const p = prog(list.id);
|
|
280
|
-
if (item && !item.event && !progress.get(
|
|
327
|
+
if (item && !item.event && !progress.get(ended2)?.dismissed && !p.done.has(item.id)) {
|
|
281
328
|
markDone(p, item.id);
|
|
282
329
|
record({ flow: list.id, step: item.id, kind: "checklist", action: "completed" });
|
|
330
|
+
celebrate(list);
|
|
283
331
|
}
|
|
284
332
|
active = list.id;
|
|
285
333
|
const again = onboardingView();
|
|
286
334
|
if (again) return again;
|
|
287
335
|
if (!holding) active = null;
|
|
288
336
|
} else if (known) {
|
|
289
|
-
const
|
|
337
|
+
const was = flowById(ended2);
|
|
338
|
+
const after = was ? momentOf(was) : void 0;
|
|
290
339
|
Promise.resolve().then(() => autoStart(after));
|
|
291
340
|
}
|
|
292
341
|
}
|
|
@@ -314,22 +363,64 @@ var createFlows = (env) => {
|
|
|
314
363
|
emit();
|
|
315
364
|
return true;
|
|
316
365
|
};
|
|
317
|
-
const allowed = (f) => f.audience !== "signed_in" || !!env.personId();
|
|
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
|
+
};
|
|
318
381
|
const autoStart = (after) => {
|
|
319
382
|
if (!auto || active || !known) return;
|
|
320
383
|
if (!env.personId() && !env.storage?.()) return;
|
|
321
384
|
const path = env.path?.();
|
|
322
385
|
const same = after && !manual(after) ? eventSlug(after) : "";
|
|
323
|
-
const next =
|
|
324
|
-
(f) => (isPageTrigger(f
|
|
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)
|
|
325
388
|
);
|
|
326
389
|
if (next) start(next);
|
|
327
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
|
+
};
|
|
328
417
|
const refresh = () => {
|
|
329
418
|
const pid = env.personId();
|
|
330
419
|
if (progressFor !== null && progressFor !== pid) {
|
|
331
420
|
progress.clear();
|
|
332
421
|
seenEvents.clear();
|
|
422
|
+
answers.clear();
|
|
423
|
+
drafts.clear();
|
|
333
424
|
handled.clear();
|
|
334
425
|
active = null;
|
|
335
426
|
returnTo = null;
|
|
@@ -346,6 +437,10 @@ var createFlows = (env) => {
|
|
|
346
437
|
if (seen) {
|
|
347
438
|
for (const e of JSON.parse(seen)) if (typeof e === "string") seenEvents.add(e);
|
|
348
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
|
+
}
|
|
349
444
|
} catch {
|
|
350
445
|
}
|
|
351
446
|
}
|
|
@@ -356,6 +451,7 @@ var createFlows = (env) => {
|
|
|
356
451
|
if (state && env.personId() === pid) {
|
|
357
452
|
merge(state.onboarding);
|
|
358
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);
|
|
359
455
|
messages = (state.messages ?? []).filter((m) => m && m.id && m.title);
|
|
360
456
|
}
|
|
361
457
|
}
|
|
@@ -449,27 +545,33 @@ var createFlows = (env) => {
|
|
|
449
545
|
if (fresh) seenEvents.add(slug);
|
|
450
546
|
const flow = flowById(active);
|
|
451
547
|
let ticked = false;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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)))
|
|
455
553
|
if (s.kind === "checklist" && s.event && !p.done.has(s.id) && matchesTrigger(s.event, name)) {
|
|
456
554
|
markDone(p, s.id);
|
|
457
|
-
|
|
458
|
-
env.track(ONBOARDING_EVENT, { flow:
|
|
555
|
+
here = true;
|
|
556
|
+
env.track(ONBOARDING_EVENT, { flow: l.id, step: s.id, kind: s.kind, action: "completed" });
|
|
459
557
|
}
|
|
558
|
+
if (here) {
|
|
559
|
+
ticked = true;
|
|
560
|
+
celebrate(l);
|
|
561
|
+
}
|
|
460
562
|
}
|
|
461
|
-
if (ticked || fresh && flow) {
|
|
563
|
+
if (ticked || fresh && (flow || lists.length)) {
|
|
462
564
|
save();
|
|
463
565
|
emit();
|
|
464
566
|
} else if (fresh) save();
|
|
465
567
|
if (!auto || !env.personId() && !env.storage?.()) return;
|
|
466
|
-
const next =
|
|
568
|
+
const next = drawn().find((f) => nodesOf(f).length && !manual(momentOf(f)) && matchesTrigger(momentOf(f), name) && allowed(f) && !finished(f));
|
|
467
569
|
if (next) start(next);
|
|
468
570
|
},
|
|
469
571
|
openCancelFlow,
|
|
470
572
|
startOnboarding: (id) => {
|
|
471
|
-
const f = id ? flowById(id) :
|
|
472
|
-
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;
|
|
473
575
|
const p = prog(f.id);
|
|
474
576
|
p.dismissed = false;
|
|
475
577
|
return start(f);
|
|
@@ -560,8 +662,17 @@ var createFlows = (env) => {
|
|
|
560
662
|
next: () => {
|
|
561
663
|
const v = onboardingView();
|
|
562
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
|
+
}
|
|
563
673
|
markDone(prog(v.flow.id), v.step.id);
|
|
564
674
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "completed" });
|
|
675
|
+
celebrate(v.flow);
|
|
565
676
|
save();
|
|
566
677
|
emit();
|
|
567
678
|
const url = v.step.kind === "modal" ? safeUrl(v.step.url) : void 0;
|
|
@@ -574,6 +685,7 @@ var createFlows = (env) => {
|
|
|
574
685
|
if (!item || item.done) return;
|
|
575
686
|
markDone(prog(v.flow.id), stepId);
|
|
576
687
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
688
|
+
celebrate(v.flow);
|
|
577
689
|
save();
|
|
578
690
|
emit();
|
|
579
691
|
},
|
|
@@ -590,20 +702,112 @@ var createFlows = (env) => {
|
|
|
590
702
|
startTour: (stepId) => {
|
|
591
703
|
const v = onboardingView();
|
|
592
704
|
if (v?.type !== "checklist") return false;
|
|
593
|
-
const
|
|
594
|
-
if (!
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
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
|
+
}
|
|
602
726
|
save();
|
|
603
727
|
emit();
|
|
728
|
+
if (o.kind === "page") env.navigate?.(o.target.trim());
|
|
729
|
+
else env.task?.(stepId, v.flow);
|
|
604
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
|
+
}
|
|
750
|
+
save();
|
|
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);
|
|
605
806
|
}
|
|
606
807
|
},
|
|
808
|
+
finale: () => finaleNow,
|
|
809
|
+
accent: () => config?.onboardingAccent,
|
|
810
|
+
answers: () => Object.fromEntries(answers),
|
|
607
811
|
message: {
|
|
608
812
|
click: () => {
|
|
609
813
|
const v = view();
|
|
@@ -626,22 +830,30 @@ var createFlows = (env) => {
|
|
|
626
830
|
return controller;
|
|
627
831
|
};
|
|
628
832
|
export {
|
|
833
|
+
AFTER_PREFIX,
|
|
629
834
|
CANCEL_EVENT,
|
|
630
835
|
FROM_CHECKLIST,
|
|
836
|
+
FROM_CODE,
|
|
631
837
|
INAPP_EVENT,
|
|
838
|
+
NEEDS_NEWER,
|
|
632
839
|
ONBOARDING_EVENT,
|
|
633
840
|
PLAIN_CANCEL,
|
|
634
841
|
REVIEW_EVENT,
|
|
842
|
+
afterOf,
|
|
843
|
+
answerLabel,
|
|
844
|
+
answerOk,
|
|
635
845
|
createFlows,
|
|
636
846
|
discounted,
|
|
637
847
|
eventSlug,
|
|
638
848
|
isPageTrigger,
|
|
639
849
|
matchesTrigger,
|
|
640
850
|
mediaOf,
|
|
851
|
+
momentOf,
|
|
641
852
|
money,
|
|
642
853
|
monthsSince,
|
|
643
854
|
nodesOf,
|
|
644
855
|
offerButton,
|
|
856
|
+
opensOf,
|
|
645
857
|
pageMatches,
|
|
646
858
|
ruleMatches,
|
|
647
859
|
runId,
|