@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
|
@@ -48,10 +48,10 @@ __export(native_exports, {
|
|
|
48
48
|
useVariant: () => useVariant
|
|
49
49
|
});
|
|
50
50
|
module.exports = __toCommonJS(native_exports);
|
|
51
|
-
var
|
|
51
|
+
var import_react4 = require("react");
|
|
52
52
|
|
|
53
53
|
// src/core.ts
|
|
54
|
-
var SDK_VERSION = "0.
|
|
54
|
+
var SDK_VERSION = "0.18.0";
|
|
55
55
|
var propOf = (person, name) => {
|
|
56
56
|
const want = name.trim().toLowerCase();
|
|
57
57
|
for (const [k, v] of Object.entries(person)) if (k.toLowerCase() === want) return v;
|
|
@@ -173,6 +173,46 @@ var textChanges = (config, distinctId, preview) => {
|
|
|
173
173
|
};
|
|
174
174
|
var newDistinctId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `ck_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
|
|
175
175
|
|
|
176
|
+
// src/onboarding-state.ts
|
|
177
|
+
var import_react = require("react");
|
|
178
|
+
var none = [];
|
|
179
|
+
var useOnboardingItem = (flows, id, start) => {
|
|
180
|
+
const [state, setState] = (0, import_react.useState)(() => flows && id ? flows.onboarding.item(id) : null);
|
|
181
|
+
(0, import_react.useEffect)(() => {
|
|
182
|
+
if (!flows || !id) {
|
|
183
|
+
setState(null);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const up = () => {
|
|
187
|
+
const s = flows.onboarding.item(id);
|
|
188
|
+
setState(s);
|
|
189
|
+
if (s && !s.done && !s.dismissed) flows.onboarding.seen(id);
|
|
190
|
+
};
|
|
191
|
+
up();
|
|
192
|
+
return flows.subscribe(up);
|
|
193
|
+
}, [flows, id]);
|
|
194
|
+
return (0, import_react.useMemo)(
|
|
195
|
+
() => ({
|
|
196
|
+
item: state?.item ?? null,
|
|
197
|
+
steps: state?.steps ?? none,
|
|
198
|
+
done: !!state?.done,
|
|
199
|
+
dismissed: !!state?.dismissed,
|
|
200
|
+
eligible: !!state?.eligible,
|
|
201
|
+
complete: (stepId) => {
|
|
202
|
+
if (flows && id) flows.onboarding.complete(id, stepId);
|
|
203
|
+
},
|
|
204
|
+
dismiss: () => {
|
|
205
|
+
if (flows && id) flows.onboarding.dismissItem(id);
|
|
206
|
+
},
|
|
207
|
+
answer: (question, value) => {
|
|
208
|
+
if (flows && id) flows.onboarding.answerItem(id, question, value);
|
|
209
|
+
},
|
|
210
|
+
start
|
|
211
|
+
}),
|
|
212
|
+
[state, flows, id, start]
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
176
216
|
// src/identity.ts
|
|
177
217
|
var UNSIGNED_HELP = "401: sign the user id on your server with userHash(id) from @mrrocket/sdk/next/server and pass identify(id, props, { hash }).";
|
|
178
218
|
var warnUnsigned = (status, log = (m) => console.warn(m)) => {
|
|
@@ -242,9 +282,9 @@ var call = async (url, init, signal) => {
|
|
|
242
282
|
};
|
|
243
283
|
var createApi = (c) => {
|
|
244
284
|
const base = `${c.host}/api/sdk`;
|
|
245
|
-
const
|
|
285
|
+
const who2 = { key: c.apiKey, distinctId: c.distinctId, user: c.user, userHash: c.userHash };
|
|
246
286
|
const me = { key: c.apiKey, distinctId: c.distinctId, userHash: c.userHash };
|
|
247
|
-
const post = (path, body, signal) => call(`${base}${path}`, { method: "POST", body: JSON.stringify({ ...
|
|
287
|
+
const post = (path, body, signal) => call(`${base}${path}`, { method: "POST", body: JSON.stringify({ ...who2, ...body }) }, signal);
|
|
248
288
|
return {
|
|
249
289
|
list: (o, signal) => call(`${base}/feedback?${qs({ ...me, board: o.board, sort: o.sort, q: o.q })}`, void 0, signal),
|
|
250
290
|
post: (id, signal) => call(`${base}/feedback/${encodeURIComponent(id)}?${qs(me)}`, void 0, signal),
|
|
@@ -358,6 +398,39 @@ var matchesTrigger = (trigger, event) => {
|
|
|
358
398
|
return t === e || SIGNUP.has(t) && SIGNUP.has(e);
|
|
359
399
|
};
|
|
360
400
|
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());
|
|
401
|
+
var isPageTrigger = (trigger) => trigger.trim().startsWith("/");
|
|
402
|
+
var NEEDS_NEWER = "Needs tracking code 0.18.0";
|
|
403
|
+
var momentOf = (f) => f.when ?? f.trigger;
|
|
404
|
+
var manual = (trigger) => eventSlug(trigger) === "from_a_checklist" || eventSlug(trigger) === "from_your_code" || eventSlug(trigger) === eventSlug(NEEDS_NEWER);
|
|
405
|
+
var AFTER_PREFIX = "after:";
|
|
406
|
+
var afterOf = (trigger) => {
|
|
407
|
+
const t = (trigger ?? "").trim();
|
|
408
|
+
return t.toLowerCase().startsWith(AFTER_PREFIX) ? t.slice(AFTER_PREFIX.length).trim() || null : null;
|
|
409
|
+
};
|
|
410
|
+
var opensOf = (step) => step.opens ?? (step.startsTour ? { kind: "tour", id: step.startsTour } : void 0);
|
|
411
|
+
var answerOk = (q, value) => {
|
|
412
|
+
if (!q || value == null) return false;
|
|
413
|
+
if (q.type === "choice") return (q.options ?? []).some((o) => o.id === value);
|
|
414
|
+
return value.trim().length > 0 && value.length <= 500;
|
|
415
|
+
};
|
|
416
|
+
var answerLabel = (q, value) => q?.type === "choice" ? q.options?.find((o) => o.id === value)?.label ?? value : value.trim();
|
|
417
|
+
var videoEmbed = (url) => {
|
|
418
|
+
const u = (url ?? "").trim();
|
|
419
|
+
if (!/^https?:\/\//i.test(u)) return null;
|
|
420
|
+
let m = u.match(/^https?:\/\/(?:www\.|m\.)?(?:youtube\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/|live\/)|youtu\.be\/|youtube-nocookie\.com\/embed\/)([\w-]{6,20})/i);
|
|
421
|
+
if (m) return { kind: "iframe", src: `https://www.youtube-nocookie.com/embed/${m[1]}?rel=0` };
|
|
422
|
+
m = u.match(/^https?:\/\/(?:www\.|player\.)?vimeo\.com\/(?:video\/)?(\d{4,12})/i);
|
|
423
|
+
if (m) return { kind: "iframe", src: `https://player.vimeo.com/video/${m[1]}?dnt=1` };
|
|
424
|
+
m = u.match(/^https?:\/\/(?:www\.)?loom\.com\/(?:share|embed)\/([\w-]{8,64})/i);
|
|
425
|
+
if (m) return { kind: "iframe", src: `https://www.loom.com/embed/${m[1]}` };
|
|
426
|
+
if (/\.(mp4|webm|mov|m4v)(\?|#|$)/i.test(u) || /\/media\/uploads\//.test(u)) return { kind: "file", src: u };
|
|
427
|
+
return null;
|
|
428
|
+
};
|
|
429
|
+
var mediaOf = (step) => {
|
|
430
|
+
const m = step.media;
|
|
431
|
+
if (!m || m.kind !== "image" && m.kind !== "video" || !/^https?:\/\//i.test(m.url ?? "")) return void 0;
|
|
432
|
+
return m.kind === "video" && !videoEmbed(m.url) ? void 0 : m;
|
|
433
|
+
};
|
|
361
434
|
var runId = () => `cf_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
|
|
362
435
|
var discounted = (amount, percent) => Math.round(amount * (1 - percent / 100) * 100) / 100;
|
|
363
436
|
var money = (amount, currency) => {
|
|
@@ -405,7 +478,13 @@ var createFlows = (env) => {
|
|
|
405
478
|
const seenEvents = /* @__PURE__ */ new Set();
|
|
406
479
|
const now = () => env.now?.() ?? Date.now();
|
|
407
480
|
let timer = null;
|
|
481
|
+
let returnTo = null;
|
|
482
|
+
const answers = /* @__PURE__ */ new Map();
|
|
483
|
+
const drafts = /* @__PURE__ */ new Map();
|
|
484
|
+
const celebrated = /* @__PURE__ */ new Set();
|
|
485
|
+
let finaleNow = null;
|
|
408
486
|
const flows = () => config?.onboarding ?? [];
|
|
487
|
+
const drawn = () => flows().filter((f) => f.shownBy !== "code");
|
|
409
488
|
const flowById = (id) => id ? flows().find((f) => f.id === id) : void 0;
|
|
410
489
|
const prog = (id) => {
|
|
411
490
|
let p = progress.get(id);
|
|
@@ -479,6 +558,14 @@ var createFlows = (env) => {
|
|
|
479
558
|
};
|
|
480
559
|
const keyOf = (pid) => `${PROGRESS_KEY}:${pid ?? "visitor"}`;
|
|
481
560
|
const eventsKeyOf = (pid) => `${PROGRESS_KEY}:events:${pid ?? "visitor"}`;
|
|
561
|
+
const answersKeyOf = (pid) => `${PROGRESS_KEY}:answers:${pid ?? "visitor"}`;
|
|
562
|
+
const celebrate = (f) => {
|
|
563
|
+
if (!f.finish || f.finish === "none" || f.shownBy === "code" || celebrated.has(f.id)) return;
|
|
564
|
+
const p = progress.get(f.id);
|
|
565
|
+
if (!p || p.dismissed || walkLine(f, nodesOf(f), p, false).at !== "end") return;
|
|
566
|
+
celebrated.add(f.id);
|
|
567
|
+
finaleNow = { kind: f.finish, key: `${f.id}:${now()}` };
|
|
568
|
+
};
|
|
482
569
|
const save = () => {
|
|
483
570
|
dirty = false;
|
|
484
571
|
const store = env.storage?.();
|
|
@@ -494,6 +581,7 @@ var createFlows = (env) => {
|
|
|
494
581
|
};
|
|
495
582
|
try {
|
|
496
583
|
store.set(keyOf(env.personId()), JSON.stringify(out));
|
|
584
|
+
if (answers.size) store.set(answersKeyOf(env.personId()), JSON.stringify(Object.fromEntries(answers)));
|
|
497
585
|
if (seenEvents.size) store.set(eventsKeyOf(env.personId()), JSON.stringify([...seenEvents].slice(-200)));
|
|
498
586
|
} catch {
|
|
499
587
|
}
|
|
@@ -542,7 +630,23 @@ var createFlows = (env) => {
|
|
|
542
630
|
shown.add(`s:${i.id}`);
|
|
543
631
|
env.track(ONBOARDING_EVENT, { flow: flow.id, step: i.id, kind: "checklist", action: "shown" });
|
|
544
632
|
}
|
|
545
|
-
return {
|
|
633
|
+
return {
|
|
634
|
+
type: "checklist",
|
|
635
|
+
flow,
|
|
636
|
+
items: items.map((s) => {
|
|
637
|
+
const o = opensOf(s);
|
|
638
|
+
const t = o && (o.kind === "tour" || o.kind === "modal") && o.id !== flow.id ? flowById(o.id) : void 0;
|
|
639
|
+
const target = t && t.shownBy !== "code" && nodesOf(t).length ? t : void 0;
|
|
640
|
+
const opens = o && (o.kind === "page" ? !!o.target.trim() : o.kind === "code" || !!target) ? o : void 0;
|
|
641
|
+
return {
|
|
642
|
+
step: s,
|
|
643
|
+
done: p.done.has(s.id),
|
|
644
|
+
...target && o?.kind === "tour" ? { tour: target } : {},
|
|
645
|
+
...opens ? { opens } : {},
|
|
646
|
+
...target ? { target } : {}
|
|
647
|
+
};
|
|
648
|
+
})
|
|
649
|
+
};
|
|
546
650
|
}
|
|
547
651
|
if (!shown.has(`s:${step.id}`)) {
|
|
548
652
|
shown.add(`s:${step.id}`);
|
|
@@ -551,7 +655,16 @@ var createFlows = (env) => {
|
|
|
551
655
|
const rest = line.slice(index + 1);
|
|
552
656
|
const fork = rest.findIndex((n) => n.kind === "condition");
|
|
553
657
|
const ahead = (fork < 0 ? rest : rest.slice(0, fork)).filter(isStep).length;
|
|
554
|
-
return {
|
|
658
|
+
return {
|
|
659
|
+
type: "step",
|
|
660
|
+
flow,
|
|
661
|
+
step,
|
|
662
|
+
index: w.before,
|
|
663
|
+
total: w.before + 1 + ahead,
|
|
664
|
+
last: !ahead && fork < 0,
|
|
665
|
+
// 0.18.0: a question's answer so far, and whether there is one before it to go back to.
|
|
666
|
+
...step.kind === "question" ? { answer: drafts.get(step.id) ?? (step.question ? answers.get(step.question.key) : void 0), back: w.before > 0 } : {}
|
|
667
|
+
};
|
|
555
668
|
};
|
|
556
669
|
const view = () => {
|
|
557
670
|
if (cancel) {
|
|
@@ -576,7 +689,30 @@ var createFlows = (env) => {
|
|
|
576
689
|
}
|
|
577
690
|
const ob = onboardingView();
|
|
578
691
|
if (ob) return ob;
|
|
579
|
-
if (active && !holding)
|
|
692
|
+
if (active && !holding) {
|
|
693
|
+
const back = returnTo;
|
|
694
|
+
const ended2 = active;
|
|
695
|
+
returnTo = null;
|
|
696
|
+
active = null;
|
|
697
|
+
const list = back ? flowById(back.flow) : void 0;
|
|
698
|
+
if (back && list) {
|
|
699
|
+
const item = stepsIn(nodesOf(list)).find((s) => s.id === back.step);
|
|
700
|
+
const p = prog(list.id);
|
|
701
|
+
if (item && !item.event && !progress.get(ended2)?.dismissed && !p.done.has(item.id)) {
|
|
702
|
+
markDone(p, item.id);
|
|
703
|
+
record({ flow: list.id, step: item.id, kind: "checklist", action: "completed" });
|
|
704
|
+
celebrate(list);
|
|
705
|
+
}
|
|
706
|
+
active = list.id;
|
|
707
|
+
const again = onboardingView();
|
|
708
|
+
if (again) return again;
|
|
709
|
+
if (!holding) active = null;
|
|
710
|
+
} else if (known) {
|
|
711
|
+
const was = flowById(ended2);
|
|
712
|
+
const after = was ? momentOf(was) : void 0;
|
|
713
|
+
Promise.resolve().then(() => autoStart(after));
|
|
714
|
+
}
|
|
715
|
+
}
|
|
580
716
|
const m = messages.find((x) => !handled.has(x.id));
|
|
581
717
|
return m ? { type: "message", message: m } : null;
|
|
582
718
|
};
|
|
@@ -601,19 +737,67 @@ var createFlows = (env) => {
|
|
|
601
737
|
emit();
|
|
602
738
|
return true;
|
|
603
739
|
};
|
|
604
|
-
const
|
|
740
|
+
const allowed = (f) => f.audience === "answered" ? !!f.answered && answers.get(f.answered.question) === f.answered.option : f.audience !== "signed_in" || !!env.personId();
|
|
741
|
+
const predecessorEnded = (id) => {
|
|
742
|
+
const g = flowById(id);
|
|
743
|
+
return !g || finished(g);
|
|
744
|
+
};
|
|
745
|
+
const due = (f, trigger = momentOf(f)) => {
|
|
746
|
+
const path = env.path?.();
|
|
747
|
+
const pred = afterOf(trigger);
|
|
748
|
+
if (pred) return predecessorEnded(pred);
|
|
749
|
+
if (manual(trigger)) return false;
|
|
750
|
+
if (isPageTrigger(trigger)) return path !== void 0 && pageMatches(trigger, path);
|
|
751
|
+
if (startsOnLoad(trigger)) return true;
|
|
752
|
+
for (const e of seenEvents) if (matchesTrigger(trigger, e)) return true;
|
|
753
|
+
return false;
|
|
754
|
+
};
|
|
755
|
+
const autoStart = (after) => {
|
|
605
756
|
if (!auto || active || !known) return;
|
|
606
757
|
if (!env.personId() && !env.storage?.()) return;
|
|
607
|
-
const
|
|
758
|
+
const path = env.path?.();
|
|
759
|
+
const same2 = after && !manual(after) ? eventSlug(after) : "";
|
|
760
|
+
const next = drawn().find(
|
|
761
|
+
(f) => (afterOf(momentOf(f)) ? predecessorEnded(afterOf(momentOf(f))) : isPageTrigger(momentOf(f)) ? path !== void 0 && pageMatches(momentOf(f), path) : startsOnLoad(momentOf(f)) || !!same2 && eventSlug(momentOf(f)) === same2) && allowed(f) && nodesOf(f).length && !finished(f)
|
|
762
|
+
);
|
|
608
763
|
if (next) start(next);
|
|
609
764
|
};
|
|
765
|
+
const openItem = (list, stepId, target) => {
|
|
766
|
+
const p = prog(target.id);
|
|
767
|
+
p.done.clear();
|
|
768
|
+
p.at.clear();
|
|
769
|
+
p.dismissed = false;
|
|
770
|
+
returnTo = { flow: list.id, step: stepId };
|
|
771
|
+
active = target.id;
|
|
772
|
+
env.track(ONBOARDING_EVENT, { flow: target.id, action: "started", from: list.id });
|
|
773
|
+
save();
|
|
774
|
+
emit();
|
|
775
|
+
};
|
|
776
|
+
const answerStep = (flow, step, raw) => {
|
|
777
|
+
const q = step.question;
|
|
778
|
+
const value = q.type === "text" ? raw.trim().slice(0, 500) : raw;
|
|
779
|
+
answers.set(q.key, value);
|
|
780
|
+
drafts.delete(step.id);
|
|
781
|
+
markDone(prog(flow.id), step.id);
|
|
782
|
+
env.track(ONBOARDING_EVENT, { flow: flow.id, step: step.id, kind: "question", action: "completed", question: q.key, answer: value, label: answerLabel(q, value) });
|
|
783
|
+
celebrate(flow);
|
|
784
|
+
save();
|
|
785
|
+
};
|
|
786
|
+
const ended = (f) => {
|
|
787
|
+
save();
|
|
788
|
+
if (finished(f)) Promise.resolve().then(() => autoStart());
|
|
789
|
+
emit();
|
|
790
|
+
};
|
|
610
791
|
const refresh = () => {
|
|
611
792
|
const pid = env.personId();
|
|
612
793
|
if (progressFor !== null && progressFor !== pid) {
|
|
613
794
|
progress.clear();
|
|
614
795
|
seenEvents.clear();
|
|
796
|
+
answers.clear();
|
|
797
|
+
drafts.clear();
|
|
615
798
|
handled.clear();
|
|
616
799
|
active = null;
|
|
800
|
+
returnTo = null;
|
|
617
801
|
loadedFor = void 0;
|
|
618
802
|
}
|
|
619
803
|
progressFor = pid;
|
|
@@ -627,6 +811,10 @@ var createFlows = (env) => {
|
|
|
627
811
|
if (seen) {
|
|
628
812
|
for (const e of JSON.parse(seen)) if (typeof e === "string") seenEvents.add(e);
|
|
629
813
|
}
|
|
814
|
+
const said = await store.get(answersKeyOf(pid));
|
|
815
|
+
if (said) {
|
|
816
|
+
for (const [k, v] of Object.entries(JSON.parse(said))) if (typeof v === "string") answers.set(k, v);
|
|
817
|
+
}
|
|
630
818
|
} catch {
|
|
631
819
|
}
|
|
632
820
|
}
|
|
@@ -637,6 +825,7 @@ var createFlows = (env) => {
|
|
|
637
825
|
if (state && env.personId() === pid) {
|
|
638
826
|
merge(state.onboarding);
|
|
639
827
|
for (const e of state.events ?? []) if (typeof e === "string") seenEvents.add(eventSlug(e));
|
|
828
|
+
for (const [k, v] of Object.entries(state.answers ?? {})) if (typeof v === "string" && !answers.has(k)) answers.set(k, v);
|
|
640
829
|
messages = (state.messages ?? []).filter((m) => m && m.id && m.title);
|
|
641
830
|
}
|
|
642
831
|
}
|
|
@@ -652,9 +841,9 @@ var createFlows = (env) => {
|
|
|
652
841
|
};
|
|
653
842
|
const offerAt = (c) => c.round > 1 ? { round: 2 } : c.rule >= 0 ? { rule: c.rule } : {};
|
|
654
843
|
const toOffer = (c) => {
|
|
655
|
-
const
|
|
844
|
+
const who2 = { answer: c.answer, plan: c.options.plan, months: monthsSince(c.options.customerSince, env.now?.()) };
|
|
656
845
|
const rules = c.flow.rules?.[c.reason] ?? [];
|
|
657
|
-
c.rule = rules.findIndex((r) => ruleMatches(r,
|
|
846
|
+
c.rule = rules.findIndex((r) => ruleMatches(r, who2));
|
|
658
847
|
c.offer = c.rule < 0 ? c.flow.offers[c.reason] : rules[c.rule].offer ?? void 0;
|
|
659
848
|
c.round = 1;
|
|
660
849
|
c.screen = c.offer ? "offer" : "confirm";
|
|
@@ -723,33 +912,40 @@ var createFlows = (env) => {
|
|
|
723
912
|
},
|
|
724
913
|
refresh,
|
|
725
914
|
onEvent: (name) => {
|
|
915
|
+
if (name === "$pageview") autoStart();
|
|
726
916
|
if (!name || name.startsWith("$")) return;
|
|
727
917
|
const slug = eventSlug(name);
|
|
728
918
|
const fresh = !!slug && !seenEvents.has(slug);
|
|
729
919
|
if (fresh) seenEvents.add(slug);
|
|
730
920
|
const flow = flowById(active);
|
|
731
921
|
let ticked = false;
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
922
|
+
const lists = [...flow ? [flow] : [], ...flows().filter((f) => f.shownBy === "code" && f.id !== flow?.id)];
|
|
923
|
+
for (const l of lists) {
|
|
924
|
+
const p = prog(l.id);
|
|
925
|
+
let here = false;
|
|
926
|
+
for (const s of stepsIn(nodesOf(l)))
|
|
735
927
|
if (s.kind === "checklist" && s.event && !p.done.has(s.id) && matchesTrigger(s.event, name)) {
|
|
736
928
|
markDone(p, s.id);
|
|
737
|
-
|
|
738
|
-
env.track(ONBOARDING_EVENT, { flow:
|
|
929
|
+
here = true;
|
|
930
|
+
env.track(ONBOARDING_EVENT, { flow: l.id, step: s.id, kind: s.kind, action: "completed" });
|
|
739
931
|
}
|
|
932
|
+
if (here) {
|
|
933
|
+
ticked = true;
|
|
934
|
+
celebrate(l);
|
|
935
|
+
}
|
|
740
936
|
}
|
|
741
|
-
if (ticked || fresh && flow) {
|
|
937
|
+
if (ticked || fresh && (flow || lists.length)) {
|
|
742
938
|
save();
|
|
743
939
|
emit();
|
|
744
940
|
} else if (fresh) save();
|
|
745
941
|
if (!auto || !env.personId() && !env.storage?.()) return;
|
|
746
|
-
const next =
|
|
942
|
+
const next = drawn().find((f) => nodesOf(f).length && !manual(momentOf(f)) && matchesTrigger(momentOf(f), name) && allowed(f) && !finished(f));
|
|
747
943
|
if (next) start(next);
|
|
748
944
|
},
|
|
749
945
|
openCancelFlow,
|
|
750
946
|
startOnboarding: (id) => {
|
|
751
|
-
const f = id ? flowById(id) :
|
|
752
|
-
if (!f || !nodesOf(f).length) return false;
|
|
947
|
+
const f = id ? flowById(id) : drawn().find((x) => nodesOf(x).length && !manual(momentOf(x)) && !afterOf(momentOf(x)) && !finished(x));
|
|
948
|
+
if (!f || !nodesOf(f).length || f.shownBy === "code") return false;
|
|
753
949
|
const p = prog(f.id);
|
|
754
950
|
p.dismissed = false;
|
|
755
951
|
return start(f);
|
|
@@ -840,10 +1036,21 @@ var createFlows = (env) => {
|
|
|
840
1036
|
next: () => {
|
|
841
1037
|
const v = onboardingView();
|
|
842
1038
|
if (v?.type !== "step") return;
|
|
1039
|
+
if (v.step.kind === "question") {
|
|
1040
|
+
const q = v.step.question;
|
|
1041
|
+
const a = drafts.get(v.step.id) ?? (q ? answers.get(q.key) : void 0);
|
|
1042
|
+
if (!q || !answerOk(q, a)) return;
|
|
1043
|
+
answerStep(v.flow, v.step, a);
|
|
1044
|
+
emit();
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
843
1047
|
markDone(prog(v.flow.id), v.step.id);
|
|
844
1048
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: v.step.id, kind: v.step.kind, action: "completed" });
|
|
1049
|
+
celebrate(v.flow);
|
|
845
1050
|
save();
|
|
846
1051
|
emit();
|
|
1052
|
+
const url = v.step.kind === "modal" ? safeUrl(v.step.url) : void 0;
|
|
1053
|
+
if (url) env.openUrl?.(url);
|
|
847
1054
|
},
|
|
848
1055
|
check: (stepId) => {
|
|
849
1056
|
const v = onboardingView();
|
|
@@ -852,6 +1059,7 @@ var createFlows = (env) => {
|
|
|
852
1059
|
if (!item || item.done) return;
|
|
853
1060
|
markDone(prog(v.flow.id), stepId);
|
|
854
1061
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
1062
|
+
celebrate(v.flow);
|
|
855
1063
|
save();
|
|
856
1064
|
emit();
|
|
857
1065
|
},
|
|
@@ -860,11 +1068,120 @@ var createFlows = (env) => {
|
|
|
860
1068
|
if (!v || v.type !== "step" && v.type !== "checklist") return;
|
|
861
1069
|
prog(v.flow.id).dismissed = true;
|
|
862
1070
|
env.track(ONBOARDING_EVENT, { flow: v.flow.id, ...v.type === "step" ? { step: v.step.id } : {}, action: "dismissed" });
|
|
863
|
-
active = null;
|
|
1071
|
+
active = returnTo && returnTo.flow !== v.flow.id && flowById(returnTo.flow) ? returnTo.flow : null;
|
|
1072
|
+
returnTo = null;
|
|
1073
|
+
save();
|
|
1074
|
+
emit();
|
|
1075
|
+
},
|
|
1076
|
+
startTour: (stepId) => {
|
|
1077
|
+
const v = onboardingView();
|
|
1078
|
+
if (v?.type !== "checklist") return false;
|
|
1079
|
+
const target = v.items.find((i) => i.step.id === stepId)?.target;
|
|
1080
|
+
if (!target) return false;
|
|
1081
|
+
openItem(v.flow, stepId, target);
|
|
1082
|
+
return true;
|
|
1083
|
+
},
|
|
1084
|
+
open: (stepId) => {
|
|
1085
|
+
const v = onboardingView();
|
|
1086
|
+
if (v?.type !== "checklist") return false;
|
|
1087
|
+
const it = v.items.find((i) => i.step.id === stepId);
|
|
1088
|
+
const o = it?.opens;
|
|
1089
|
+
if (!it || !o) return false;
|
|
1090
|
+
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "opened", opens: o.kind });
|
|
1091
|
+
if ((o.kind === "tour" || o.kind === "modal") && it.target) {
|
|
1092
|
+
openItem(v.flow, stepId, it.target);
|
|
1093
|
+
return true;
|
|
1094
|
+
}
|
|
1095
|
+
if (!it.done && !it.step.event) {
|
|
1096
|
+
markDone(prog(v.flow.id), stepId);
|
|
1097
|
+
env.track(ONBOARDING_EVENT, { flow: v.flow.id, step: stepId, kind: "checklist", action: "completed" });
|
|
1098
|
+
celebrate(v.flow);
|
|
1099
|
+
}
|
|
864
1100
|
save();
|
|
865
1101
|
emit();
|
|
1102
|
+
if (o.kind === "page") env.navigate?.(o.target.trim());
|
|
1103
|
+
else env.task?.(stepId, v.flow);
|
|
1104
|
+
return true;
|
|
1105
|
+
},
|
|
1106
|
+
answer: (value) => {
|
|
1107
|
+
const v = onboardingView();
|
|
1108
|
+
if (v?.type !== "step" || v.step.kind !== "question") return;
|
|
1109
|
+
drafts.set(v.step.id, String(value).slice(0, 500));
|
|
1110
|
+
emit();
|
|
1111
|
+
},
|
|
1112
|
+
back: () => {
|
|
1113
|
+
const v = onboardingView();
|
|
1114
|
+
if (v?.type !== "step" || v.step.kind !== "question" || !v.back) return;
|
|
1115
|
+
const line = stepsIn(nodesOf(v.flow));
|
|
1116
|
+
const at = line.findIndex((s) => s.id === v.step.id);
|
|
1117
|
+
const p = prog(v.flow.id);
|
|
1118
|
+
for (let i = at - 1; i >= 0; i--)
|
|
1119
|
+
if (p.done.has(line[i].id)) {
|
|
1120
|
+
p.done.delete(line[i].id);
|
|
1121
|
+
p.at.delete(line[i].id);
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
save();
|
|
1125
|
+
emit();
|
|
1126
|
+
},
|
|
1127
|
+
item: (id) => {
|
|
1128
|
+
const f = flowById(id);
|
|
1129
|
+
if (!f) return null;
|
|
1130
|
+
const p = progress.get(f.id);
|
|
1131
|
+
const steps = stepsIn(nodesOf(f)).map((s) => {
|
|
1132
|
+
const a = s.question ? answers.get(s.question.key) : void 0;
|
|
1133
|
+
return { ...s, done: !!p?.done.has(s.id), ...a !== void 0 ? { answer: a } : {} };
|
|
1134
|
+
});
|
|
1135
|
+
const done = steps.length > 0 && steps.every((s) => s.done);
|
|
1136
|
+
const dismissed = !!p?.dismissed;
|
|
1137
|
+
return { item: f, steps, done, dismissed, eligible: !done && !dismissed && allowed(f) && due(f) };
|
|
1138
|
+
},
|
|
1139
|
+
seen: (id) => {
|
|
1140
|
+
const f = flowById(id);
|
|
1141
|
+
if (!f || f.shownBy !== "code" || !known) return;
|
|
1142
|
+
if (!shown.has(`f:${f.id}`)) {
|
|
1143
|
+
shown.add(`f:${f.id}`);
|
|
1144
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, action: "started" });
|
|
1145
|
+
}
|
|
1146
|
+
const p = progress.get(f.id);
|
|
1147
|
+
for (const s of stepsIn(nodesOf(f)))
|
|
1148
|
+
if (!p?.done.has(s.id) && !shown.has(`s:${s.id}`)) {
|
|
1149
|
+
shown.add(`s:${s.id}`);
|
|
1150
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, step: s.id, kind: s.kind, action: "shown" });
|
|
1151
|
+
if (s.kind !== "checklist") break;
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
complete: (id, stepId) => {
|
|
1155
|
+
const f = flowById(id);
|
|
1156
|
+
const s = f && stepsIn(nodesOf(f)).find((x) => x.id === stepId);
|
|
1157
|
+
if (!f || !s || s.kind === "question") return;
|
|
1158
|
+
const p = prog(f.id);
|
|
1159
|
+
if (p.done.has(s.id)) return;
|
|
1160
|
+
markDone(p, s.id);
|
|
1161
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, step: s.id, kind: s.kind, action: "completed" });
|
|
1162
|
+
ended(f);
|
|
1163
|
+
},
|
|
1164
|
+
dismissItem: (id) => {
|
|
1165
|
+
const f = flowById(id);
|
|
1166
|
+
if (!f) return;
|
|
1167
|
+
const p = prog(f.id);
|
|
1168
|
+
if (p.dismissed) return;
|
|
1169
|
+
p.dismissed = true;
|
|
1170
|
+
env.track(ONBOARDING_EVENT, { flow: f.id, action: "dismissed" });
|
|
1171
|
+
if (active === f.id) active = null;
|
|
1172
|
+
ended(f);
|
|
1173
|
+
},
|
|
1174
|
+
answerItem: (id, question, value) => {
|
|
1175
|
+
const f = flowById(id);
|
|
1176
|
+
const s = f && stepsIn(nodesOf(f)).find((x) => x.kind === "question" && (x.id === question || x.question?.key === question));
|
|
1177
|
+
if (!f || !s?.question || !answerOk(s.question, value)) return;
|
|
1178
|
+
answerStep(f, s, value);
|
|
1179
|
+
ended(f);
|
|
866
1180
|
}
|
|
867
1181
|
},
|
|
1182
|
+
finale: () => finaleNow,
|
|
1183
|
+
accent: () => config?.onboardingAccent,
|
|
1184
|
+
answers: () => Object.fromEntries(answers),
|
|
868
1185
|
message: {
|
|
869
1186
|
click: () => {
|
|
870
1187
|
const v = view();
|
|
@@ -1298,7 +1615,14 @@ var createClient = (options, deps) => {
|
|
|
1298
1615
|
set: (k, v) => void set(k, v)
|
|
1299
1616
|
} : null,
|
|
1300
1617
|
openUrl: deps.openUrl,
|
|
1301
|
-
fetchInApp: (id) => fetchInApp(id)
|
|
1618
|
+
fetchInApp: (id) => fetchInApp(id),
|
|
1619
|
+
// 0.18.0: a task's page or screen goes to the app's navigator; without one only a link with a scheme opens.
|
|
1620
|
+
navigate: (target) => {
|
|
1621
|
+
if (options.onNavigate) return options.onNavigate(target);
|
|
1622
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(target) && !/^(javascript|data|vbscript):/i.test(target)) deps.openUrl?.(target);
|
|
1623
|
+
else warn(`A checklist task opens "${target}": pass onNavigate to MRRocketProvider to open screens and paths.`);
|
|
1624
|
+
},
|
|
1625
|
+
task: (taskId, item) => options.onTask?.(taskId, item)
|
|
1302
1626
|
});
|
|
1303
1627
|
const refreshFlows = () => {
|
|
1304
1628
|
if (!isReady || closed) return;
|
|
@@ -1474,7 +1798,7 @@ var createClient = (options, deps) => {
|
|
|
1474
1798
|
if (errorsSeen.has(mark)) return;
|
|
1475
1799
|
errorsSeen.add(mark);
|
|
1476
1800
|
errorsSent++;
|
|
1477
|
-
const
|
|
1801
|
+
const who2 = sendId();
|
|
1478
1802
|
errorQueue.push({
|
|
1479
1803
|
...d,
|
|
1480
1804
|
mechanism,
|
|
@@ -1483,7 +1807,7 @@ var createClient = (options, deps) => {
|
|
|
1483
1807
|
ts: now(),
|
|
1484
1808
|
crumbs: crumbs.slice(),
|
|
1485
1809
|
...release ? { release } : {},
|
|
1486
|
-
...
|
|
1810
|
+
...who2 ? { distinctId: who2 } : {},
|
|
1487
1811
|
...session ? { sessionId: session.id } : {}
|
|
1488
1812
|
});
|
|
1489
1813
|
recorder?.mark({ kind: "error", path: currentScreen ?? "/", label: clip2(d.message, 120) });
|
|
@@ -1598,20 +1922,20 @@ var createClient = (options, deps) => {
|
|
|
1598
1922
|
await loadedNow();
|
|
1599
1923
|
if (!apiKey || consent === "off") return { status: "error", reason: !apiKey ? "No public key." : "The consent is off." };
|
|
1600
1924
|
if (!identified) return { status: "not-signed-in" };
|
|
1601
|
-
const
|
|
1602
|
-
const userHash = hashOf(
|
|
1925
|
+
const who2 = identified;
|
|
1926
|
+
const userHash = hashOf(who2);
|
|
1603
1927
|
try {
|
|
1604
1928
|
const permission = await deps.push.permission(o.ask !== false);
|
|
1605
1929
|
if (permission !== "granted") return { status: permission === "denied" ? "denied" : "not-asked" };
|
|
1606
1930
|
const token = await deps.push.token(o.projectId);
|
|
1607
1931
|
if (!token) return { status: "unavailable", reason: "This device has no push token (a simulator, or no EAS project id)." };
|
|
1608
|
-
const status = await post("/api/sdk/push", JSON.stringify({ key: apiKey, distinctId:
|
|
1932
|
+
const status = await post("/api/sdk/push", JSON.stringify({ key: apiKey, distinctId: who2, userHash, platform: "expo", token, app: context }));
|
|
1609
1933
|
if (status < 200 || status >= 300) {
|
|
1610
1934
|
warn(`Push registration was rejected with ${status || "no answer"}. Check the public key and the host.`);
|
|
1611
1935
|
return { status: "error", reason: `MRRocket answered ${status || "nothing"}.` };
|
|
1612
1936
|
}
|
|
1613
1937
|
pushToken = token;
|
|
1614
|
-
pushFor =
|
|
1938
|
+
pushFor = who2;
|
|
1615
1939
|
pushHash = userHash;
|
|
1616
1940
|
listenForOpens();
|
|
1617
1941
|
debug("Registered for push.");
|
|
@@ -1936,30 +2260,216 @@ var activeRouteName = (state) => {
|
|
|
1936
2260
|
};
|
|
1937
2261
|
|
|
1938
2262
|
// src/native/flows-view.ts
|
|
1939
|
-
var
|
|
2263
|
+
var import_react2 = require("react");
|
|
2264
|
+
|
|
2265
|
+
// src/icons.ts
|
|
2266
|
+
var FLOW_ICONS = {
|
|
2267
|
+
check: { label: "Check", paths: ["M5 12.5l4.5 4.5L19 7.5"], emoji: "\u2705" },
|
|
2268
|
+
star: { label: "Star", paths: ["M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z"], emoji: "\u2B50" },
|
|
2269
|
+
rocket: {
|
|
2270
|
+
label: "Rocket",
|
|
2271
|
+
paths: ["M12 3c3 2 4.5 5.5 4 10l-2 3h-4l-2-3c-.5-4.5 1-8 4-10z", "M8 13.5l-3 3 3.5.5", "M16 13.5l3 3-3.5.5", "M13.5 9.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z", "M11 19.5v1.5M13 19.5v1.5"],
|
|
2272
|
+
emoji: "\u{1F680}"
|
|
2273
|
+
},
|
|
2274
|
+
user: { label: "Person", paths: ["M15.5 8a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z", "M5 20c.8-3.5 3.6-5.5 7-5.5s6.2 2 7 5.5"], emoji: "\u{1F464}" },
|
|
2275
|
+
users: {
|
|
2276
|
+
label: "Team",
|
|
2277
|
+
paths: ["M13 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z", "M3.5 19c.6-3 3-4.8 6.5-4.8s5.9 1.8 6.5 4.8", "M16 5.2a3 3 0 0 1 0 5.6", "M18 14.6c1.5.6 2.4 2 2.7 4.4"],
|
|
2278
|
+
emoji: "\u{1F465}"
|
|
2279
|
+
},
|
|
2280
|
+
settings: {
|
|
2281
|
+
label: "Settings",
|
|
2282
|
+
paths: ["M12 2.8v2.4M12 18.8v2.4M2.8 12h2.4M18.8 12h2.4M5.5 5.5l1.7 1.7M16.8 16.8l1.7 1.7M5.5 18.5l1.7-1.7M16.8 7.2l1.7-1.7", "M17 12a5 5 0 1 1-10 0 5 5 0 0 1 10 0z", "M14 12a2 2 0 1 1-4 0 2 2 0 0 1 4 0z"],
|
|
2283
|
+
emoji: "\u2699\uFE0F"
|
|
2284
|
+
},
|
|
2285
|
+
bell: { label: "Bell", paths: ["M6 16v-5a6 6 0 0 1 12 0v5l1.5 2h-15z", "M10 20.5a2 2 0 0 0 4 0"], emoji: "\u{1F514}" },
|
|
2286
|
+
mail: { label: "Mail", paths: ["M4 6h16v12H4z", "M4 7l8 6 8-6"], emoji: "\u2709\uFE0F" },
|
|
2287
|
+
chat: { label: "Chat", paths: ["M4 5h16v11H9l-5 4z"], emoji: "\u{1F4AC}" },
|
|
2288
|
+
heart: { label: "Heart", paths: ["M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z"], emoji: "\u2764\uFE0F" },
|
|
2289
|
+
flag: { label: "Flag", paths: ["M5 21V4", "M5 4h11l-2 4 2 4H5"], emoji: "\u{1F6A9}" },
|
|
2290
|
+
bolt: { label: "Bolt", paths: ["M13 3L5 13.5h6L10 21l8-10.5h-6z"], emoji: "\u26A1" },
|
|
2291
|
+
book: { label: "Book", paths: ["M4 5.5C6.5 4 9.5 4 12 6c2.5-2 5.5-2 8-.5V19c-2.5-1.5-5.5-1.5-8 .5-2.5-2-5.5-2-8-.5z", "M12 6v13.5"], emoji: "\u{1F4D6}" },
|
|
2292
|
+
calendar: { label: "Calendar", paths: ["M4 6h16v14H4z", "M4 10h16", "M8 3.5v4M16 3.5v4"], emoji: "\u{1F4C5}" },
|
|
2293
|
+
camera: { label: "Camera", paths: ["M4 8h3.5L9 5.5h6L16.5 8H20v11H4z", "M15.5 13a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z"], emoji: "\u{1F4F7}" },
|
|
2294
|
+
cart: { label: "Cart", paths: ["M3.5 4.5H6l2 10h10l2-7H7", "M9.5 19.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z", "M18.5 19.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"], emoji: "\u{1F6D2}" },
|
|
2295
|
+
chart: { label: "Chart", paths: ["M4 20h16", "M7 16v-4M12 16V8M17 16V9"], emoji: "\u{1F4CA}" },
|
|
2296
|
+
gift: { label: "Gift", paths: ["M4 10h16v10H4z", "M3 7h18v3H3z", "M12 7v13", "M12 7c-1.5-3-5-3-5-1s3.5 1 5 1z", "M12 7c1.5-3 5-3 5-1s-3.5 1-5 1z"], emoji: "\u{1F381}" },
|
|
2297
|
+
home: { label: "Home", paths: ["M4 11l8-7 8 7", "M6 9.5V20h12V9.5", "M10 20v-6h4v6"], emoji: "\u{1F3E0}" },
|
|
2298
|
+
link: { label: "Link", paths: ["M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1", "M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"], emoji: "\u{1F517}" },
|
|
2299
|
+
lock: { label: "Lock", paths: ["M6 11h12v9H6z", "M8.5 11V8a3.5 3.5 0 0 1 7 0v3"], emoji: "\u{1F512}" },
|
|
2300
|
+
pencil: { label: "Pencil", paths: ["M4 20l1-4L16 5l3 3L8 19z", "M14 7l3 3"], emoji: "\u270F\uFE0F" },
|
|
2301
|
+
plus: { label: "Plus", paths: ["M12 5v14M5 12h14"], emoji: "\u2795" },
|
|
2302
|
+
search: { label: "Search", paths: ["M16 10.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z", "M14.5 14.5L20 20"], emoji: "\u{1F50D}" },
|
|
2303
|
+
upload: { label: "Upload", paths: ["M12 15V4", "M7.5 8.5L12 4l4.5 4.5", "M4 15v5h16v-5"], emoji: "\u2B06\uFE0F" },
|
|
2304
|
+
play: { label: "Play", paths: ["M8 5l11 7-11 7z"], emoji: "\u25B6\uFE0F" },
|
|
2305
|
+
sparkle: { label: "Sparkle", paths: ["M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z", "M19 16l.7 2 2 .7-2 .7-.7 2-.7-2-2-.7 2-.7z"], emoji: "\u2728" },
|
|
2306
|
+
globe: {
|
|
2307
|
+
label: "Globe",
|
|
2308
|
+
paths: ["M20 12a8 8 0 1 1-16 0 8 8 0 0 1 16 0z", "M4 12h16", "M12 4c2.2 2.2 3.3 4.9 3.3 8s-1.1 5.8-3.3 8c-2.2-2.2-3.3-4.9-3.3-8S9.8 6.2 12 4z"],
|
|
2309
|
+
emoji: "\u{1F310}"
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
var FLOW_ICON_NAMES = Object.keys(FLOW_ICONS);
|
|
2313
|
+
var iconOf = (icon) => {
|
|
2314
|
+
if (!icon) return void 0;
|
|
2315
|
+
if (icon.kind === "builtin") return icon.name && FLOW_ICONS[icon.name] ? icon : void 0;
|
|
2316
|
+
if (icon.kind === "emoji") return icon.value && icon.value.trim() && [...icon.value.trim()].length <= 8 ? icon : void 0;
|
|
2317
|
+
if (icon.kind === "image") return icon.url && /^https?:\/\//i.test(icon.url) ? icon : void 0;
|
|
2318
|
+
return void 0;
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
// src/native/flows-view.ts
|
|
1940
2322
|
var RN = require("react-native");
|
|
2323
|
+
var svg = (() => {
|
|
2324
|
+
try {
|
|
2325
|
+
return require("react-native-svg");
|
|
2326
|
+
} catch {
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
})();
|
|
2330
|
+
var iconNode = (icon, size, color) => {
|
|
2331
|
+
const i = iconOf(icon);
|
|
2332
|
+
if (!i) return null;
|
|
2333
|
+
if (i.kind === "image")
|
|
2334
|
+
return RN.Image ? (0, import_react2.createElement)(RN.Image, { source: { uri: i.url }, accessibilityElementsHidden: true, style: { width: size, height: size, borderRadius: size / 4 } }) : null;
|
|
2335
|
+
const Svg = svg?.Svg ?? svg?.default;
|
|
2336
|
+
if (i.kind === "builtin" && Svg && svg?.Path)
|
|
2337
|
+
return (0, import_react2.createElement)(
|
|
2338
|
+
Svg,
|
|
2339
|
+
{ width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" },
|
|
2340
|
+
...FLOW_ICONS[i.name].paths.map((d, k) => (0, import_react2.createElement)(svg.Path, { key: k, d }))
|
|
2341
|
+
);
|
|
2342
|
+
return (0, import_react2.createElement)(RN.Text, { style: { fontSize: size * 0.8, lineHeight: size, textAlign: "center", width: size } }, i.kind === "emoji" ? i.value : FLOW_ICONS[i.name].emoji);
|
|
2343
|
+
};
|
|
2344
|
+
var FINALE_COLORS = ["#f59e0b", "#10b981", "#ef4444", "#8b5cf6", "#06b6d4", "#ec4899"];
|
|
2345
|
+
var finaleBits = (kind, accent) => {
|
|
2346
|
+
const rnd = (a, b) => a + Math.random() * (b - a);
|
|
2347
|
+
const colors = [accent, accent, ...FINALE_COLORS];
|
|
2348
|
+
const pick = () => colors[Math.floor(Math.random() * colors.length)];
|
|
2349
|
+
if (kind === "confetti")
|
|
2350
|
+
return Array.from({ length: 48 }, (_, i) => ({
|
|
2351
|
+
x: i % 2 ? 12 : 82,
|
|
2352
|
+
y: 92,
|
|
2353
|
+
dx: (i % 2 ? 1 : -1) * rnd(40, 200),
|
|
2354
|
+
mid: -rnd(380, 620),
|
|
2355
|
+
dy: -rnd(120, 300),
|
|
2356
|
+
size: rnd(7, 11),
|
|
2357
|
+
rot: rnd(-540, 540),
|
|
2358
|
+
color: pick(),
|
|
2359
|
+
delay: rnd(0, 160),
|
|
2360
|
+
life: rnd(1500, 2e3),
|
|
2361
|
+
shape: "rect"
|
|
2362
|
+
}));
|
|
2363
|
+
if (kind === "fireworks")
|
|
2364
|
+
return Array.from({ length: 3 }, (_, b) => {
|
|
2365
|
+
const x = rnd(20, 75);
|
|
2366
|
+
const y = rnd(18, 45);
|
|
2367
|
+
const color = pick();
|
|
2368
|
+
return Array.from({ length: 18 }, (_2, i) => {
|
|
2369
|
+
const a = Math.PI * 2 * i / 18;
|
|
2370
|
+
const r = rnd(70, 130);
|
|
2371
|
+
return { x, y, dx: Math.cos(a) * r, mid: Math.sin(a) * r * 0.8, dy: Math.sin(a) * r + 40, size: 5, rot: 0, color, delay: b * 320, life: rnd(900, 1200), shape: "dot" };
|
|
2372
|
+
});
|
|
2373
|
+
}).flat();
|
|
2374
|
+
return Array.from({ length: 22 }, () => ({
|
|
2375
|
+
x: rnd(6, 88),
|
|
2376
|
+
y: rnd(20, 80),
|
|
2377
|
+
dx: 0,
|
|
2378
|
+
mid: -rnd(10, 25),
|
|
2379
|
+
dy: -rnd(30, 60),
|
|
2380
|
+
size: rnd(16, 28),
|
|
2381
|
+
rot: rnd(-40, 40),
|
|
2382
|
+
color: pick(),
|
|
2383
|
+
delay: rnd(0, 600),
|
|
2384
|
+
life: rnd(900, 1300),
|
|
2385
|
+
shape: "star"
|
|
2386
|
+
}));
|
|
2387
|
+
};
|
|
2388
|
+
var Finale = ({ kind, accent }) => {
|
|
2389
|
+
const A = RN.Animated;
|
|
2390
|
+
const [bits] = (0, import_react2.useState)(() => finaleBits(kind, accent));
|
|
2391
|
+
const [values] = (0, import_react2.useState)(() => A ? bits.map(() => new A.Value(0)) : []);
|
|
2392
|
+
const [on, setOn] = (0, import_react2.useState)(!!A);
|
|
2393
|
+
(0, import_react2.useEffect)(() => {
|
|
2394
|
+
if (!A) return;
|
|
2395
|
+
let stopped = false;
|
|
2396
|
+
let run = null;
|
|
2397
|
+
const go = () => {
|
|
2398
|
+
if (stopped) return;
|
|
2399
|
+
run = A.parallel(values.map((v, i) => A.timing(v, { toValue: 1, duration: bits[i].life, delay: bits[i].delay, useNativeDriver: true })));
|
|
2400
|
+
run.start(() => !stopped && setOn(false));
|
|
2401
|
+
};
|
|
2402
|
+
Promise.resolve(RN.AccessibilityInfo?.isReduceMotionEnabled?.()).then((reduce) => reduce ? !stopped && setOn(false) : go()).catch(go);
|
|
2403
|
+
return () => {
|
|
2404
|
+
stopped = true;
|
|
2405
|
+
run?.stop();
|
|
2406
|
+
};
|
|
2407
|
+
}, [A, bits, values]);
|
|
2408
|
+
if (!on || !A) return null;
|
|
2409
|
+
return (0, import_react2.createElement)(
|
|
2410
|
+
RN.View,
|
|
2411
|
+
{ pointerEvents: "none", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: { position: "absolute", left: 0, right: 0, top: 0, bottom: 0 } },
|
|
2412
|
+
...bits.map((b, i) => {
|
|
2413
|
+
const t = values[i];
|
|
2414
|
+
const fade = t.interpolate({ inputRange: [0, 0.7, 1], outputRange: [1, 1, 0] });
|
|
2415
|
+
const scale = b.shape === "star" ? t.interpolate({ inputRange: [0, 0.25, 1], outputRange: [0.2, 1.15, 0.6] }) : 1;
|
|
2416
|
+
return (0, import_react2.createElement)(
|
|
2417
|
+
A.View,
|
|
2418
|
+
{
|
|
2419
|
+
key: i,
|
|
2420
|
+
style: {
|
|
2421
|
+
position: "absolute",
|
|
2422
|
+
left: `${b.x}%`,
|
|
2423
|
+
top: `${b.y}%`,
|
|
2424
|
+
width: b.size,
|
|
2425
|
+
height: b.shape === "rect" ? b.size * 0.45 : b.size,
|
|
2426
|
+
borderRadius: b.shape === "dot" ? b.size / 2 : 2,
|
|
2427
|
+
backgroundColor: b.shape === "star" ? "transparent" : b.color,
|
|
2428
|
+
alignItems: "center",
|
|
2429
|
+
justifyContent: "center",
|
|
2430
|
+
opacity: fade,
|
|
2431
|
+
transform: [
|
|
2432
|
+
{ translateX: t.interpolate({ inputRange: [0, 1], outputRange: [0, b.dx] }) },
|
|
2433
|
+
{ translateY: t.interpolate({ inputRange: [0, 0.5, 1], outputRange: [0, b.mid, b.dy] }) },
|
|
2434
|
+
{ rotate: t.interpolate({ inputRange: [0, 1], outputRange: ["0deg", `${b.rot}deg`] }) },
|
|
2435
|
+
{ scale }
|
|
2436
|
+
]
|
|
2437
|
+
}
|
|
2438
|
+
},
|
|
2439
|
+
b.shape === "star" ? (0, import_react2.createElement)(RN.Text, { style: { color: b.color, fontSize: b.size, lineHeight: b.size } }, "\u2605") : null
|
|
2440
|
+
);
|
|
2441
|
+
})
|
|
2442
|
+
);
|
|
2443
|
+
};
|
|
1941
2444
|
var LIGHT = { bg: "#ffffff", fg: "#1c1d20", muted: "#5d6068", soft: "#f4f5f7", line: "#e4e5e8" };
|
|
1942
2445
|
var DARK = { bg: "#17181b", fg: "#f1f2f4", muted: "#a9acb3", soft: "#232428", line: "#2e2f35" };
|
|
1943
2446
|
var months = (n) => `${n} ${n === 1 ? "month" : "months"}`;
|
|
1944
|
-
var MRRocketFlows = (
|
|
2447
|
+
var MRRocketFlows = (props) => {
|
|
2448
|
+
const [, setTick] = (0, import_react2.useState)(0);
|
|
2449
|
+
(0, import_react2.useEffect)(() => props.flows.subscribe(() => setTick((t) => t + 1)), [props.flows]);
|
|
2450
|
+
const fin = props.flows.finale?.() ?? null;
|
|
2451
|
+
const accent = props.appearance?.accent ?? props.flows.accent?.() ?? "#3f76ff";
|
|
2452
|
+
return (0, import_react2.createElement)(import_react2.Fragment, null, (0, import_react2.createElement)(FlowsBody, props), fin ? (0, import_react2.createElement)(Finale, { key: fin.key, kind: fin.kind, accent }) : null);
|
|
2453
|
+
};
|
|
2454
|
+
var FlowsBody = ({ flows, paywall, appearance = {} }) => {
|
|
1945
2455
|
const scheme = RN.useColorScheme?.();
|
|
1946
2456
|
const dark = appearance.theme === "dark" || (appearance.theme ?? "auto") === "auto" && scheme === "dark";
|
|
1947
|
-
const p = { ...dark ? DARK : LIGHT, accent: appearance.accent ?? "#3f76ff", danger: "#d92d20" };
|
|
1948
|
-
const [, setTick] = (0,
|
|
1949
|
-
(0,
|
|
1950
|
-
(0,
|
|
2457
|
+
const p = { ...dark ? DARK : LIGHT, accent: appearance.accent ?? flows.accent?.() ?? "#3f76ff", danger: "#d92d20" };
|
|
2458
|
+
const [, setTick] = (0, import_react2.useState)(0);
|
|
2459
|
+
(0, import_react2.useEffect)(() => flows.subscribe(() => setTick((t) => t + 1)), [flows]);
|
|
2460
|
+
(0, import_react2.useEffect)(() => paywall?.subscribe(() => setTick((t) => t + 1)), [paywall]);
|
|
1951
2461
|
const pw = paywall?.view() ?? null;
|
|
1952
2462
|
const v = flows.view();
|
|
1953
|
-
const [comment, setComment] = (0,
|
|
2463
|
+
const [comment, setComment] = (0, import_react2.useState)("");
|
|
1954
2464
|
const screen = v?.type === "cancel" ? v.screen : null;
|
|
1955
|
-
(0,
|
|
2465
|
+
(0, import_react2.useEffect)(() => {
|
|
1956
2466
|
if (!screen) setComment("");
|
|
1957
2467
|
}, [screen]);
|
|
1958
2468
|
if (!v && !pw) return null;
|
|
1959
|
-
const text2 = (children, style = {}) => (0,
|
|
2469
|
+
const text2 = (children, style = {}) => (0, import_react2.createElement)(RN.Text, { style: { color: p.fg, fontSize: 15, ...style } }, children);
|
|
1960
2470
|
const muted = (children, style = {}) => text2(children, { color: p.muted, fontSize: 13, ...style });
|
|
1961
|
-
const title = (children) => (0,
|
|
1962
|
-
const btn = (label, kind, onPress, disabled = false) => (0,
|
|
2471
|
+
const title = (children) => (0, import_react2.createElement)(RN.Text, { accessibilityRole: "header", style: { color: p.fg, fontSize: 18, fontWeight: "700" } }, children);
|
|
2472
|
+
const btn = (label, kind, onPress, disabled = false) => (0, import_react2.createElement)(
|
|
1963
2473
|
RN.Pressable,
|
|
1964
2474
|
{
|
|
1965
2475
|
key: label,
|
|
@@ -1983,12 +2493,12 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
1983
2493
|
fontWeight: kind === "quiet" ? "500" : "600"
|
|
1984
2494
|
})
|
|
1985
2495
|
);
|
|
1986
|
-
const close = (label, onPress) => (0,
|
|
2496
|
+
const close = (label, onPress) => (0, import_react2.createElement)(
|
|
1987
2497
|
RN.Pressable,
|
|
1988
2498
|
{ onPress, accessibilityRole: "button", accessibilityLabel: label, hitSlop: 12, style: { marginLeft: "auto", padding: 4 } },
|
|
1989
2499
|
text2("\xD7", { fontSize: 22, color: p.muted })
|
|
1990
2500
|
);
|
|
1991
|
-
const card = (children, style = {}) => (0,
|
|
2501
|
+
const card = (children, style = {}) => (0, import_react2.createElement)(
|
|
1992
2502
|
RN.View,
|
|
1993
2503
|
{
|
|
1994
2504
|
style: {
|
|
@@ -2005,16 +2515,16 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2005
2515
|
},
|
|
2006
2516
|
...children
|
|
2007
2517
|
);
|
|
2008
|
-
const sheet = (children, onClose) => (0,
|
|
2518
|
+
const sheet = (children, onClose) => (0, import_react2.createElement)(
|
|
2009
2519
|
RN.Modal,
|
|
2010
2520
|
{ visible: true, transparent: true, animationType: "fade", onRequestClose: onClose },
|
|
2011
|
-
(0,
|
|
2521
|
+
(0, import_react2.createElement)(
|
|
2012
2522
|
RN.View,
|
|
2013
2523
|
{ style: { flex: 1, backgroundColor: "rgba(0,0,0,0.4)", justifyContent: "flex-end" } },
|
|
2014
2524
|
card(children, { borderBottomLeftRadius: 0, borderBottomRightRadius: 0, paddingBottom: 34 })
|
|
2015
2525
|
)
|
|
2016
2526
|
);
|
|
2017
|
-
const input = (placeholder, value = comment, onChange = setComment) => (0,
|
|
2527
|
+
const input = (placeholder, value = comment, onChange = setComment) => (0, import_react2.createElement)(RN.TextInput, {
|
|
2018
2528
|
value,
|
|
2019
2529
|
onChangeText: onChange,
|
|
2020
2530
|
placeholder,
|
|
@@ -2029,19 +2539,19 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2029
2539
|
const host = paywall;
|
|
2030
2540
|
return sheet(
|
|
2031
2541
|
[
|
|
2032
|
-
(0,
|
|
2542
|
+
(0, import_react2.createElement)(
|
|
2033
2543
|
RN.View,
|
|
2034
2544
|
{ key: "top", style: { flexDirection: "row", alignItems: "center", gap: 4 } },
|
|
2035
2545
|
...w.total > 1 ? Array.from(
|
|
2036
2546
|
{ length: w.total },
|
|
2037
|
-
(_, i) => (0,
|
|
2547
|
+
(_, i) => (0, import_react2.createElement)(RN.View, { key: i, style: { width: 16, height: 4, borderRadius: 4, backgroundColor: i <= w.index ? p.accent : p.line } })
|
|
2038
2548
|
) : [],
|
|
2039
2549
|
close("Close", host.close)
|
|
2040
2550
|
),
|
|
2041
2551
|
title(pg.title),
|
|
2042
2552
|
pg.body ? muted(pg.body, { fontSize: 15 }) : null,
|
|
2043
2553
|
...pg.kind === "benefits" ? (pg.items ?? []).map(
|
|
2044
|
-
(item, i) => (0,
|
|
2554
|
+
(item, i) => (0, import_react2.createElement)(
|
|
2045
2555
|
RN.View,
|
|
2046
2556
|
{ key: `b${i}`, style: { flexDirection: "row", gap: 10, alignItems: "flex-start" } },
|
|
2047
2557
|
text2("\u2713", { color: p.accent, fontWeight: "700" }),
|
|
@@ -2049,13 +2559,13 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2049
2559
|
)
|
|
2050
2560
|
) : [],
|
|
2051
2561
|
...pg.kind === "proof" ? (pg.quotes ?? []).map(
|
|
2052
|
-
(q, i) => (0,
|
|
2562
|
+
(q, i) => (0, import_react2.createElement)(RN.View, { key: `q${i}`, style: { backgroundColor: p.soft, borderRadius: 12, padding: 12, gap: 6 } }, text2(q.text), q.by ? muted(q.by) : null)
|
|
2053
2563
|
) : [],
|
|
2054
|
-
pg.kind === "plans" ? (0,
|
|
2564
|
+
pg.kind === "plans" ? (0, import_react2.createElement)(
|
|
2055
2565
|
RN.View,
|
|
2056
2566
|
{ key: "plans", accessibilityRole: "radiogroup", style: { gap: 6 } },
|
|
2057
2567
|
...w.plans.map(
|
|
2058
|
-
(plan) => (0,
|
|
2568
|
+
(plan) => (0, import_react2.createElement)(
|
|
2059
2569
|
RN.Pressable,
|
|
2060
2570
|
{
|
|
2061
2571
|
key: plan.id,
|
|
@@ -2075,7 +2585,7 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2075
2585
|
gap: 10
|
|
2076
2586
|
}
|
|
2077
2587
|
},
|
|
2078
|
-
(0,
|
|
2588
|
+
(0, import_react2.createElement)(RN.View, { style: { flex: 1 } }, text2(plan.name, { fontWeight: "600" }), plan.note ? muted(plan.note) : null),
|
|
2079
2589
|
text2(plan.price, { fontWeight: "700" })
|
|
2080
2590
|
)
|
|
2081
2591
|
)
|
|
@@ -2090,22 +2600,22 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2090
2600
|
if (pw) return paywallSheet(pw);
|
|
2091
2601
|
if (!v) return null;
|
|
2092
2602
|
if (v.type === "cancel") {
|
|
2093
|
-
const top = (0,
|
|
2603
|
+
const top = (0, import_react2.createElement)(
|
|
2094
2604
|
RN.View,
|
|
2095
2605
|
{ style: { flexDirection: "row", alignItems: "center", gap: 4 } },
|
|
2096
2606
|
...v.steps > 1 ? Array.from(
|
|
2097
2607
|
{ length: v.steps },
|
|
2098
|
-
(_, i) => (0,
|
|
2608
|
+
(_, i) => (0, import_react2.createElement)(RN.View, { key: i, style: { width: 16, height: 4, borderRadius: 4, backgroundColor: i < v.step ? p.accent : p.line } })
|
|
2099
2609
|
) : [],
|
|
2100
2610
|
close("Close", flows.cancel.close)
|
|
2101
2611
|
);
|
|
2102
2612
|
const error = v.error ? text2(v.error, { color: p.danger, fontSize: 13 }) : null;
|
|
2103
2613
|
let body = [];
|
|
2104
|
-
const choices = (items) => (0,
|
|
2614
|
+
const choices = (items) => (0, import_react2.createElement)(
|
|
2105
2615
|
RN.ScrollView,
|
|
2106
2616
|
{ style: { maxHeight: 320 }, contentContainerStyle: { gap: 6 }, accessibilityRole: "radiogroup" },
|
|
2107
2617
|
...items.map(
|
|
2108
|
-
(c) => (0,
|
|
2618
|
+
(c) => (0, import_react2.createElement)(
|
|
2109
2619
|
RN.Pressable,
|
|
2110
2620
|
{
|
|
2111
2621
|
key: c.key,
|
|
@@ -2150,7 +2660,7 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2150
2660
|
body = [
|
|
2151
2661
|
label ? muted(`You said: ${label}`) : null,
|
|
2152
2662
|
title(o.headline),
|
|
2153
|
-
detail ? (0,
|
|
2663
|
+
detail ? (0, import_react2.createElement)(RN.View, { style: { backgroundColor: p.soft, borderRadius: 10, padding: 12 } }, text2(detail, { fontWeight: "600" })) : null,
|
|
2154
2664
|
o.kind === "contact" ? input("What would make you stay?") : null,
|
|
2155
2665
|
btn(v.busy ? "One moment\u2026" : offerButton(o), "primary", () => flows.cancel.accept(comment), v.busy),
|
|
2156
2666
|
btn("No thanks, continue cancelling", "quiet", flows.cancel.decline, v.busy)
|
|
@@ -2165,15 +2675,92 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2165
2675
|
];
|
|
2166
2676
|
return sheet([top, ...body, error], flows.cancel.close);
|
|
2167
2677
|
}
|
|
2678
|
+
const media = (s) => {
|
|
2679
|
+
const m2 = mediaOf(s);
|
|
2680
|
+
if (!m2) return null;
|
|
2681
|
+
if (m2.kind === "image")
|
|
2682
|
+
return RN.Image ? (0, import_react2.createElement)(RN.Image, {
|
|
2683
|
+
key: "media",
|
|
2684
|
+
source: { uri: m2.url },
|
|
2685
|
+
accessibilityLabel: m2.alt,
|
|
2686
|
+
resizeMode: "cover",
|
|
2687
|
+
style: { width: "100%", aspectRatio: 16 / 9, borderRadius: 10, backgroundColor: p.soft }
|
|
2688
|
+
}) : null;
|
|
2689
|
+
const v2 = videoEmbed(m2.url);
|
|
2690
|
+
const open = v2?.kind === "file" ? v2.src : m2.url;
|
|
2691
|
+
return RN.Linking ? btn("\u25B6 Watch the video", "secondary", () => void RN.Linking?.openURL(open).catch(() => {
|
|
2692
|
+
})) : null;
|
|
2693
|
+
};
|
|
2694
|
+
if (v.type === "step" && v.step.kind === "question") {
|
|
2695
|
+
const s = v.step;
|
|
2696
|
+
const q = s.question;
|
|
2697
|
+
const ok = answerOk(q, v.answer);
|
|
2698
|
+
return sheet(
|
|
2699
|
+
[
|
|
2700
|
+
(0, import_react2.createElement)(
|
|
2701
|
+
RN.View,
|
|
2702
|
+
{ key: "top", style: { flexDirection: "row", alignItems: "center", gap: 4 } },
|
|
2703
|
+
...v.total > 1 ? Array.from(
|
|
2704
|
+
{ length: v.total },
|
|
2705
|
+
(_, i) => (0, import_react2.createElement)(RN.View, { key: i, style: { width: 16, height: 4, borderRadius: 4, backgroundColor: i <= v.index ? p.accent : p.line } })
|
|
2706
|
+
) : [],
|
|
2707
|
+
close("Close", flows.onboarding.dismiss)
|
|
2708
|
+
),
|
|
2709
|
+
v.index === 0 && v.flow.icon ? (0, import_react2.createElement)(RN.View, { key: "icon" }, iconNode(v.flow.icon, 36, p.accent)) : null,
|
|
2710
|
+
title(s.title),
|
|
2711
|
+
s.body ? muted(s.body, { fontSize: 15 }) : null,
|
|
2712
|
+
q?.type === "choice" ? (0, import_react2.createElement)(
|
|
2713
|
+
RN.ScrollView,
|
|
2714
|
+
{ key: "opts", style: { maxHeight: 320 }, contentContainerStyle: { gap: 6 }, accessibilityRole: "radiogroup" },
|
|
2715
|
+
...(q.options ?? []).map(
|
|
2716
|
+
(o) => (0, import_react2.createElement)(
|
|
2717
|
+
RN.Pressable,
|
|
2718
|
+
{
|
|
2719
|
+
key: o.id,
|
|
2720
|
+
onPress: () => flows.onboarding.answer(o.id),
|
|
2721
|
+
accessibilityRole: "radio",
|
|
2722
|
+
accessibilityState: { checked: v.answer === o.id },
|
|
2723
|
+
style: {
|
|
2724
|
+
minHeight: 44,
|
|
2725
|
+
paddingHorizontal: 12,
|
|
2726
|
+
borderRadius: 10,
|
|
2727
|
+
borderWidth: 1,
|
|
2728
|
+
borderColor: v.answer === o.id ? p.accent : p.line,
|
|
2729
|
+
backgroundColor: v.answer === o.id ? p.soft : p.bg,
|
|
2730
|
+
justifyContent: "center"
|
|
2731
|
+
}
|
|
2732
|
+
},
|
|
2733
|
+
text2(o.label, { fontWeight: "500" })
|
|
2734
|
+
)
|
|
2735
|
+
)
|
|
2736
|
+
) : q ? (0, import_react2.createElement)(RN.TextInput, {
|
|
2737
|
+
key: "answer",
|
|
2738
|
+
value: v.answer ?? "",
|
|
2739
|
+
onChangeText: (t) => flows.onboarding.answer(t),
|
|
2740
|
+
onSubmitEditing: flows.onboarding.next,
|
|
2741
|
+
placeholder: q.placeholder || "Your answer",
|
|
2742
|
+
placeholderTextColor: p.muted,
|
|
2743
|
+
maxLength: 500,
|
|
2744
|
+
accessibilityLabel: s.title,
|
|
2745
|
+
style: { height: 44, borderWidth: 1, borderColor: p.line, borderRadius: 10, paddingHorizontal: 12, color: p.fg }
|
|
2746
|
+
}) : null,
|
|
2747
|
+
btn(s.button || (v.last ? "Done" : "Continue"), "primary", flows.onboarding.next, !ok),
|
|
2748
|
+
v.back ? btn("Back", "quiet", flows.onboarding.back) : null
|
|
2749
|
+
],
|
|
2750
|
+
flows.onboarding.dismiss
|
|
2751
|
+
);
|
|
2752
|
+
}
|
|
2168
2753
|
if (v.type === "step")
|
|
2169
2754
|
return sheet(
|
|
2170
2755
|
[
|
|
2171
|
-
(0,
|
|
2756
|
+
(0, import_react2.createElement)(
|
|
2172
2757
|
RN.View,
|
|
2173
2758
|
{ style: { flexDirection: "row", alignItems: "center" } },
|
|
2174
2759
|
v.total > 1 ? muted(`Step ${v.index + 1} of ${v.total}`) : null,
|
|
2175
2760
|
close("Close the tour", flows.onboarding.dismiss)
|
|
2176
2761
|
),
|
|
2762
|
+
v.step.kind === "modal" && v.flow.icon ? (0, import_react2.createElement)(RN.View, { key: "icon" }, iconNode(v.flow.icon, 36, p.accent)) : null,
|
|
2763
|
+
media(v.step),
|
|
2177
2764
|
title(v.step.title),
|
|
2178
2765
|
v.step.body ? muted(v.step.body, { fontSize: 15 }) : null,
|
|
2179
2766
|
btn(v.step.button || (v.last ? "Done" : "Next"), "primary", flows.onboarding.next)
|
|
@@ -2182,11 +2769,11 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2182
2769
|
);
|
|
2183
2770
|
if (v.type === "checklist") {
|
|
2184
2771
|
const done = v.items.filter((i) => i.done).length;
|
|
2185
|
-
return (0,
|
|
2772
|
+
return (0, import_react2.createElement)(
|
|
2186
2773
|
RN.View,
|
|
2187
2774
|
{ pointerEvents: "box-none", style: { position: "absolute", left: 12, right: 12, bottom: 28 } },
|
|
2188
2775
|
card([
|
|
2189
|
-
(0,
|
|
2776
|
+
(0, import_react2.createElement)(
|
|
2190
2777
|
RN.View,
|
|
2191
2778
|
{ key: "t", style: { flexDirection: "row", alignItems: "center" } },
|
|
2192
2779
|
title(v.flow.name),
|
|
@@ -2194,17 +2781,19 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2194
2781
|
),
|
|
2195
2782
|
muted(`${done} of ${v.items.length} done`),
|
|
2196
2783
|
...v.items.map(
|
|
2197
|
-
({ step, done: d }) => (0,
|
|
2784
|
+
({ step, done: d, opens }) => (0, import_react2.createElement)(
|
|
2198
2785
|
RN.Pressable,
|
|
2199
2786
|
{
|
|
2200
2787
|
key: step.id,
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2788
|
+
// 0.17.0/0.18.0: a task that opens something (a tour, a modal, a screen, the app's code) does it;
|
|
2789
|
+
// a finished tour or modal ticks it, a screen or the app's code once opened (unless an event does).
|
|
2790
|
+
disabled: d || !!step.event && !opens,
|
|
2791
|
+
onPress: () => opens ? flows.onboarding.open(step.id) : flows.onboarding.check(step.id),
|
|
2792
|
+
accessibilityRole: opens && !d ? "button" : "checkbox",
|
|
2204
2793
|
accessibilityState: { checked: d },
|
|
2205
2794
|
style: { flexDirection: "row", gap: 10, alignItems: "flex-start", paddingVertical: 6 }
|
|
2206
2795
|
},
|
|
2207
|
-
(0,
|
|
2796
|
+
(0, import_react2.createElement)(
|
|
2208
2797
|
RN.View,
|
|
2209
2798
|
{
|
|
2210
2799
|
style: {
|
|
@@ -2220,7 +2809,8 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2220
2809
|
},
|
|
2221
2810
|
d ? text2("\u2713", { color: "#fff", fontSize: 12 }) : null
|
|
2222
2811
|
),
|
|
2223
|
-
(
|
|
2812
|
+
step.icon ? iconNode(step.icon, 20, p.accent) : null,
|
|
2813
|
+
(0, import_react2.createElement)(
|
|
2224
2814
|
RN.View,
|
|
2225
2815
|
{ style: { flex: 1 } },
|
|
2226
2816
|
text2(step.title, { fontWeight: "600", color: d ? p.muted : p.fg, textDecorationLine: d ? "line-through" : "none" }),
|
|
@@ -2233,14 +2823,14 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2233
2823
|
}
|
|
2234
2824
|
const m = v.message;
|
|
2235
2825
|
if (m.style === "banner")
|
|
2236
|
-
return (0,
|
|
2826
|
+
return (0, import_react2.createElement)(
|
|
2237
2827
|
RN.View,
|
|
2238
2828
|
{ pointerEvents: "box-none", style: { position: "absolute", left: 12, right: 12, top: 56 } },
|
|
2239
2829
|
card([
|
|
2240
|
-
(0,
|
|
2830
|
+
(0, import_react2.createElement)(
|
|
2241
2831
|
RN.View,
|
|
2242
2832
|
{ key: "t", style: { flexDirection: "row", alignItems: "center", gap: 8 } },
|
|
2243
|
-
(0,
|
|
2833
|
+
(0, import_react2.createElement)(RN.View, { style: { flex: 1 } }, text2(m.title, { fontWeight: "700" }), m.body ? muted(m.body) : null),
|
|
2244
2834
|
close("Dismiss", flows.message.dismiss)
|
|
2245
2835
|
),
|
|
2246
2836
|
m.button ? btn(m.button, "primary", flows.message.click) : null
|
|
@@ -2248,7 +2838,7 @@ var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
|
2248
2838
|
);
|
|
2249
2839
|
return sheet(
|
|
2250
2840
|
[
|
|
2251
|
-
(0,
|
|
2841
|
+
(0, import_react2.createElement)(RN.View, { key: "t", style: { flexDirection: "row" } }, close("Dismiss", flows.message.dismiss)),
|
|
2252
2842
|
title(m.title),
|
|
2253
2843
|
m.body ? muted(m.body, { fontSize: 15 }) : null,
|
|
2254
2844
|
m.button ? btn(m.button, "primary", flows.message.click) : null
|
|
@@ -2431,7 +3021,7 @@ var optionalModules = () => ({
|
|
|
2431
3021
|
});
|
|
2432
3022
|
|
|
2433
3023
|
// src/native/widgets-view.ts
|
|
2434
|
-
var
|
|
3024
|
+
var import_react3 = require("react");
|
|
2435
3025
|
var RN3 = require("react-native");
|
|
2436
3026
|
var usePalette = (appearance = {}) => {
|
|
2437
3027
|
const scheme = RN3.useColorScheme?.();
|
|
@@ -2439,10 +3029,10 @@ var usePalette = (appearance = {}) => {
|
|
|
2439
3029
|
return { ...dark ? DARK : LIGHT, accent: appearance.accent ?? "#3f76ff", danger: "#d92d20" };
|
|
2440
3030
|
};
|
|
2441
3031
|
var kit = (p) => {
|
|
2442
|
-
const text2 = (children, style = {}) => (0,
|
|
3032
|
+
const text2 = (children, style = {}) => (0, import_react3.createElement)(RN3.Text, { style: { color: p.fg, fontSize: 15, ...style } }, children);
|
|
2443
3033
|
const muted = (children, style = {}) => text2(children, { color: p.muted, fontSize: 13, ...style });
|
|
2444
|
-
const title = (children) => (0,
|
|
2445
|
-
const btn = (label, kind, onPress, disabled = false, style = {}) => (0,
|
|
3034
|
+
const title = (children) => (0, import_react3.createElement)(RN3.Text, { accessibilityRole: "header", style: { color: p.fg, fontSize: 17, fontWeight: "700", flex: 1 } }, children);
|
|
3035
|
+
const btn = (label, kind, onPress, disabled = false, style = {}) => (0, import_react3.createElement)(
|
|
2446
3036
|
RN3.Pressable,
|
|
2447
3037
|
{
|
|
2448
3038
|
key: label,
|
|
@@ -2465,8 +3055,8 @@ var kit = (p) => {
|
|
|
2465
3055
|
},
|
|
2466
3056
|
text2(label, { color: kind === "primary" ? "#ffffff" : p.fg, fontWeight: "600" })
|
|
2467
3057
|
);
|
|
2468
|
-
const closeX = (label, onPress) => (0,
|
|
2469
|
-
const field = (o) => (0,
|
|
3058
|
+
const closeX = (label, onPress) => (0, import_react3.createElement)(RN3.Pressable, { onPress, accessibilityRole: "button", accessibilityLabel: label, hitSlop: 12, style: { padding: 4 } }, text2("\xD7", { fontSize: 24, color: p.muted }));
|
|
3059
|
+
const field = (o) => (0, import_react3.createElement)(RN3.TextInput, {
|
|
2470
3060
|
value: o.value,
|
|
2471
3061
|
onChangeText: o.onChange,
|
|
2472
3062
|
placeholder: o.placeholder,
|
|
@@ -2489,7 +3079,7 @@ var kit = (p) => {
|
|
|
2489
3079
|
...o.style
|
|
2490
3080
|
}
|
|
2491
3081
|
});
|
|
2492
|
-
const chip = (label, on, onPress, key = label) => (0,
|
|
3082
|
+
const chip = (label, on, onPress, key = label) => (0, import_react3.createElement)(
|
|
2493
3083
|
RN3.Pressable,
|
|
2494
3084
|
{
|
|
2495
3085
|
key,
|
|
@@ -2500,13 +3090,13 @@ var kit = (p) => {
|
|
|
2500
3090
|
},
|
|
2501
3091
|
text2(label, { fontSize: 13, fontWeight: "600", color: on ? p.accent : p.fg })
|
|
2502
3092
|
);
|
|
2503
|
-
const page = (heading, onClose, children) => (0,
|
|
3093
|
+
const page = (heading, onClose, children) => (0, import_react3.createElement)(
|
|
2504
3094
|
RN3.Modal,
|
|
2505
3095
|
{ visible: true, animationType: "slide", presentationStyle: "pageSheet", onRequestClose: onClose },
|
|
2506
|
-
(0,
|
|
3096
|
+
(0, import_react3.createElement)(
|
|
2507
3097
|
RN3.KeyboardAvoidingView,
|
|
2508
3098
|
{ behavior: RN3.Platform.OS === "ios" ? "padding" : void 0, style: { flex: 1, backgroundColor: p.bg } },
|
|
2509
|
-
(0,
|
|
3099
|
+
(0, import_react3.createElement)(
|
|
2510
3100
|
RN3.View,
|
|
2511
3101
|
{ style: { flexDirection: "row", alignItems: "center", paddingHorizontal: 16, paddingTop: 16, paddingBottom: 12, borderBottomWidth: 1, borderBottomColor: p.line } },
|
|
2512
3102
|
title(heading),
|
|
@@ -2534,8 +3124,8 @@ var opener = () => {
|
|
|
2534
3124
|
listeners.forEach((l) => l(v));
|
|
2535
3125
|
};
|
|
2536
3126
|
const useOpen = () => {
|
|
2537
|
-
const [v, setV] = (0,
|
|
2538
|
-
(0,
|
|
3127
|
+
const [v, setV] = (0, import_react3.useState)(open);
|
|
3128
|
+
(0, import_react3.useEffect)(() => {
|
|
2539
3129
|
listeners.add(setV);
|
|
2540
3130
|
setV(open);
|
|
2541
3131
|
return () => {
|
|
@@ -2549,19 +3139,19 @@ var opener = () => {
|
|
|
2549
3139
|
var isAnswered = (a) => Array.isArray(a) ? a.length > 0 : typeof a === "number" ? true : !!a?.trim();
|
|
2550
3140
|
var SurveySheet = ({ survey, api, p, onDone }) => {
|
|
2551
3141
|
const k = kit(p);
|
|
2552
|
-
const [step, setStep] = (0,
|
|
2553
|
-
const [answers, setAnswers] = (0,
|
|
2554
|
-
const [done, setDone] = (0,
|
|
2555
|
-
const [error, setError] = (0,
|
|
2556
|
-
const started = (0,
|
|
2557
|
-
const finished = (0,
|
|
3142
|
+
const [step, setStep] = (0, import_react3.useState)(0);
|
|
3143
|
+
const [answers, setAnswers] = (0, import_react3.useState)({});
|
|
3144
|
+
const [done, setDone] = (0, import_react3.useState)(false);
|
|
3145
|
+
const [error, setError] = (0, import_react3.useState)("");
|
|
3146
|
+
const started = (0, import_react3.useRef)(Date.now());
|
|
3147
|
+
const finished = (0, import_react3.useRef)(false);
|
|
2558
3148
|
const q = survey.questions[step];
|
|
2559
3149
|
const last = step === survey.questions.length - 1;
|
|
2560
3150
|
const value = answers[q.key];
|
|
2561
|
-
(0,
|
|
3151
|
+
(0, import_react3.useEffect)(() => {
|
|
2562
3152
|
api.seen(survey.id).catch(() => void 0);
|
|
2563
3153
|
}, [api, survey.id]);
|
|
2564
|
-
(0,
|
|
3154
|
+
(0, import_react3.useEffect)(() => {
|
|
2565
3155
|
if (!done) return;
|
|
2566
3156
|
const t = setTimeout(onDone, 2500);
|
|
2567
3157
|
return () => clearTimeout(t);
|
|
@@ -2590,16 +3180,16 @@ var SurveySheet = ({ survey, api, p, onDone }) => {
|
|
|
2590
3180
|
if (q.kind === "nps" || q.kind === "rating") {
|
|
2591
3181
|
const scale = q.kind === "nps" ? 11 : Math.min(Math.max(q.scale ?? 5, 2), 10);
|
|
2592
3182
|
const start = q.kind === "nps" ? 0 : 1;
|
|
2593
|
-
input = (0,
|
|
3183
|
+
input = (0, import_react3.createElement)(
|
|
2594
3184
|
RN3.View,
|
|
2595
3185
|
{ style: { gap: 6 } },
|
|
2596
|
-
(0,
|
|
3186
|
+
(0, import_react3.createElement)(
|
|
2597
3187
|
RN3.View,
|
|
2598
3188
|
{ style: { flexDirection: "row", flexWrap: "wrap", gap: 6 }, accessibilityRole: "radiogroup", accessibilityLabel: q.title },
|
|
2599
3189
|
...Array.from({ length: scale }, (_, i) => {
|
|
2600
3190
|
const n = i + start;
|
|
2601
3191
|
const on = value === n;
|
|
2602
|
-
return (0,
|
|
3192
|
+
return (0, import_react3.createElement)(
|
|
2603
3193
|
RN3.Pressable,
|
|
2604
3194
|
{
|
|
2605
3195
|
key: n,
|
|
@@ -2613,17 +3203,17 @@ var SurveySheet = ({ survey, api, p, onDone }) => {
|
|
|
2613
3203
|
);
|
|
2614
3204
|
})
|
|
2615
3205
|
),
|
|
2616
|
-
q.low || q.high || q.kind === "nps" ? (0,
|
|
3206
|
+
q.low || q.high || q.kind === "nps" ? (0, import_react3.createElement)(RN3.View, { style: { flexDirection: "row", justifyContent: "space-between" } }, k.muted(q.low ?? (q.kind === "nps" ? "Not likely" : "")), k.muted(q.high ?? (q.kind === "nps" ? "Very likely" : ""))) : null
|
|
2617
3207
|
);
|
|
2618
3208
|
} else if (q.kind === "single" || q.kind === "multi") {
|
|
2619
3209
|
const multi = q.kind === "multi";
|
|
2620
3210
|
const picked = multi ? value ?? [] : [];
|
|
2621
|
-
input = (0,
|
|
3211
|
+
input = (0, import_react3.createElement)(
|
|
2622
3212
|
RN3.View,
|
|
2623
3213
|
{ style: { gap: 6 } },
|
|
2624
3214
|
...(q.options ?? []).map((o) => {
|
|
2625
3215
|
const on = multi ? picked.includes(o) : value === o;
|
|
2626
|
-
return (0,
|
|
3216
|
+
return (0, import_react3.createElement)(
|
|
2627
3217
|
RN3.Pressable,
|
|
2628
3218
|
{
|
|
2629
3219
|
key: o,
|
|
@@ -2638,26 +3228,26 @@ var SurveySheet = ({ survey, api, p, onDone }) => {
|
|
|
2638
3228
|
);
|
|
2639
3229
|
} else input = k.field({ value: value ?? "", onChange: pick, placeholder: q.placeholder ?? "Type your answer", multiline: true });
|
|
2640
3230
|
const body = done ? [k.text(survey.thanks || "Thanks for your feedback.", { fontWeight: "600", textAlign: "center", paddingVertical: 16 })] : [
|
|
2641
|
-
(0,
|
|
3231
|
+
(0, import_react3.createElement)(
|
|
2642
3232
|
RN3.View,
|
|
2643
3233
|
{ key: "top", style: { flexDirection: "row", alignItems: "center", gap: 4 } },
|
|
2644
|
-
...survey.questions.map((x, i) => (0,
|
|
2645
|
-
(0,
|
|
3234
|
+
...survey.questions.map((x, i) => (0, import_react3.createElement)(RN3.View, { key: x.key, style: { width: 16, height: 4, borderRadius: 4, backgroundColor: i <= step ? p.accent : p.line } })),
|
|
3235
|
+
(0, import_react3.createElement)(RN3.View, { style: { flex: 1 } }),
|
|
2646
3236
|
k.closeX("Close survey", dismiss)
|
|
2647
3237
|
),
|
|
2648
|
-
(0,
|
|
3238
|
+
(0, import_react3.createElement)(RN3.Text, { key: "q", accessibilityRole: "header", style: { color: p.fg, fontSize: 17, fontWeight: "700" } }, q.title, q.required ? "" : (0, import_react3.createElement)(RN3.Text, { style: { color: p.muted, fontSize: 13, fontWeight: "400" } }, " optional")),
|
|
2649
3239
|
q.description ? k.muted(q.description) : null,
|
|
2650
3240
|
input,
|
|
2651
3241
|
error ? k.text(error, { color: p.danger, fontSize: 13 }) : null,
|
|
2652
3242
|
k.btn(last ? "Send" : "Next", "primary", next)
|
|
2653
3243
|
];
|
|
2654
|
-
return (0,
|
|
3244
|
+
return (0, import_react3.createElement)(
|
|
2655
3245
|
RN3.Modal,
|
|
2656
3246
|
{ visible: true, transparent: true, animationType: "slide", onRequestClose: dismiss },
|
|
2657
|
-
(0,
|
|
3247
|
+
(0, import_react3.createElement)(
|
|
2658
3248
|
RN3.KeyboardAvoidingView,
|
|
2659
3249
|
{ behavior: RN3.Platform.OS === "ios" ? "padding" : void 0, style: { flex: 1, backgroundColor: "rgba(0,0,0,0.35)", justifyContent: "flex-end" } },
|
|
2660
|
-
(0,
|
|
3250
|
+
(0, import_react3.createElement)(
|
|
2661
3251
|
RN3.View,
|
|
2662
3252
|
{
|
|
2663
3253
|
accessibilityViewIsModal: true,
|
|
@@ -2671,10 +3261,10 @@ var SurveySheet = ({ survey, api, p, onDone }) => {
|
|
|
2671
3261
|
};
|
|
2672
3262
|
var MRRocketSurveys = ({ client, appearance }) => {
|
|
2673
3263
|
const p = usePalette(appearance);
|
|
2674
|
-
const [survey, setSurvey] = (0,
|
|
2675
|
-
const [
|
|
2676
|
-
(0,
|
|
2677
|
-
(0,
|
|
3264
|
+
const [survey, setSurvey] = (0, import_react3.useState)(null);
|
|
3265
|
+
const [who2, setWho] = (0, import_react3.useState)(() => client.getDistinctId());
|
|
3266
|
+
(0, import_react3.useEffect)(() => client.subscribe(() => setWho(client.getDistinctId())), [client]);
|
|
3267
|
+
(0, import_react3.useEffect)(() => {
|
|
2678
3268
|
let stop = false;
|
|
2679
3269
|
const ctrl = new AbortController();
|
|
2680
3270
|
const timer = setTimeout(() => {
|
|
@@ -2693,34 +3283,34 @@ var MRRocketSurveys = ({ client, appearance }) => {
|
|
|
2693
3283
|
clearTimeout(timer);
|
|
2694
3284
|
ctrl.abort();
|
|
2695
3285
|
};
|
|
2696
|
-
}, [client,
|
|
2697
|
-
const done = (0,
|
|
3286
|
+
}, [client, who2]);
|
|
3287
|
+
const done = (0, import_react3.useCallback)(() => {
|
|
2698
3288
|
setSurvey((cur) => {
|
|
2699
3289
|
if (cur) client.markSurveyDone(cur.s.id);
|
|
2700
3290
|
return null;
|
|
2701
3291
|
});
|
|
2702
3292
|
}, [client]);
|
|
2703
3293
|
if (!survey) return null;
|
|
2704
|
-
return (0,
|
|
3294
|
+
return (0, import_react3.createElement)(SurveySheet, { key: survey.s.id, survey: survey.s, api: survey.api, p, onDone: done });
|
|
2705
3295
|
};
|
|
2706
3296
|
var feedbackOpen = opener();
|
|
2707
3297
|
var useFeedback = () => ({ open: () => feedbackOpen.set(true), close: () => feedbackOpen.set(false) });
|
|
2708
3298
|
var FeedbackSheet = ({ client, p, title }) => {
|
|
2709
3299
|
const k = kit(p);
|
|
2710
|
-
const [tab, setTab] = (0,
|
|
2711
|
-
const [posts, setPosts] = (0,
|
|
2712
|
-
const [boards, setBoards] = (0,
|
|
2713
|
-
const [error, setError] = (0,
|
|
2714
|
-
const [board, setBoard] = (0,
|
|
2715
|
-
const [subject, setSubject] = (0,
|
|
2716
|
-
const [details, setDetails] = (0,
|
|
2717
|
-
const [name, setName] = (0,
|
|
2718
|
-
const [email, setEmail] = (0,
|
|
2719
|
-
const [sending, setSending] = (0,
|
|
2720
|
-
const [sent, setSent] = (0,
|
|
3300
|
+
const [tab, setTab] = (0, import_react3.useState)("top");
|
|
3301
|
+
const [posts, setPosts] = (0, import_react3.useState)(null);
|
|
3302
|
+
const [boards, setBoards] = (0, import_react3.useState)([]);
|
|
3303
|
+
const [error, setError] = (0, import_react3.useState)("");
|
|
3304
|
+
const [board, setBoard] = (0, import_react3.useState)("feature");
|
|
3305
|
+
const [subject, setSubject] = (0, import_react3.useState)("");
|
|
3306
|
+
const [details, setDetails] = (0, import_react3.useState)("");
|
|
3307
|
+
const [name, setName] = (0, import_react3.useState)("");
|
|
3308
|
+
const [email, setEmail] = (0, import_react3.useState)("");
|
|
3309
|
+
const [sending, setSending] = (0, import_react3.useState)(false);
|
|
3310
|
+
const [sent, setSent] = (0, import_react3.useState)(false);
|
|
2721
3311
|
const close = () => feedbackOpen.set(false);
|
|
2722
3312
|
const user = client.getUser();
|
|
2723
|
-
(0,
|
|
3313
|
+
(0, import_react3.useEffect)(() => {
|
|
2724
3314
|
const api = client.api();
|
|
2725
3315
|
if (!api) return setError("Feedback is off while tracking is off.");
|
|
2726
3316
|
const ctrl = new AbortController();
|
|
@@ -2752,7 +3342,7 @@ var FeedbackSheet = ({ client, p, title }) => {
|
|
|
2752
3342
|
setSent(true);
|
|
2753
3343
|
}).catch((e) => setError(e.message)).finally(() => setSending(false));
|
|
2754
3344
|
};
|
|
2755
|
-
const tabs = (0,
|
|
3345
|
+
const tabs = (0, import_react3.createElement)(
|
|
2756
3346
|
RN3.View,
|
|
2757
3347
|
{ style: { flexDirection: "row", gap: 8, paddingHorizontal: 16, paddingTop: 12 } },
|
|
2758
3348
|
k.chip("Top requests", tab === "top", () => setTab("top")),
|
|
@@ -2761,17 +3351,17 @@ var FeedbackSheet = ({ client, p, title }) => {
|
|
|
2761
3351
|
setSent(false);
|
|
2762
3352
|
})
|
|
2763
3353
|
);
|
|
2764
|
-
const list = (0,
|
|
3354
|
+
const list = (0, import_react3.createElement)(
|
|
2765
3355
|
RN3.ScrollView,
|
|
2766
3356
|
{ style: { flex: 1 }, contentContainerStyle: { padding: 16, gap: 10 } },
|
|
2767
3357
|
error ? k.text(error, { color: p.danger, fontSize: 13 }) : null,
|
|
2768
3358
|
posts === null && !error ? k.muted("Loading\u2026") : null,
|
|
2769
3359
|
posts?.length === 0 ? k.muted("No requests yet. Be the first to suggest one.") : null,
|
|
2770
3360
|
...(posts ?? []).map(
|
|
2771
|
-
(post) => (0,
|
|
3361
|
+
(post) => (0, import_react3.createElement)(
|
|
2772
3362
|
RN3.View,
|
|
2773
3363
|
{ key: post.id, style: { flexDirection: "row", gap: 12, alignItems: "flex-start", paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: p.line } },
|
|
2774
|
-
(0,
|
|
3364
|
+
(0, import_react3.createElement)(
|
|
2775
3365
|
RN3.Pressable,
|
|
2776
3366
|
{
|
|
2777
3367
|
onPress: () => vote(post),
|
|
@@ -2783,15 +3373,15 @@ var FeedbackSheet = ({ client, p, title }) => {
|
|
|
2783
3373
|
k.text("\u25B2", { fontSize: 11, color: post.voted ? p.accent : p.muted }),
|
|
2784
3374
|
k.text(String(post.votes), { fontWeight: "700", fontSize: 14, color: post.voted ? p.accent : p.fg })
|
|
2785
3375
|
),
|
|
2786
|
-
(0,
|
|
3376
|
+
(0, import_react3.createElement)(RN3.View, { style: { flex: 1, gap: 2 } }, k.text(post.title, { fontWeight: "600" }), post.body ? k.muted(post.body.slice(0, 160)) : null)
|
|
2787
3377
|
)
|
|
2788
3378
|
)
|
|
2789
3379
|
);
|
|
2790
|
-
const form = (0,
|
|
3380
|
+
const form = (0, import_react3.createElement)(
|
|
2791
3381
|
RN3.ScrollView,
|
|
2792
3382
|
{ style: { flex: 1 }, contentContainerStyle: { padding: 16, gap: 10 }, keyboardShouldPersistTaps: "handled" },
|
|
2793
3383
|
sent ? k.text("Thanks! Your request is on the board.", { fontWeight: "600" }) : null,
|
|
2794
|
-
boards.length > 1 ? (0,
|
|
3384
|
+
boards.length > 1 ? (0, import_react3.createElement)(RN3.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: 6 } }, ...boards.map((b) => k.chip(b.label, board === b.id, () => setBoard(b.id), b.id))) : null,
|
|
2795
3385
|
k.field({ value: subject, onChange: setSubject, placeholder: "Short title", max: 120 }),
|
|
2796
3386
|
k.field({ value: details, onChange: setDetails, placeholder: "Details (optional)", multiline: true }),
|
|
2797
3387
|
...user?.email ? [] : [
|
|
@@ -2807,7 +3397,7 @@ var FeedbackSheet = ({ client, p, title }) => {
|
|
|
2807
3397
|
var MRRocketFeedback = ({ client, appearance, options = {} }) => {
|
|
2808
3398
|
const p = usePalette(appearance);
|
|
2809
3399
|
const open = feedbackOpen.useOpen();
|
|
2810
|
-
return open ? (0,
|
|
3400
|
+
return open ? (0, import_react3.createElement)(FeedbackSheet, { client, p, title: options.title ?? "Feedback" }) : null;
|
|
2811
3401
|
};
|
|
2812
3402
|
var POLL_OPEN_MS = 4e3;
|
|
2813
3403
|
var POLL_WAITING_MS = 8e3;
|
|
@@ -2815,6 +3405,7 @@ var POLL_IDLE_MS = 3e4;
|
|
|
2815
3405
|
var WAITING_FOR_MS = 10 * 6e4;
|
|
2816
3406
|
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
|
|
2817
3407
|
var whoLabel = { visitor: "You", team: "Team", ai: "AI agent", auto: "Team" };
|
|
3408
|
+
var who = (from, agentName) => from === "ai" && agentName?.trim() || whoLabel[from];
|
|
2818
3409
|
var msgView = "home";
|
|
2819
3410
|
var messengerOpen = opener();
|
|
2820
3411
|
var openAt = (v = "home") => {
|
|
@@ -2846,11 +3437,11 @@ try {
|
|
|
2846
3437
|
}
|
|
2847
3438
|
var PHOTO_TYPES = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", webp: "image/webp", gif: "image/gif" };
|
|
2848
3439
|
var teamOf = (t) => (t?.messages ?? []).filter((m) => m.from !== "visitor");
|
|
2849
|
-
var
|
|
3440
|
+
var svg2 = null;
|
|
2850
3441
|
try {
|
|
2851
|
-
|
|
3442
|
+
svg2 = require("react-native-svg");
|
|
2852
3443
|
} catch {
|
|
2853
|
-
|
|
3444
|
+
svg2 = null;
|
|
2854
3445
|
}
|
|
2855
3446
|
var GLYPH = {
|
|
2856
3447
|
chat: "M2.5 4.5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v4.5a2 2 0 0 1-2 2H7l-3 2.5V11a2 2 0 0 1-1.5-2z",
|
|
@@ -2865,15 +3456,15 @@ var GLYPH = {
|
|
|
2865
3456
|
};
|
|
2866
3457
|
var FALLBACK = { chat: "\u{1F4AC}", home: "\u2302", help: "?", send: "\u2192", up: "\u2191", next: "\u203A", search: "\u2315", cross: "\xD7", clip: "\u{1F4CE}" };
|
|
2867
3458
|
var glyph = (name, color, size = 20) => {
|
|
2868
|
-
const Svg =
|
|
2869
|
-
if (!
|
|
2870
|
-
return (0,
|
|
3459
|
+
const Svg = svg2?.Svg ?? svg2?.default;
|
|
3460
|
+
if (!svg2 || !Svg) return (0, import_react3.createElement)(RN3.Text, { style: { color, fontSize: Math.round(size * 0.85), lineHeight: size + 2, textAlign: "center", minWidth: size } }, FALLBACK[name]);
|
|
3461
|
+
return (0, import_react3.createElement)(Svg, { width: size, height: size, viewBox: "0 0 16 16", fill: "none" }, (0, import_react3.createElement)(svg2.Path, { d: GLYPH[name], stroke: color, strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }));
|
|
2871
3462
|
};
|
|
2872
3463
|
var alpha = (hex, a) => /^#[0-9a-f]{6}$/i.test(hex) ? `${hex}${Math.round(a * 255).toString(16).padStart(2, "0")}` : hex;
|
|
2873
|
-
var teamMark = (title, bg, fg, size = 36) => (0,
|
|
3464
|
+
var teamMark = (title, bg, fg, size = 36) => (0, import_react3.createElement)(
|
|
2874
3465
|
RN3.View,
|
|
2875
3466
|
{ style: { width: size, height: size, borderRadius: size / 2, backgroundColor: bg, alignItems: "center", justifyContent: "center" } },
|
|
2876
|
-
(0,
|
|
3467
|
+
(0, import_react3.createElement)(RN3.Text, { style: { color: fg, fontSize: Math.round(size * 0.42), fontWeight: "700" } }, (title.trim()[0] ?? "?").toUpperCase())
|
|
2877
3468
|
);
|
|
2878
3469
|
var HU = {
|
|
2879
3470
|
light: { bg: "#ffffff", surface: "#f4f4f5", def: "#ececee", segment: "#ffffff", fg: "#18181b", muted: "#71717a" },
|
|
@@ -2881,20 +3472,20 @@ var HU = {
|
|
|
2881
3472
|
};
|
|
2882
3473
|
var hairline = { shadowColor: "#000", shadowOpacity: 0.07, shadowRadius: 3, shadowOffset: { width: 0, height: 1 }, elevation: 1 };
|
|
2883
3474
|
var useChat = (client, o, open, view) => {
|
|
2884
|
-
const [thread, setThread] = (0,
|
|
2885
|
-
const [loaded, setLoaded] = (0,
|
|
2886
|
-
const [error, setError] = (0,
|
|
2887
|
-
const [unseen, setUnseen] = (0,
|
|
2888
|
-
const known = (0,
|
|
3475
|
+
const [thread, setThread] = (0, import_react3.useState)(null);
|
|
3476
|
+
const [loaded, setLoaded] = (0, import_react3.useState)(false);
|
|
3477
|
+
const [error, setError] = (0, import_react3.useState)("");
|
|
3478
|
+
const [unseen, setUnseen] = (0, import_react3.useState)([]);
|
|
3479
|
+
const known = (0, import_react3.useRef)(null);
|
|
2889
3480
|
const watching = open && view === "messages";
|
|
2890
|
-
const watch = (0,
|
|
3481
|
+
const watch = (0, import_react3.useRef)(watching);
|
|
2891
3482
|
watch.current = watching;
|
|
2892
|
-
const [active, setActive] = (0,
|
|
2893
|
-
(0,
|
|
3483
|
+
const [active, setActive] = (0, import_react3.useState)(RN3.AppState.currentState === "active");
|
|
3484
|
+
(0, import_react3.useEffect)(() => {
|
|
2894
3485
|
const sub = RN3.AppState.addEventListener("change", (st) => setActive(st === "active"));
|
|
2895
3486
|
return () => sub.remove();
|
|
2896
3487
|
}, []);
|
|
2897
|
-
const take = (0,
|
|
3488
|
+
const take = (0, import_react3.useCallback)(
|
|
2898
3489
|
(t) => {
|
|
2899
3490
|
const team = teamOf(t);
|
|
2900
3491
|
if (known.current !== null) {
|
|
@@ -2910,10 +3501,10 @@ var useChat = (client, o, open, view) => {
|
|
|
2910
3501
|
},
|
|
2911
3502
|
[o.haptics]
|
|
2912
3503
|
);
|
|
2913
|
-
(0,
|
|
3504
|
+
(0, import_react3.useEffect)(() => {
|
|
2914
3505
|
if (watching) setUnseen([]);
|
|
2915
3506
|
}, [watching]);
|
|
2916
|
-
(0,
|
|
3507
|
+
(0, import_react3.useEffect)(() => {
|
|
2917
3508
|
if (!active) return;
|
|
2918
3509
|
let stop = false;
|
|
2919
3510
|
let timer;
|
|
@@ -2953,9 +3544,9 @@ var useChat = (client, o, open, view) => {
|
|
|
2953
3544
|
return { thread, loaded, error, setError, unseen, take };
|
|
2954
3545
|
};
|
|
2955
3546
|
var useArticles = (client, on, query) => {
|
|
2956
|
-
const [list, setList] = (0,
|
|
2957
|
-
const [any, setAny] = (0,
|
|
2958
|
-
(0,
|
|
3547
|
+
const [list, setList] = (0, import_react3.useState)(null);
|
|
3548
|
+
const [any, setAny] = (0, import_react3.useState)(null);
|
|
3549
|
+
(0, import_react3.useEffect)(() => {
|
|
2959
3550
|
if (!on) return;
|
|
2960
3551
|
let stop = false;
|
|
2961
3552
|
const t = setTimeout(
|
|
@@ -2976,7 +3567,7 @@ var useArticles = (client, on, query) => {
|
|
|
2976
3567
|
return { list, any };
|
|
2977
3568
|
};
|
|
2978
3569
|
var spansOf = (p, spans, base) => spans.map(
|
|
2979
|
-
(s, i) => (0,
|
|
3570
|
+
(s, i) => (0, import_react3.createElement)(
|
|
2980
3571
|
RN3.Text,
|
|
2981
3572
|
{
|
|
2982
3573
|
key: i,
|
|
@@ -2995,10 +3586,10 @@ var spansOf = (p, spans, base) => spans.map(
|
|
|
2995
3586
|
);
|
|
2996
3587
|
var ArticleView = ({ client, p, id, onAsk }) => {
|
|
2997
3588
|
const k = kit(p);
|
|
2998
|
-
const [a, setA] = (0,
|
|
2999
|
-
const [error, setError] = (0,
|
|
3000
|
-
const [rated, setRated] = (0,
|
|
3001
|
-
(0,
|
|
3589
|
+
const [a, setA] = (0, import_react3.useState)(null);
|
|
3590
|
+
const [error, setError] = (0, import_react3.useState)("");
|
|
3591
|
+
const [rated, setRated] = (0, import_react3.useState)(false);
|
|
3592
|
+
(0, import_react3.useEffect)(() => {
|
|
3002
3593
|
const ctrl = new AbortController();
|
|
3003
3594
|
client.api()?.article(id, ctrl.signal).then(setA).catch((e) => e.name !== "AbortError" && setError(e.message));
|
|
3004
3595
|
return () => ctrl.abort();
|
|
@@ -3007,30 +3598,30 @@ var ArticleView = ({ client, p, id, onAsk }) => {
|
|
|
3007
3598
|
if (!a) return k.muted("Loading\u2026");
|
|
3008
3599
|
const base = { color: p.fg, fontSize: 15, lineHeight: 22 };
|
|
3009
3600
|
const blocks = a.blocks.map((b, i) => {
|
|
3010
|
-
if (b.type === "h2" || b.type === "h3") return (0,
|
|
3011
|
-
if (b.type === "p") return (0,
|
|
3012
|
-
if (b.type === "quote") return (0,
|
|
3601
|
+
if (b.type === "h2" || b.type === "h3") return (0, import_react3.createElement)(RN3.Text, { key: i, accessibilityRole: "header", style: { ...base, fontSize: b.type === "h2" ? 17 : 16, fontWeight: "700", marginTop: 8 } }, ...spansOf(p, b.spans, {}));
|
|
3602
|
+
if (b.type === "p") return (0, import_react3.createElement)(RN3.Text, { key: i, style: base }, ...spansOf(p, b.spans, {}));
|
|
3603
|
+
if (b.type === "quote") return (0, import_react3.createElement)(RN3.View, { key: i, style: { borderLeftWidth: 3, borderLeftColor: p.line, paddingLeft: 10 } }, (0, import_react3.createElement)(RN3.Text, { style: { ...base, color: p.muted } }, ...spansOf(p, b.spans, {})));
|
|
3013
3604
|
if (b.type === "ul" || b.type === "ol")
|
|
3014
|
-
return (0,
|
|
3605
|
+
return (0, import_react3.createElement)(
|
|
3015
3606
|
RN3.View,
|
|
3016
3607
|
{ key: i, style: { gap: 4 } },
|
|
3017
|
-
...b.items.map((it, j) => (0,
|
|
3608
|
+
...b.items.map((it, j) => (0, import_react3.createElement)(RN3.View, { key: j, style: { flexDirection: "row", gap: 8 } }, k.text(b.type === "ol" ? `${j + 1}.` : "\u2022", base), (0, import_react3.createElement)(RN3.Text, { style: { ...base, flex: 1 } }, ...spansOf(p, it, {}))))
|
|
3018
3609
|
);
|
|
3019
|
-
if (b.type === "code") return (0,
|
|
3020
|
-
return (0,
|
|
3610
|
+
if (b.type === "code") return (0, import_react3.createElement)(RN3.View, { key: i, style: { backgroundColor: p.soft, borderRadius: 8, padding: 10 } }, k.text(b.text, { fontFamily: RN3.Platform.OS === "ios" ? "Menlo" : "monospace", fontSize: 13 }));
|
|
3611
|
+
return (0, import_react3.createElement)(RN3.View, { key: i, style: { height: 1, backgroundColor: p.line } });
|
|
3021
3612
|
});
|
|
3022
3613
|
const rate = (helpful) => {
|
|
3023
3614
|
setRated(true);
|
|
3024
3615
|
client.api()?.rateArticle(id, helpful).catch(() => void 0);
|
|
3025
3616
|
if (!helpful) onAsk();
|
|
3026
3617
|
};
|
|
3027
|
-
return (0,
|
|
3618
|
+
return (0, import_react3.createElement)(
|
|
3028
3619
|
RN3.View,
|
|
3029
3620
|
{ style: { gap: 10 } },
|
|
3030
3621
|
k.muted(a.collection),
|
|
3031
|
-
(0,
|
|
3622
|
+
(0, import_react3.createElement)(RN3.Text, { accessibilityRole: "header", style: { color: p.fg, fontSize: 20, fontWeight: "700" } }, a.title),
|
|
3032
3623
|
...blocks,
|
|
3033
|
-
(0,
|
|
3624
|
+
(0, import_react3.createElement)(
|
|
3034
3625
|
RN3.View,
|
|
3035
3626
|
{ style: { flexDirection: "row", alignItems: "center", gap: 8, padding: 12, borderRadius: 10, backgroundColor: p.soft, marginTop: 8 } },
|
|
3036
3627
|
rated ? k.muted("Thanks for letting us know.") : k.muted("Did this answer your question?", { flex: 1 }),
|
|
@@ -3050,19 +3641,26 @@ var MessengerSheet = ({
|
|
|
3050
3641
|
brand
|
|
3051
3642
|
}) => {
|
|
3052
3643
|
const k = kit(p);
|
|
3053
|
-
const [body, setBody] = (0,
|
|
3054
|
-
const [email, setEmail] = (0,
|
|
3055
|
-
const [pending, setPending] = (0,
|
|
3056
|
-
const [
|
|
3057
|
-
|
|
3644
|
+
const [body, setBody] = (0, import_react3.useState)("");
|
|
3645
|
+
const [email, setEmail] = (0, import_react3.useState)("");
|
|
3646
|
+
const [pending, setPending] = (0, import_react3.useState)(null);
|
|
3647
|
+
const [slow, setSlow] = (0, import_react3.useState)(false);
|
|
3648
|
+
(0, import_react3.useEffect)(() => {
|
|
3649
|
+
setSlow(false);
|
|
3650
|
+
if (!pending) return;
|
|
3651
|
+
const t = setTimeout(() => setSlow(true), 1500);
|
|
3652
|
+
return () => clearTimeout(t);
|
|
3653
|
+
}, [pending]);
|
|
3654
|
+
const [photos, setPhotos] = (0, import_react3.useState)([]);
|
|
3655
|
+
const [query, setQuery] = (0, import_react3.useState)("");
|
|
3058
3656
|
const helpOn = o.help !== false;
|
|
3059
3657
|
const arts = useArticles(client, helpOn, query);
|
|
3060
|
-
const scroll = (0,
|
|
3658
|
+
const scroll = (0, import_react3.useRef)(null);
|
|
3061
3659
|
const close = () => messengerOpen.set(false);
|
|
3062
3660
|
const greeting = o.greeting ?? "Hi! How can we help?";
|
|
3063
3661
|
const { thread } = chat;
|
|
3064
3662
|
const count = (thread?.messages.length ?? 0) + (pending ? 1 : 0);
|
|
3065
|
-
(0,
|
|
3663
|
+
(0, import_react3.useEffect)(() => {
|
|
3066
3664
|
if (view === "messages") setTimeout(() => scroll.current?.scrollToEnd?.({ animated: true }), 50);
|
|
3067
3665
|
}, [count, view]);
|
|
3068
3666
|
const needEmail = (o.askEmail ?? true) && !thread?.hasEmail && !client.getUser()?.email;
|
|
@@ -3145,7 +3743,7 @@ var MessengerSheet = ({
|
|
|
3145
3743
|
setPending(null);
|
|
3146
3744
|
}
|
|
3147
3745
|
};
|
|
3148
|
-
const localUris = (0,
|
|
3746
|
+
const localUris = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
3149
3747
|
for (const f of photos) localUris.current.set(f.key, f.uri);
|
|
3150
3748
|
const fileUrl = (id) => localUris.current.get(id) ?? client.api()?.attachmentUrl(id) ?? "";
|
|
3151
3749
|
const ink = inkOn(p.accent);
|
|
@@ -3160,11 +3758,11 @@ var MessengerSheet = ({
|
|
|
3160
3758
|
const title = o.title?.trim() ?? "";
|
|
3161
3759
|
const bubble = (m, isPending = false) => {
|
|
3162
3760
|
const mine = m.from === "visitor";
|
|
3163
|
-
return (0,
|
|
3761
|
+
return (0, import_react3.createElement)(
|
|
3164
3762
|
RN3.View,
|
|
3165
3763
|
{ key: m.id, style: { alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "82%", gap: 4 } },
|
|
3166
3764
|
...(m.attachments ?? []).map(
|
|
3167
|
-
(f) => (0,
|
|
3765
|
+
(f) => (0, import_react3.createElement)(
|
|
3168
3766
|
RN3.Pressable,
|
|
3169
3767
|
{
|
|
3170
3768
|
key: f.id,
|
|
@@ -3173,10 +3771,10 @@ var MessengerSheet = ({
|
|
|
3173
3771
|
accessibilityLabel: f.name,
|
|
3174
3772
|
style: { alignSelf: mine ? "flex-end" : "flex-start", opacity: isPending ? 0.7 : 1 }
|
|
3175
3773
|
},
|
|
3176
|
-
f.type.startsWith("image/") ? (0,
|
|
3774
|
+
f.type.startsWith("image/") ? (0, import_react3.createElement)(RN3.Image, { source: { uri: fileUrl(f.id) }, resizeMode: "cover", style: { width: 200, height: 150, borderRadius: r.bubble, backgroundColor: p.soft } }) : (0, import_react3.createElement)(RN3.View, { style: { backgroundColor: p.soft, borderRadius: r.card, paddingHorizontal: 10, paddingVertical: 7 } }, k.text(`\u{1F4C4} ${f.name}`, { fontSize: 13 }))
|
|
3177
3775
|
)
|
|
3178
3776
|
),
|
|
3179
|
-
!m.body && m.attachments?.length ? null : (0,
|
|
3777
|
+
!m.body && m.attachments?.length ? null : (0, import_react3.createElement)(
|
|
3180
3778
|
RN3.View,
|
|
3181
3779
|
{
|
|
3182
3780
|
style: {
|
|
@@ -3193,23 +3791,23 @@ var MessengerSheet = ({
|
|
|
3193
3791
|
k.text(m.body, { color: mine ? ink : hu.fg })
|
|
3194
3792
|
),
|
|
3195
3793
|
...(m.articles ?? []).map(
|
|
3196
|
-
(a) => (0,
|
|
3794
|
+
(a) => (0, import_react3.createElement)(
|
|
3197
3795
|
RN3.Pressable,
|
|
3198
3796
|
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "link", style: { backgroundColor: p.soft, borderRadius: r.card, paddingHorizontal: 10, paddingVertical: 7 } },
|
|
3199
3797
|
k.text(`\u{1F4C4} ${a.title}`, { fontSize: 13 })
|
|
3200
3798
|
)
|
|
3201
3799
|
),
|
|
3202
|
-
m.at ? k.muted(`${mine ? "" : `${
|
|
3800
|
+
m.at ? k.muted(`${mine ? "" : `${who(m.from, o.agentName)} \xB7 `}${isPending && slow ? "Sending\u2026" : timeAgo(m.at)}`, { fontSize: 11, textAlign: mine ? "right" : "left", paddingHorizontal: 6 }) : null
|
|
3203
3801
|
);
|
|
3204
3802
|
};
|
|
3205
|
-
const row = (a) => (0,
|
|
3803
|
+
const row = (a) => (0, import_react3.createElement)(
|
|
3206
3804
|
RN3.Pressable,
|
|
3207
3805
|
{ key: a.id, onPress: () => setView({ article: a.id }), accessibilityRole: "button", style: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 11, paddingHorizontal: 8 } },
|
|
3208
3806
|
k.text(a.title, { flex: 1 }),
|
|
3209
3807
|
glyph("next", p.accent, 14)
|
|
3210
3808
|
);
|
|
3211
|
-
const card = (children, style = {}) => (0,
|
|
3212
|
-
const searchRow = (onPress) => (0,
|
|
3809
|
+
const card = (children, style = {}) => (0, import_react3.createElement)(RN3.View, { style: { backgroundColor: raised, borderRadius: r.card, padding: 16, ...surf, ...style } }, ...children);
|
|
3810
|
+
const searchRow = (onPress) => (0, import_react3.createElement)(
|
|
3213
3811
|
RN3.Pressable,
|
|
3214
3812
|
{ key: "s", onPress, accessibilityRole: "search", style: { flexDirection: "row", alignItems: "center", height: 44, borderRadius: r.field, paddingHorizontal: 14, backgroundColor: hu.def } },
|
|
3215
3813
|
k.muted("Search for help", { flex: 1, fontSize: 15 }),
|
|
@@ -3218,12 +3816,12 @@ var MessengerSheet = ({
|
|
|
3218
3816
|
const search = k.field({ value: query, onChange: setQuery, placeholder: "Search for help", max: 200, style: { borderWidth: 0, borderRadius: r.field, backgroundColor: raised, ...surf } });
|
|
3219
3817
|
const first = client.getUser()?.name?.trim().split(/\s+/)[0];
|
|
3220
3818
|
const rest = greeting.replace(/^(hi|hello|hey|hallo)( there)?\s*[!,.]*\s*/i, "").trim() || "How can we help you today?";
|
|
3221
|
-
const hero = (fg, sub) => (0,
|
|
3819
|
+
const hero = (fg, sub) => (0, import_react3.createElement)(
|
|
3222
3820
|
RN3.Text,
|
|
3223
3821
|
{ key: "hero", accessibilityRole: "header", style: { color: fg, fontSize: 25, fontWeight: "600", letterSpacing: -0.6, lineHeight: 30 } },
|
|
3224
3822
|
first ? `Hi, ${first} \u{1F44B}
|
|
3225
3823
|
` : "Hi there \u{1F44B}\n",
|
|
3226
|
-
(0,
|
|
3824
|
+
(0, import_react3.createElement)(RN3.Text, { style: { color: sub, fontWeight: "500" } }, rest)
|
|
3227
3825
|
);
|
|
3228
3826
|
const last = thread?.messages.at(-1);
|
|
3229
3827
|
const showHelp = helpOn && arts.any !== false;
|
|
@@ -3231,11 +3829,11 @@ var MessengerSheet = ({
|
|
|
3231
3829
|
if (view === "home") {
|
|
3232
3830
|
const cards = [
|
|
3233
3831
|
// "Ask a question": the words go into the chat's field and are sent as the chat opens.
|
|
3234
|
-
(0,
|
|
3832
|
+
(0, import_react3.createElement)(
|
|
3235
3833
|
RN3.View,
|
|
3236
3834
|
{ key: "ask", style: { flexDirection: "row", alignItems: "center", gap: 8, height: 48, borderRadius: 24, paddingLeft: 18, paddingRight: 6, backgroundColor: hu.surface, ...surf } },
|
|
3237
3835
|
k.field({ value: body, onChange: setBody, placeholder: "Ask a question", max: 4e3, style: { flex: 1, borderWidth: 0, paddingHorizontal: 0, backgroundColor: "transparent" } }),
|
|
3238
|
-
(0,
|
|
3836
|
+
(0, import_react3.createElement)(
|
|
3239
3837
|
RN3.Pressable,
|
|
3240
3838
|
{
|
|
3241
3839
|
onPress: () => {
|
|
@@ -3249,60 +3847,60 @@ var MessengerSheet = ({
|
|
|
3249
3847
|
glyph("up", body.trim() ? ink : hu.muted, 18)
|
|
3250
3848
|
)
|
|
3251
3849
|
),
|
|
3252
|
-
last ? (0,
|
|
3850
|
+
last ? (0, import_react3.createElement)(
|
|
3253
3851
|
RN3.Pressable,
|
|
3254
3852
|
{ key: "recent", onPress: () => setView("messages"), accessibilityRole: "button" },
|
|
3255
3853
|
card([
|
|
3256
|
-
(0,
|
|
3854
|
+
(0, import_react3.createElement)(
|
|
3257
3855
|
RN3.View,
|
|
3258
3856
|
{ key: "r", style: { flexDirection: "row", alignItems: "center", gap: 10 } },
|
|
3259
3857
|
title ? teamMark(title, alpha(p.accent, 0.16), p.accent, 26) : null,
|
|
3260
|
-
(0,
|
|
3261
|
-
chat.unseen.length ? (0,
|
|
3858
|
+
(0, import_react3.createElement)(RN3.View, { style: { flex: 1, gap: 1 } }, (0, import_react3.createElement)(RN3.Text, { numberOfLines: 1, style: { color: hu.fg, fontSize: 14, fontWeight: "500" } }, last.body || (last.attachments?.length ? `Sent ${last.attachments.length === 1 ? last.attachments[0].name : `${last.attachments.length} files`}` : "")), k.muted(`${last.from === "visitor" ? "You" : who(last.from, o.agentName)} \xB7 ${timeAgo(last.at)}`, { fontSize: 11.5 })),
|
|
3859
|
+
chat.unseen.length ? (0, import_react3.createElement)(RN3.View, { style: { width: 8, height: 8, borderRadius: 4, backgroundColor: p.danger } }) : glyph("next", p.muted, 14)
|
|
3262
3860
|
)
|
|
3263
3861
|
], { paddingVertical: 10, paddingHorizontal: 12 })
|
|
3264
3862
|
) : null,
|
|
3265
3863
|
showHelp ? card([searchRow(() => setView("help")), ...(arts.list ?? []).slice(0, 4).map(row)], { padding: 8, gap: 2 }) : null
|
|
3266
3864
|
];
|
|
3267
|
-
content = plain ? (0,
|
|
3865
|
+
content = plain ? (0, import_react3.createElement)(
|
|
3268
3866
|
RN3.ScrollView,
|
|
3269
3867
|
{ key: "home", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { paddingHorizontal: 16, paddingTop: 4, paddingBottom: 24, gap: 12 }, keyboardShouldPersistTaps: "handled" },
|
|
3270
|
-
(0,
|
|
3868
|
+
(0, import_react3.createElement)(RN3.View, { key: "top", style: { paddingHorizontal: 6, paddingBottom: 10 } }, hero(p.fg, p.muted)),
|
|
3271
3869
|
...cards
|
|
3272
|
-
) : (0,
|
|
3870
|
+
) : (0, import_react3.createElement)(
|
|
3273
3871
|
RN3.ScrollView,
|
|
3274
3872
|
{ key: "home", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { paddingBottom: 24 }, keyboardShouldPersistTaps: "handled" },
|
|
3275
|
-
(0,
|
|
3276
|
-
(0,
|
|
3873
|
+
(0, import_react3.createElement)(RN3.View, { style: { backgroundColor: p.accent, paddingHorizontal: 22, paddingTop: 4, paddingBottom: 64 } }, hero(ink, alpha(ink, 0.8))),
|
|
3874
|
+
(0, import_react3.createElement)(RN3.View, { style: { marginTop: -48, paddingHorizontal: 16, gap: 12 } }, ...cards)
|
|
3277
3875
|
);
|
|
3278
3876
|
} else if (view === "messages")
|
|
3279
|
-
content = (0,
|
|
3877
|
+
content = (0, import_react3.createElement)(
|
|
3280
3878
|
RN3.View,
|
|
3281
3879
|
{ key: "messages", style: { flex: 1, backgroundColor: hu.bg } },
|
|
3282
|
-
(0,
|
|
3880
|
+
(0, import_react3.createElement)(
|
|
3283
3881
|
RN3.ScrollView,
|
|
3284
3882
|
{ ref: scroll, style: { flex: 1 }, contentContainerStyle: { paddingHorizontal: 16, paddingTop: 4, paddingBottom: 16, gap: 12 } },
|
|
3285
|
-
|
|
3883
|
+
// The greeting opens an empty chat only, never above the visitor's first words (2026-10-30).
|
|
3884
|
+
!thread?.messages.length && !pending ? bubble({ id: "greeting", from: "team", body: greeting, at: "" }) : null,
|
|
3286
3885
|
!chat.loaded ? k.muted("Loading\u2026") : null,
|
|
3287
3886
|
...(thread?.messages ?? []).map((m) => bubble(m)),
|
|
3288
3887
|
pending ? bubble(pending, true) : null,
|
|
3289
3888
|
thread?.conversation?.status === "solved" && !pending ? k.muted("This conversation is closed. Write to start a new one.", { textAlign: "center" }) : null
|
|
3290
3889
|
),
|
|
3291
|
-
(0,
|
|
3890
|
+
(0, import_react3.createElement)(
|
|
3292
3891
|
RN3.View,
|
|
3293
3892
|
{ style: { paddingHorizontal: 12, paddingTop: 8, paddingBottom: 6, gap: 8 } },
|
|
3294
3893
|
chat.error ? k.text(chat.error, { color: p.danger, fontSize: 12 }) : null,
|
|
3295
|
-
needEmail ? k.field({ value: email, onChange: setEmail, placeholder: "Your email (optional), so we can follow up", email: true, max: 200, style: { borderWidth: emailOk ? 0 : 1, borderColor: p.danger, borderRadius: r.field, paddingHorizontal: 16, backgroundColor: hu.surface, ...surf } }) : null,
|
|
3296
3894
|
// Photos picked for the next message, each with a way to take it out again.
|
|
3297
|
-
photos.length ? (0,
|
|
3895
|
+
photos.length ? (0, import_react3.createElement)(
|
|
3298
3896
|
RN3.View,
|
|
3299
3897
|
{ style: { flexDirection: "row", flexWrap: "wrap", gap: 10, paddingTop: 6, paddingHorizontal: 2 } },
|
|
3300
3898
|
...photos.map(
|
|
3301
|
-
(f) => (0,
|
|
3899
|
+
(f) => (0, import_react3.createElement)(
|
|
3302
3900
|
RN3.View,
|
|
3303
3901
|
{ key: f.key, style: { width: 56, height: 56 } },
|
|
3304
|
-
(0,
|
|
3305
|
-
(0,
|
|
3902
|
+
(0, import_react3.createElement)(RN3.Image, { source: { uri: f.uri }, resizeMode: "cover", accessibilityLabel: f.id ? f.name : `${f.name}, uploading`, style: { width: 56, height: 56, borderRadius: Math.max(4, r.card - 4), backgroundColor: p.soft, opacity: f.id ? 1 : 0.5 } }),
|
|
3903
|
+
(0, import_react3.createElement)(
|
|
3306
3904
|
RN3.Pressable,
|
|
3307
3905
|
{
|
|
3308
3906
|
onPress: () => setPhotos((list) => list.filter((x) => x.key !== f.key)),
|
|
@@ -3317,20 +3915,29 @@ var MessengerSheet = ({
|
|
|
3317
3915
|
)
|
|
3318
3916
|
) : null,
|
|
3319
3917
|
// The message field on top, the paperclip (when the app has expo-image-picker) and the send button under it.
|
|
3320
|
-
(0,
|
|
3918
|
+
(0, import_react3.createElement)(
|
|
3321
3919
|
RN3.View,
|
|
3322
3920
|
{ style: { gap: 2, borderRadius: 20, paddingTop: 10, paddingBottom: 6, paddingRight: 6, paddingLeft: 16, backgroundColor: hu.surface, ...surf } },
|
|
3921
|
+
// The optional email: the box's first line, under a hairline the message follows.
|
|
3922
|
+
needEmail ? k.field({
|
|
3923
|
+
value: email,
|
|
3924
|
+
onChange: setEmail,
|
|
3925
|
+
placeholder: "Email for our reply (optional)",
|
|
3926
|
+
email: true,
|
|
3927
|
+
max: 200,
|
|
3928
|
+
style: { minHeight: 0, marginRight: 10, marginBottom: 4, paddingHorizontal: 0, paddingTop: 0, paddingBottom: 8, borderWidth: 0, borderRadius: 0, borderBottomWidth: 1, borderBottomColor: emailOk ? p.line : p.danger, backgroundColor: "transparent", fontSize: 13.5 }
|
|
3929
|
+
}) : null,
|
|
3323
3930
|
k.field({ value: body, onChange: setBody, placeholder: "Write a message\u2026", multiline: true, max: 4e3, style: { minHeight: 28, maxHeight: 120, borderWidth: 0, paddingHorizontal: 0, paddingVertical: 4, backgroundColor: "transparent" } }),
|
|
3324
|
-
(0,
|
|
3931
|
+
(0, import_react3.createElement)(
|
|
3325
3932
|
RN3.View,
|
|
3326
3933
|
{ style: { flexDirection: "row", alignItems: "center", marginLeft: -8 } },
|
|
3327
|
-
imagePicker?.launchImageLibraryAsync ? (0,
|
|
3934
|
+
imagePicker?.launchImageLibraryAsync ? (0, import_react3.createElement)(
|
|
3328
3935
|
RN3.Pressable,
|
|
3329
3936
|
{ onPress: () => void pickPhotos(), disabled: !!pending, accessibilityRole: "button", accessibilityLabel: "Attach a photo or screenshot", hitSlop: 6, style: { width: 34, height: 34, borderRadius: 17, alignItems: "center", justifyContent: "center" } },
|
|
3330
3937
|
glyph("clip", hu.muted, 19)
|
|
3331
3938
|
) : null,
|
|
3332
|
-
(0,
|
|
3333
|
-
(0,
|
|
3939
|
+
(0, import_react3.createElement)(RN3.View, { style: { flex: 1 } }),
|
|
3940
|
+
(0, import_react3.createElement)(
|
|
3334
3941
|
RN3.Pressable,
|
|
3335
3942
|
{
|
|
3336
3943
|
onPress: () => void send(),
|
|
@@ -3348,76 +3955,78 @@ var MessengerSheet = ({
|
|
|
3348
3955
|
else if (view === "help") {
|
|
3349
3956
|
const groups = /* @__PURE__ */ new Map();
|
|
3350
3957
|
for (const a of arts.list ?? []) groups.set(a.collection, [...groups.get(a.collection) ?? [], a]);
|
|
3351
|
-
content = (0,
|
|
3958
|
+
content = (0, import_react3.createElement)(
|
|
3352
3959
|
RN3.ScrollView,
|
|
3353
3960
|
{ key: "help", style: { flex: 1, backgroundColor: canvas }, contentContainerStyle: { paddingHorizontal: 16, paddingTop: 4, paddingBottom: 16, gap: 12 }, keyboardShouldPersistTaps: "handled" },
|
|
3354
3961
|
search,
|
|
3355
3962
|
arts.list === null ? k.muted("Loading\u2026") : null,
|
|
3356
|
-
arts.list?.length === 0 ? (0,
|
|
3357
|
-
...query.trim() ? arts.list?.length ? [card((arts.list ?? []).map(row), { padding: 8 })] : [] : [...groups].map(([name, items]) => (0,
|
|
3963
|
+
arts.list?.length === 0 ? (0, import_react3.createElement)(RN3.View, { style: { gap: 10, alignItems: "center", paddingVertical: 24 } }, k.muted(query.trim() ? `Nothing found for \u201C${query.trim()}\u201D.` : "No help articles yet."), k.btn("Send us a message", "primary", () => setView("messages"))) : null,
|
|
3964
|
+
...query.trim() ? arts.list?.length ? [card((arts.list ?? []).map(row), { padding: 8 })] : [] : [...groups].map(([name, items]) => (0, import_react3.createElement)(RN3.View, { key: name, style: { gap: 6 } }, k.muted(`${name} \xB7 ${items.length}`, { fontSize: 12, fontWeight: "600", paddingHorizontal: 2 }), card(items.map(row), { padding: 8 })))
|
|
3358
3965
|
);
|
|
3359
3966
|
} else
|
|
3360
|
-
content = (0,
|
|
3967
|
+
content = (0, import_react3.createElement)(
|
|
3361
3968
|
RN3.ScrollView,
|
|
3362
3969
|
{ key: `a-${view.article}`, style: { flex: 1 }, contentContainerStyle: { paddingHorizontal: 16, paddingTop: 4, paddingBottom: 32 } },
|
|
3363
|
-
(0,
|
|
3970
|
+
(0, import_react3.createElement)(ArticleView, { client, p, id: view.article, onAsk: () => setView("messages") })
|
|
3364
3971
|
);
|
|
3365
3972
|
const current = typeof view === "string" ? view : "help";
|
|
3366
3973
|
const tab = (v, name, icon, badge = 0) => {
|
|
3367
3974
|
const on = current === v;
|
|
3368
|
-
return (0,
|
|
3975
|
+
return (0, import_react3.createElement)(
|
|
3369
3976
|
RN3.Pressable,
|
|
3370
3977
|
{
|
|
3371
3978
|
key: v,
|
|
3372
3979
|
onPress: () => setView(v),
|
|
3373
3980
|
accessibilityRole: "tab",
|
|
3981
|
+
accessibilityLabel: name,
|
|
3374
3982
|
accessibilityState: { selected: on },
|
|
3375
|
-
|
|
3983
|
+
// Only the open tab carries its name; the others are icons, so the bar fits a narrow phone.
|
|
3984
|
+
style: { ...on ? { flex: 1 } : { width: 48 }, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, height: 36, borderRadius: 18, ...on ? { backgroundColor: hu.segment, ...segLift } : {} }
|
|
3376
3985
|
},
|
|
3377
3986
|
glyph(icon, on ? hu.fg : hu.muted, 17),
|
|
3378
|
-
k.text(name, { fontSize: 13.5, fontWeight: "500", color:
|
|
3379
|
-
badge ? (0,
|
|
3987
|
+
on ? k.text(name, { fontSize: 13.5, fontWeight: "500", color: hu.fg }) : null,
|
|
3988
|
+
badge ? (0, import_react3.createElement)(RN3.View, { style: { position: "absolute", top: 7, right: 12, width: 8, height: 8, borderRadius: 4, backgroundColor: p.danger } }) : null
|
|
3380
3989
|
);
|
|
3381
3990
|
};
|
|
3382
3991
|
const onAccent = view === "home" && !plain;
|
|
3383
3992
|
const ground = onAccent ? p.accent : hu.bg;
|
|
3384
|
-
const back = (to, label) => (0,
|
|
3993
|
+
const back = (to, label) => (0, import_react3.createElement)(
|
|
3385
3994
|
RN3.Pressable,
|
|
3386
3995
|
{ key: "back", onPress: () => setView(to), accessibilityRole: "button", accessibilityLabel: label, hitSlop: 10, style: { width: 32, height: 32, alignItems: "center", justifyContent: "center", transform: [{ rotate: "180deg" }] } },
|
|
3387
3996
|
glyph("next", hu.fg, 18)
|
|
3388
3997
|
);
|
|
3389
|
-
const head = (0,
|
|
3998
|
+
const head = (0, import_react3.createElement)(
|
|
3390
3999
|
RN3.View,
|
|
3391
4000
|
{ key: "head", style: { flexDirection: "row", alignItems: "center", gap: 8, paddingLeft: 12, paddingRight: 12, paddingTop: 12, paddingBottom: 6, backgroundColor: ground } },
|
|
3392
|
-
typeof view !== "string" ? back("help", "All articles") : view === "messages" ? back("home", "Back to home") : view === "home" && (o.logo || title) ? o.logo ? (0,
|
|
4001
|
+
typeof view !== "string" ? back("help", "All articles") : view === "messages" ? back("home", "Back to home") : view === "home" && (o.logo || title) ? o.logo ? (0, import_react3.createElement)(RN3.Image, { key: "logo", source: { uri: o.logo }, accessibilityIgnoresInvertColors: true, resizeMode: "contain", style: { height: 28, aspectRatio: 1, maxWidth: 132, borderRadius: 8, marginLeft: 4 } }) : teamMark(title, alpha(p.accent, 0.16), p.accent, 28) : null,
|
|
3393
4002
|
// In the chat: who answers, in the middle.
|
|
3394
|
-
view === "messages" && title ? (0,
|
|
4003
|
+
view === "messages" && title ? (0, import_react3.createElement)(
|
|
3395
4004
|
RN3.View,
|
|
3396
4005
|
{ style: { flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 8 } },
|
|
3397
4006
|
teamMark(title, alpha(p.accent, 0.16), p.accent, 28),
|
|
3398
|
-
(0,
|
|
3399
|
-
) : (0,
|
|
3400
|
-
(0,
|
|
4007
|
+
(0, import_react3.createElement)(RN3.Text, { numberOfLines: 1, style: { flexShrink: 1, color: hu.fg, fontSize: 15, fontWeight: "600" } }, title)
|
|
4008
|
+
) : (0, import_react3.createElement)(RN3.View, { style: { flex: 1 } }),
|
|
4009
|
+
(0, import_react3.createElement)(RN3.Pressable, { onPress: close, accessibilityRole: "button", accessibilityLabel: "Close", hitSlop: 12, style: { width: 32, height: 32, borderRadius: 10, alignItems: "center", justifyContent: "center" } }, glyph("cross", onAccent ? ink : p.muted, 18))
|
|
3401
4010
|
);
|
|
3402
|
-
const powered = brand ? (0,
|
|
4011
|
+
const powered = brand ? (0, import_react3.createElement)(
|
|
3403
4012
|
RN3.View,
|
|
3404
4013
|
{ key: "brand", style: { paddingTop: 2, paddingBottom: 6, alignItems: "center", backgroundColor: hu.bg } },
|
|
3405
|
-
(0,
|
|
4014
|
+
(0, import_react3.createElement)(
|
|
3406
4015
|
RN3.Text,
|
|
3407
4016
|
{ onPress: () => void RN3.Linking.openURL(BRAND_URL).catch(() => void 0), accessibilityRole: "link", hitSlop: 8, style: { color: p.muted, fontSize: 11.5 } },
|
|
3408
4017
|
"Powered by ",
|
|
3409
|
-
(0,
|
|
4018
|
+
(0, import_react3.createElement)(RN3.Text, { style: { fontWeight: "600" } }, "MRRocket")
|
|
3410
4019
|
)
|
|
3411
4020
|
) : null;
|
|
3412
|
-
return (0,
|
|
4021
|
+
return (0, import_react3.createElement)(
|
|
3413
4022
|
RN3.Modal,
|
|
3414
4023
|
{ visible: true, animationType: "slide", presentationStyle: "pageSheet", onRequestClose: close },
|
|
3415
|
-
(0,
|
|
4024
|
+
(0, import_react3.createElement)(
|
|
3416
4025
|
RN3.KeyboardAvoidingView,
|
|
3417
4026
|
{ behavior: RN3.Platform.OS === "ios" ? "padding" : void 0, style: { flex: 1, backgroundColor: hu.bg } },
|
|
3418
4027
|
head,
|
|
3419
4028
|
content,
|
|
3420
|
-
view === "messages" ? null : (0,
|
|
4029
|
+
view === "messages" ? null : (0, import_react3.createElement)(
|
|
3421
4030
|
RN3.View,
|
|
3422
4031
|
{ key: "tabs", accessibilityRole: "tablist", style: { flexDirection: "row", marginHorizontal: 12, marginTop: 6, marginBottom: 6, padding: 4, borderRadius: 22, backgroundColor: hu.surface } },
|
|
3423
4032
|
tab("home", "Home", "home"),
|
|
@@ -3425,13 +4034,13 @@ var MessengerSheet = ({
|
|
|
3425
4034
|
showHelp ? tab("help", "Help", "help") : null
|
|
3426
4035
|
),
|
|
3427
4036
|
powered,
|
|
3428
|
-
(0,
|
|
4037
|
+
(0, import_react3.createElement)(RN3.View, { style: { height: 16 } })
|
|
3429
4038
|
)
|
|
3430
4039
|
);
|
|
3431
4040
|
};
|
|
3432
4041
|
var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
3433
|
-
const [look, setLook] = (0,
|
|
3434
|
-
(0,
|
|
4042
|
+
const [look, setLook] = (0, import_react3.useState)(null);
|
|
4043
|
+
(0, import_react3.useEffect)(() => {
|
|
3435
4044
|
const ctrl = new AbortController();
|
|
3436
4045
|
void client.ready.then(
|
|
3437
4046
|
() => client.api()?.messengerLook(ctrl.signal).then(setLook).catch(() => void 0)
|
|
@@ -3453,14 +4062,15 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
3453
4062
|
corners: look.corners,
|
|
3454
4063
|
header: look.header,
|
|
3455
4064
|
logo: look.logo,
|
|
4065
|
+
agentName: look.agentName,
|
|
3456
4066
|
...defined
|
|
3457
4067
|
} : given;
|
|
3458
4068
|
const p = usePalette({ theme: appearance?.theme ?? look?.theme, accent: appearance?.accent ?? look?.accent });
|
|
3459
4069
|
const k = kit(p);
|
|
3460
4070
|
const open = messengerOpen.useOpen();
|
|
3461
|
-
const [view, setViewState] = (0,
|
|
3462
|
-
const [banner, setBanner] = (0,
|
|
3463
|
-
(0,
|
|
4071
|
+
const [view, setViewState] = (0, import_react3.useState)(msgView);
|
|
4072
|
+
const [banner, setBanner] = (0, import_react3.useState)(null);
|
|
4073
|
+
(0, import_react3.useEffect)(() => {
|
|
3464
4074
|
if (open) setViewState(msgView);
|
|
3465
4075
|
}, [open]);
|
|
3466
4076
|
const setView = (v) => {
|
|
@@ -3469,13 +4079,13 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
3469
4079
|
};
|
|
3470
4080
|
const chat = useChat(client, options, open, view);
|
|
3471
4081
|
const latest = chat.unseen.at(-1);
|
|
3472
|
-
(0,
|
|
4082
|
+
(0, import_react3.useEffect)(() => {
|
|
3473
4083
|
if (!latest || open || options.preview === false) return;
|
|
3474
4084
|
setBanner(latest);
|
|
3475
4085
|
const t = setTimeout(() => setBanner(null), 6e3);
|
|
3476
4086
|
return () => clearTimeout(t);
|
|
3477
4087
|
}, [latest, open, options.preview]);
|
|
3478
|
-
(0,
|
|
4088
|
+
(0, import_react3.useEffect)(() => {
|
|
3479
4089
|
if (open) setBanner(null);
|
|
3480
4090
|
}, [open]);
|
|
3481
4091
|
const unseen = chat.unseen.length;
|
|
@@ -3487,10 +4097,10 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
3487
4097
|
...edge === "top" ? { top: 60 } : edge === "bottom" ? { bottom: 34 } : { top: 0, bottom: 0, justifyContent: "center" },
|
|
3488
4098
|
...side === "left" ? { left: 20 } : side === "right" ? { right: 20 } : { left: 0, right: 0, alignItems: "center" }
|
|
3489
4099
|
};
|
|
3490
|
-
const launcher = options.launcher ? (0,
|
|
4100
|
+
const launcher = options.launcher ? (0, import_react3.createElement)(
|
|
3491
4101
|
RN3.View,
|
|
3492
4102
|
{ key: "launcher", pointerEvents: "box-none", style: { position: "absolute", ...place } },
|
|
3493
|
-
(0,
|
|
4103
|
+
(0, import_react3.createElement)(
|
|
3494
4104
|
RN3.Pressable,
|
|
3495
4105
|
{
|
|
3496
4106
|
onPress: () => openAt(unseen ? "messages" : "home"),
|
|
@@ -3515,10 +4125,10 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
3515
4125
|
},
|
|
3516
4126
|
glyph("chat", ink, label ? 20 : 26),
|
|
3517
4127
|
label ? k.text(label, { color: ink, fontWeight: "700" }) : null,
|
|
3518
|
-
unseen ? (0,
|
|
4128
|
+
unseen ? (0, import_react3.createElement)(RN3.View, { style: { position: "absolute", top: -2, right: -2, minWidth: 20, height: 20, borderRadius: 10, backgroundColor: p.danger, alignItems: "center", justifyContent: "center", borderWidth: 2, borderColor: p.bg } }, k.text(String(Math.min(unseen, 9)), { color: "#fff", fontSize: 11, fontWeight: "700" })) : null
|
|
3519
4129
|
)
|
|
3520
4130
|
) : null;
|
|
3521
|
-
const toast = banner ? (0,
|
|
4131
|
+
const toast = banner ? (0, import_react3.createElement)(
|
|
3522
4132
|
RN3.Pressable,
|
|
3523
4133
|
{
|
|
3524
4134
|
key: "banner",
|
|
@@ -3542,30 +4152,30 @@ var MRRocketMessenger = ({ client, appearance, options: given = {} }) => {
|
|
|
3542
4152
|
elevation: 6
|
|
3543
4153
|
}
|
|
3544
4154
|
},
|
|
3545
|
-
k.muted(`${
|
|
3546
|
-
(0,
|
|
4155
|
+
k.muted(`${who(banner.from, options.agentName)}${unseen > 1 ? ` \xB7 ${unseen} new` : ""}`, { fontWeight: "600", fontSize: 12 }),
|
|
4156
|
+
(0, import_react3.createElement)(RN3.Text, { numberOfLines: 3, style: { color: p.fg, fontSize: 15, lineHeight: 20 } }, banner.body)
|
|
3547
4157
|
) : null;
|
|
3548
4158
|
if (!launcher && !toast && !open) return null;
|
|
3549
|
-
return (0,
|
|
4159
|
+
return (0, import_react3.createElement)(
|
|
3550
4160
|
RN3.View,
|
|
3551
4161
|
{ pointerEvents: "box-none", style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 } },
|
|
3552
4162
|
launcher,
|
|
3553
4163
|
toast,
|
|
3554
|
-
open ? (0,
|
|
4164
|
+
open ? (0, import_react3.createElement)(MessengerSheet, { client, p, o: options, chat, view, setView, brand: look?.branding !== false }) : null
|
|
3555
4165
|
);
|
|
3556
4166
|
};
|
|
3557
4167
|
|
|
3558
4168
|
// src/native/index.tsx
|
|
3559
4169
|
var RN4 = require("react-native");
|
|
3560
4170
|
var MRRocketMask = ({ children, style }) => {
|
|
3561
|
-
const ref = (0,
|
|
3562
|
-
(0,
|
|
4171
|
+
const ref = (0, import_react4.useRef)(null);
|
|
4172
|
+
(0, import_react4.useEffect)(() => {
|
|
3563
4173
|
maskedViews.add(ref);
|
|
3564
4174
|
return () => {
|
|
3565
4175
|
maskedViews.delete(ref);
|
|
3566
4176
|
};
|
|
3567
4177
|
}, []);
|
|
3568
|
-
return (0,
|
|
4178
|
+
return (0, import_react4.createElement)(RN4.View, { ref, collapsable: false, style }, children);
|
|
3569
4179
|
};
|
|
3570
4180
|
var shared = null;
|
|
3571
4181
|
var sharedKey = "";
|
|
@@ -3582,16 +4192,16 @@ var createMRRocket = (options) => {
|
|
|
3582
4192
|
return shared;
|
|
3583
4193
|
};
|
|
3584
4194
|
var getMRRocket = () => shared;
|
|
3585
|
-
var Ctx = (0,
|
|
4195
|
+
var Ctx = (0, import_react4.createContext)(null);
|
|
3586
4196
|
var MRRocketProvider = ({ client: given, children, consent, flows = true, appearance, surveys = true, messenger = {}, feedback = {}, heatmaps = true, ...options }) => {
|
|
3587
|
-
const [client] = (0,
|
|
3588
|
-
(0,
|
|
4197
|
+
const [client] = (0, import_react4.useState)(() => given ?? createMRRocket({ ...options, consent }));
|
|
4198
|
+
(0, import_react4.useEffect)(() => {
|
|
3589
4199
|
if (consent) client.setConsent(consent);
|
|
3590
4200
|
}, [client, consent]);
|
|
3591
|
-
(0,
|
|
4201
|
+
(0, import_react4.useEffect)(() => {
|
|
3592
4202
|
if (options.replay !== void 0) client.setReplay(options.replay);
|
|
3593
4203
|
}, [client, options.replay]);
|
|
3594
|
-
const start = (0,
|
|
4204
|
+
const start = (0, import_react4.useRef)(null);
|
|
3595
4205
|
const touch = (e, end) => {
|
|
3596
4206
|
const n = e.nativeEvent;
|
|
3597
4207
|
const x = n.pageX ?? n.changedTouches?.[0]?.pageX;
|
|
@@ -3600,22 +4210,22 @@ var MRRocketProvider = ({ client: given, children, consent, flows = true, appear
|
|
|
3600
4210
|
if (!end) start.current = { x, y, t: Date.now() };
|
|
3601
4211
|
else if (start.current && Math.hypot(x - start.current.x, y - start.current.y) < 10 && Date.now() - start.current.t < 500) client.tap(x, y);
|
|
3602
4212
|
};
|
|
3603
|
-
return (0,
|
|
4213
|
+
return (0, import_react4.createElement)(
|
|
3604
4214
|
Ctx.Provider,
|
|
3605
4215
|
{ value: client },
|
|
3606
|
-
heatmaps ? (0,
|
|
3607
|
-
flows ? (0,
|
|
3608
|
-
surveys ? (0,
|
|
3609
|
-
feedback ? (0,
|
|
3610
|
-
messenger ? (0,
|
|
4216
|
+
heatmaps ? (0, import_react4.createElement)(RN4.View, { style: { flex: 1 }, onTouchStartCapture: (e) => touch(e, false), onTouchEndCapture: (e) => touch(e, true) }, children) : children,
|
|
4217
|
+
flows ? (0, import_react4.createElement)(MRRocketFlows, { flows: client.flows, paywall: client.paywall, appearance }) : null,
|
|
4218
|
+
surveys ? (0, import_react4.createElement)(MRRocketSurveys, { client, appearance }) : null,
|
|
4219
|
+
feedback ? (0, import_react4.createElement)(MRRocketFeedback, { client, appearance, options: feedback }) : null,
|
|
4220
|
+
messenger ? (0, import_react4.createElement)(MRRocketMessenger, { client, appearance, options: messenger }) : null
|
|
3611
4221
|
);
|
|
3612
4222
|
};
|
|
3613
4223
|
var useClient = () => {
|
|
3614
|
-
const c = (0,
|
|
4224
|
+
const c = (0, import_react4.useContext)(Ctx);
|
|
3615
4225
|
if (!c) throw new Error("MRRocket: wrap your app in <MRRocketProvider apiKey=\u2026>.");
|
|
3616
4226
|
return c;
|
|
3617
4227
|
};
|
|
3618
|
-
var useVersion = (client) => (0,
|
|
4228
|
+
var useVersion = (client) => (0, import_react4.useSyncExternalStore)(client.subscribe, client.getVersion, client.getVersion);
|
|
3619
4229
|
var useMRRocket = () => {
|
|
3620
4230
|
const client = useClient();
|
|
3621
4231
|
useVersion(client);
|
|
@@ -3649,9 +4259,9 @@ var useReview = () => {
|
|
|
3649
4259
|
const client = useClient();
|
|
3650
4260
|
return { request: client.requestReview };
|
|
3651
4261
|
};
|
|
3652
|
-
var useOnboarding = () => {
|
|
4262
|
+
var useOnboarding = (id) => {
|
|
3653
4263
|
const client = useClient();
|
|
3654
|
-
return
|
|
4264
|
+
return useOnboardingItem(client.flows, id, client.startOnboarding);
|
|
3655
4265
|
};
|
|
3656
4266
|
var useFlag = (key) => {
|
|
3657
4267
|
const client = useClient();
|
|
@@ -3668,7 +4278,7 @@ var useVariant = (key) => {
|
|
|
3668
4278
|
useVersion(client);
|
|
3669
4279
|
const config = client.getConfig();
|
|
3670
4280
|
const variant = client.peekVariant(key);
|
|
3671
|
-
(0,
|
|
4281
|
+
(0, import_react4.useEffect)(() => {
|
|
3672
4282
|
if (config) client.expose(key, variant);
|
|
3673
4283
|
}, [client, config, key, variant]);
|
|
3674
4284
|
return variant;
|
|
@@ -3679,7 +4289,7 @@ var useText = (id, fallback) => {
|
|
|
3679
4289
|
const config = client.getConfig();
|
|
3680
4290
|
const text2 = client.peekText(id);
|
|
3681
4291
|
const person = client.getDistinctId();
|
|
3682
|
-
(0,
|
|
4292
|
+
(0, import_react4.useEffect)(() => {
|
|
3683
4293
|
if (config) client.exposeText(id);
|
|
3684
4294
|
}, [client, config, id, person]);
|
|
3685
4295
|
return text2 ?? fallback;
|
|
@@ -3704,13 +4314,13 @@ var useExpoRouterTracking = () => {
|
|
|
3704
4314
|
console.warn("[MRRocket] useExpoRouterTracking needs expo-router. With React Navigation use useNavigationTracking.");
|
|
3705
4315
|
}
|
|
3706
4316
|
const pathname = (router?.usePathname ?? noPathname)();
|
|
3707
|
-
(0,
|
|
4317
|
+
(0, import_react4.useEffect)(() => {
|
|
3708
4318
|
if (pathname) client.screen(pathname);
|
|
3709
4319
|
}, [client, pathname]);
|
|
3710
4320
|
};
|
|
3711
4321
|
var useNavigationTracking = () => {
|
|
3712
4322
|
const client = useClient();
|
|
3713
|
-
return (0,
|
|
4323
|
+
return (0, import_react4.useCallback)(
|
|
3714
4324
|
(state) => {
|
|
3715
4325
|
const name = activeRouteName(state);
|
|
3716
4326
|
if (name) client.screen(name);
|