@wix/himalaya-cli 0.1525.0 → 0.1526.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +14 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +22 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/worker-subtree-safe-types.generated.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +7 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +13 -0
- package/dist/cli.mjs +137 -39
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/designing-himi-screens.md +43 -18
- package/guides/recipe-dynamic-list.md +7 -7
- package/guides/recipe-four-state.md +47 -41
- package/guides/recipe-search.md +1 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +69 -40
- package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/branded-lite/dev/index.ts +165 -88
- package/templates/branded-lite/tier5-src/business-chat/index.ts +4 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/community-club/dev/index.ts +40 -21
- package/templates/community-club/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/events-meetups/dev/index.ts +36 -19
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/gym-fitness/dev/index.ts +73 -42
- package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/nonprofit-cause/dev/index.ts +47 -29
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/podcast-creator/dev/index.ts +47 -29
- package/templates/podcast-creator/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/portfolio-creative/dev/index.ts +52 -27
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/restaurant/dev/index.ts +48 -25
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/retail-store/dev/index.ts +44 -23
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +69 -10
- package/templates/yoga-studio/dev/index.ts +57 -34
- package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +9 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-place-summary/index.ts +12 -1
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +69 -10
|
@@ -2489,8 +2489,10 @@ const SCREENS = runtimeSetting({
|
|
|
2489
2489
|
"actionId": "himi.open",
|
|
2490
2490
|
"params": {
|
|
2491
2491
|
"screenId": "himi_sign_in",
|
|
2492
|
-
"mode": "signin"
|
|
2493
|
-
|
|
2492
|
+
"mode": "signin",
|
|
2493
|
+
"modal": "1"
|
|
2494
|
+
},
|
|
2495
|
+
"presentation": "sheet"
|
|
2494
2496
|
}
|
|
2495
2497
|
}
|
|
2496
2498
|
}
|
|
@@ -2508,8 +2510,10 @@ const SCREENS = runtimeSetting({
|
|
|
2508
2510
|
"actionId": "himi.open",
|
|
2509
2511
|
"params": {
|
|
2510
2512
|
"screenId": "himi_sign_in",
|
|
2511
|
-
"mode": "register"
|
|
2512
|
-
|
|
2513
|
+
"mode": "register",
|
|
2514
|
+
"modal": "1"
|
|
2515
|
+
},
|
|
2516
|
+
"presentation": "sheet"
|
|
2513
2517
|
}
|
|
2514
2518
|
}
|
|
2515
2519
|
}
|
|
@@ -3710,6 +3714,8 @@ const SCREENS = runtimeSetting({
|
|
|
3710
3714
|
"memberAccountLinks": "1",
|
|
3711
3715
|
"restorePurchases": "1",
|
|
3712
3716
|
"signInScreen": "himi_sign_in",
|
|
3717
|
+
"signInPresentation": "sheet",
|
|
3718
|
+
"signInReturnTab": "profile",
|
|
3713
3719
|
"pollIdentity": "1",
|
|
3714
3720
|
"copy": "{\"account.subtitle\":\"Bookings, RSVPs, memberships, programs and saved content in one place.\",\"storeAccount.authBody\":\"Sign in to continue — bookings, RSVPs, memberships and programs stay with you.\",\"storeAccount.authBodyRegister\":\"Create a member account to continue — bookings, RSVPs, memberships and programs stay with you.\"}"
|
|
3715
3721
|
}
|
|
@@ -3965,8 +3971,10 @@ const SCREENS = runtimeSetting({
|
|
|
3965
3971
|
"params": {
|
|
3966
3972
|
"screenId": "himi_sign_in",
|
|
3967
3973
|
"mode": "signin",
|
|
3968
|
-
"returnScreenId": "himi_account_settings"
|
|
3969
|
-
|
|
3974
|
+
"returnScreenId": "himi_account_settings",
|
|
3975
|
+
"modal": "1"
|
|
3976
|
+
},
|
|
3977
|
+
"presentation": "sheet"
|
|
3970
3978
|
}
|
|
3971
3979
|
}
|
|
3972
3980
|
},
|
|
@@ -5876,8 +5884,7 @@ const SCREENS = runtimeSetting({
|
|
|
5876
5884
|
"style": "primary",
|
|
5877
5885
|
"fullWidth": true,
|
|
5878
5886
|
"action": {
|
|
5879
|
-
"actionId": "
|
|
5880
|
-
"presentation": "back"
|
|
5887
|
+
"actionId": "tier5.himiStoreAccount.leave"
|
|
5881
5888
|
}
|
|
5882
5889
|
}
|
|
5883
5890
|
}
|
|
@@ -5918,7 +5925,7 @@ const SCREENS = runtimeSetting({
|
|
|
5918
5925
|
"declaredCapabilities": [
|
|
5919
5926
|
"wix_api"
|
|
5920
5927
|
],
|
|
5921
|
-
"minBinaryVersion": "
|
|
5928
|
+
"minBinaryVersion": "1.7.0",
|
|
5922
5929
|
"bundleVersion": "0.0.1"
|
|
5923
5930
|
}
|
|
5924
5931
|
},
|
|
@@ -6785,8 +6792,10 @@ const SCREENS = runtimeSetting({
|
|
|
6785
6792
|
"screenId": "himi_sign_in",
|
|
6786
6793
|
"mode": "signin",
|
|
6787
6794
|
"intent": "profile",
|
|
6788
|
-
"returnScreenId": "himi_view_profile"
|
|
6789
|
-
|
|
6795
|
+
"returnScreenId": "himi_view_profile",
|
|
6796
|
+
"modal": "1"
|
|
6797
|
+
},
|
|
6798
|
+
"presentation": "sheet"
|
|
6790
6799
|
}
|
|
6791
6800
|
}
|
|
6792
6801
|
}
|
|
@@ -7851,8 +7860,10 @@ const SCREENS = runtimeSetting({
|
|
|
7851
7860
|
"screenId": "himi_sign_in",
|
|
7852
7861
|
"mode": "signin",
|
|
7853
7862
|
"intent": "wallet",
|
|
7854
|
-
"returnScreenId": "himi_wallet"
|
|
7855
|
-
|
|
7863
|
+
"returnScreenId": "himi_wallet",
|
|
7864
|
+
"modal": "1"
|
|
7865
|
+
},
|
|
7866
|
+
"presentation": "sheet"
|
|
7856
7867
|
}
|
|
7857
7868
|
}
|
|
7858
7869
|
}
|
|
@@ -8320,11 +8331,7 @@ const SCREENS = runtimeSetting({
|
|
|
8320
8331
|
"size": "sm",
|
|
8321
8332
|
"fullWidth": true,
|
|
8322
8333
|
"action": {
|
|
8323
|
-
"actionId": "
|
|
8324
|
-
"params": {
|
|
8325
|
-
"screenId": "$service:himiPlaceSummary.ctaScreenId",
|
|
8326
|
-
"mode": "$service:himiPlaceSummary.ctaMode"
|
|
8327
|
-
}
|
|
8334
|
+
"actionId": "tier5.himiPlaceSummary.openCta"
|
|
8328
8335
|
}
|
|
8329
8336
|
}
|
|
8330
8337
|
},
|
|
@@ -8365,7 +8372,8 @@ const SCREENS = runtimeSetting({
|
|
|
8365
8372
|
"onAppear": {
|
|
8366
8373
|
"actionId": "tier5.himiPlaceSummary.load",
|
|
8367
8374
|
"params": {
|
|
8368
|
-
"verticals": "[\"bookings\",\"programs\",\"plans\",\"events\",\"blog\"]"
|
|
8375
|
+
"verticals": "[\"bookings\",\"programs\",\"plans\",\"events\",\"blog\"]",
|
|
8376
|
+
"signInPresentation": "sheet"
|
|
8369
8377
|
}
|
|
8370
8378
|
}
|
|
8371
8379
|
}
|
|
@@ -11638,8 +11646,10 @@ const SCREENS = runtimeSetting({
|
|
|
11638
11646
|
"params": {
|
|
11639
11647
|
"screenId": "himi_sign_in",
|
|
11640
11648
|
"mode": "signin",
|
|
11641
|
-
"returnScreenId": "himi_bookings"
|
|
11642
|
-
|
|
11649
|
+
"returnScreenId": "himi_bookings",
|
|
11650
|
+
"modal": "1"
|
|
11651
|
+
},
|
|
11652
|
+
"presentation": "sheet"
|
|
11643
11653
|
}
|
|
11644
11654
|
}
|
|
11645
11655
|
}
|
|
@@ -15026,7 +15036,8 @@ const SCREENS = runtimeSetting({
|
|
|
15026
15036
|
"onAppear": {
|
|
15027
15037
|
"actionId": "tier5.himiBrandedAgenda.load",
|
|
15028
15038
|
"params": {
|
|
15029
|
-
"firstWeekday": "0"
|
|
15039
|
+
"firstWeekday": "0",
|
|
15040
|
+
"signInPresentation": "sheet"
|
|
15030
15041
|
}
|
|
15031
15042
|
}
|
|
15032
15043
|
}
|
|
@@ -20695,8 +20706,10 @@ const SCREENS = runtimeSetting({
|
|
|
20695
20706
|
"actionId": "himi.open",
|
|
20696
20707
|
"params": {
|
|
20697
20708
|
"screenId": "himi_sign_in",
|
|
20698
|
-
"mode": "signin"
|
|
20699
|
-
|
|
20709
|
+
"mode": "signin",
|
|
20710
|
+
"modal": "1"
|
|
20711
|
+
},
|
|
20712
|
+
"presentation": "sheet"
|
|
20700
20713
|
}
|
|
20701
20714
|
}
|
|
20702
20715
|
},
|
|
@@ -21081,8 +21094,10 @@ const SCREENS = runtimeSetting({
|
|
|
21081
21094
|
"screenId": "himi_sign_in",
|
|
21082
21095
|
"mode": "signin",
|
|
21083
21096
|
"intent": "post",
|
|
21084
|
-
"returnScreenId": "himi_create_post"
|
|
21085
|
-
|
|
21097
|
+
"returnScreenId": "himi_create_post",
|
|
21098
|
+
"modal": "1"
|
|
21099
|
+
},
|
|
21100
|
+
"presentation": "sheet"
|
|
21086
21101
|
}
|
|
21087
21102
|
}
|
|
21088
21103
|
}
|
|
@@ -31661,8 +31676,10 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
31661
31676
|
"params": {
|
|
31662
31677
|
"screenId": "himi_sign_in",
|
|
31663
31678
|
"mode": "signin",
|
|
31664
|
-
"intent": "book"
|
|
31665
|
-
|
|
31679
|
+
"intent": "book",
|
|
31680
|
+
"modal": "1"
|
|
31681
|
+
},
|
|
31682
|
+
"presentation": "sheet"
|
|
31666
31683
|
}
|
|
31667
31684
|
}
|
|
31668
31685
|
},
|
|
@@ -31687,8 +31704,10 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
31687
31704
|
"params": {
|
|
31688
31705
|
"screenId": "himi_sign_in",
|
|
31689
31706
|
"mode": "signin",
|
|
31690
|
-
"intent": "book"
|
|
31691
|
-
|
|
31707
|
+
"intent": "book",
|
|
31708
|
+
"modal": "1"
|
|
31709
|
+
},
|
|
31710
|
+
"presentation": "sheet"
|
|
31692
31711
|
}
|
|
31693
31712
|
}
|
|
31694
31713
|
},
|
|
@@ -31713,8 +31732,10 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
31713
31732
|
"params": {
|
|
31714
31733
|
"screenId": "himi_sign_in",
|
|
31715
31734
|
"mode": "signin",
|
|
31716
|
-
"intent": "book"
|
|
31717
|
-
|
|
31735
|
+
"intent": "book",
|
|
31736
|
+
"modal": "1"
|
|
31737
|
+
},
|
|
31738
|
+
"presentation": "sheet"
|
|
31718
31739
|
}
|
|
31719
31740
|
}
|
|
31720
31741
|
},
|
|
@@ -34246,8 +34267,10 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
34246
34267
|
"params": {
|
|
34247
34268
|
"screenId": "himi_sign_in",
|
|
34248
34269
|
"mode": "signin",
|
|
34249
|
-
"intent": "rsvp"
|
|
34250
|
-
|
|
34270
|
+
"intent": "rsvp",
|
|
34271
|
+
"modal": "1"
|
|
34272
|
+
},
|
|
34273
|
+
"presentation": "sheet"
|
|
34251
34274
|
}
|
|
34252
34275
|
}
|
|
34253
34276
|
},
|
|
@@ -598,6 +598,9 @@ function initial(): S {
|
|
|
598
598
|
};
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
/** How the app opens its sign-in screen, from the appear params ("" = push). */
|
|
602
|
+
let signInPresentation: "" | "sheet" | "full_screen" = "";
|
|
603
|
+
|
|
601
604
|
const svc = defineService<S, {
|
|
602
605
|
load: (s: S, p?: unknown) => Promise<S | undefined>;
|
|
603
606
|
retry: (s: S) => Promise<S | undefined>;
|
|
@@ -614,6 +617,8 @@ const svc = defineService<S, {
|
|
|
614
617
|
actions: {
|
|
615
618
|
load: async (s, p) => {
|
|
616
619
|
stashCopy(p);
|
|
620
|
+
const presentation = argOf(p, "signInPresentation");
|
|
621
|
+
if (presentation === "sheet" || presentation === "full_screen") signInPresentation = presentation;
|
|
617
622
|
const fw = Number(argOf(p, "firstWeekday") || s.firstWeekday);
|
|
618
623
|
const today = dayKey(new Date());
|
|
619
624
|
// First appearance: open on this week. A re-appearance keeps the member's place and
|
|
@@ -739,7 +744,10 @@ const svc = defineService<S, {
|
|
|
739
744
|
const before = await memberAccess().catch(() => undefined);
|
|
740
745
|
if (!before?.email) {
|
|
741
746
|
busy = false;
|
|
742
|
-
|
|
747
|
+
// As a modal it only closes, and this screen loads again (its re-appearance reload).
|
|
748
|
+
return navigate(s, signInPresentation
|
|
749
|
+
? { screenId: "himi_sign_in", presentation: signInPresentation, args: { mode: "signin", modal: "1" } }
|
|
750
|
+
: { screenId: "himi_sign_in", args: { mode: "signin", returnScreenId: "himi_agenda" } });
|
|
743
751
|
}
|
|
744
752
|
const name = await memberName();
|
|
745
753
|
const current = await memberAccess().catch(() => undefined);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// `load` is both the onAppear action and what an embed controller's `refresh()` runs (arg-less:
|
|
10
10
|
// the stashed appear params keep the verticals and the copy pack), so a host that hears
|
|
11
11
|
// `booking.created` / `booking.cancelled` re-reads the summary without a remount.
|
|
12
|
-
import { defineService } from "@himalaya/state";
|
|
12
|
+
import { defineService, navigate } from "@himalaya/state";
|
|
13
13
|
import { listMyPlanOrders, type WixPlanOrder } from "@himalaya/wix-pricing-plans";
|
|
14
14
|
import { fetchMemberBookings, type MemberBookingRow } from "../_shared/member-bookings.js";
|
|
15
15
|
import { memberAccess, assertMemberAccess, memberAccessDenied, type MemberAccess } from "../_shared/member-access.js";
|
|
@@ -52,6 +52,7 @@ const PLANS_SCREEN = "himi_plans";
|
|
|
52
52
|
const SIGN_IN_SCREEN = "himi_sign_in";
|
|
53
53
|
|
|
54
54
|
let stashedVerticals: string[] | null = null;
|
|
55
|
+
let signInPresentation: "sheet" | "full_screen" | undefined;
|
|
55
56
|
let generation = 0;
|
|
56
57
|
|
|
57
58
|
function appearVerticals(arg: unknown): string[] {
|
|
@@ -190,6 +191,8 @@ async function read(arg: unknown, again = true): Promise<PlaceSummaryState> {
|
|
|
190
191
|
* write back over the newer result. */
|
|
191
192
|
async function load(_s: PlaceSummaryState, arg?: unknown): Promise<PlaceSummaryState | undefined> {
|
|
192
193
|
stashCopy(arg);
|
|
194
|
+
const presentation = arg && typeof arg === "object" ? (arg as Record<string, unknown>).signInPresentation : undefined;
|
|
195
|
+
if (presentation === "sheet" || presentation === "full_screen") signInPresentation = presentation;
|
|
193
196
|
const mine = ++generation;
|
|
194
197
|
const next = await read(arg);
|
|
195
198
|
return mine === generation ? next : undefined;
|
|
@@ -198,11 +201,19 @@ async function load(_s: PlaceSummaryState, arg?: unknown): Promise<PlaceSummaryS
|
|
|
198
201
|
const svc = defineService<PlaceSummaryState, {
|
|
199
202
|
load: (s: PlaceSummaryState, arg?: unknown) => Promise<PlaceSummaryState | undefined>;
|
|
200
203
|
retry: (s: PlaceSummaryState) => Promise<PlaceSummaryState | undefined>;
|
|
204
|
+
openCta: (s: PlaceSummaryState) => PlaceSummaryState;
|
|
201
205
|
}>("himiPlaceSummary", {
|
|
202
206
|
state: BLANK,
|
|
203
207
|
actions: {
|
|
204
208
|
load,
|
|
205
209
|
retry: (s) => load(s),
|
|
210
|
+
openCta: (s) => {
|
|
211
|
+
if (s.hideCta || !s.ctaScreenId) return s;
|
|
212
|
+
// No return path: the tile is embedded, so the form closes over its host.
|
|
213
|
+
return navigate(s, s.ctaScreenId === SIGN_IN_SCREEN && signInPresentation
|
|
214
|
+
? { screenId: SIGN_IN_SCREEN, presentation: signInPresentation, args: { mode: "signin", modal: "1" } }
|
|
215
|
+
: { screenId: s.ctaScreenId, args: { mode: s.ctaMode } });
|
|
216
|
+
},
|
|
206
217
|
},
|
|
207
218
|
});
|
|
208
219
|
export { svc };
|
|
@@ -26,6 +26,10 @@ interface AuthRouteInput {
|
|
|
26
26
|
returnScreenId?: string;
|
|
27
27
|
returnId?: string;
|
|
28
28
|
returnChannelId?: string;
|
|
29
|
+
/** Standalone sign-in only: "1" when it was opened as a modal (sheet / cover). */
|
|
30
|
+
modal?: string;
|
|
31
|
+
/** Modal only: the tab whose stack the return screen opens on once the modal closes. */
|
|
32
|
+
returnTab?: string;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
// The screen's boot input survives refresh; consuming it must survive too.
|
|
@@ -61,6 +65,12 @@ function authIntentFromArg(arg: unknown, prev: Pick<S, "authIntent" | "authConte
|
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
/** How the standalone form leaves. A modal is closed: on web `back` pops the tab's stack,
|
|
69
|
+
* not the modal. A pushed form goes back. */
|
|
70
|
+
function leaveNav(): "dismiss" | "back" {
|
|
71
|
+
return routeInput().modal === "1" ? "dismiss" : "back";
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
/** Where a successful sign-in returns to, or null. Never Account itself — that would
|
|
65
75
|
* only push a second copy of the screen the member is already on. */
|
|
66
76
|
function resumeTarget(s: Pick<S, "returnScreenId" | "returnId" | "returnChannelId">): { screenId: string; args?: Record<string, string> } | null {
|
|
@@ -78,11 +88,26 @@ function resumeTarget(s: Pick<S, "returnScreenId" | "returnId" | "returnChannelI
|
|
|
78
88
|
* On the standalone sign-in screen the target is pushed, not a `replace`: on iOS and
|
|
79
89
|
* Android `replace` resets the stack to its root, which would drop the screens the
|
|
80
90
|
* visitor came through. Back from the target shows the form again, and the form sends a
|
|
81
|
-
* member back on appear (settle). With no target the form goes back.
|
|
91
|
+
* member back on appear (settle). With no target the form goes back.
|
|
92
|
+
*
|
|
93
|
+
* A modal form closes. A target pushed from here would open inside the modal (iOS, Android)
|
|
94
|
+
* or under it (web), so a modal that names a `returnTab` hands the target to that tab: the
|
|
95
|
+
* host closes the modal, then pushes it on that tab's stack (Account's member rows). A host
|
|
96
|
+
* showing no such tab (a drawer, a narrow Mac window) drops that request whole, modal and
|
|
97
|
+
* all, so the modal is also dismissed directly: it always closes, and the row opens where
|
|
98
|
+
* the tab exists. With no `returnTab` it only closes, and the screen under it loads again —
|
|
99
|
+
* the screen that opened the modal is the return target. */
|
|
82
100
|
function resumeAfterAuth(next: S): S {
|
|
83
101
|
const target = resumeTarget(next);
|
|
84
102
|
if (!next.isMember) return next;
|
|
85
|
-
|
|
103
|
+
const tab = routeInput().modal === "1" ? routeInput().returnTab ?? "" : "";
|
|
104
|
+
if (target && tab && next.standalone) {
|
|
105
|
+
routeInputConsumed = true;
|
|
106
|
+
void dispatch("himi.open", { presentation: "dismiss" });
|
|
107
|
+
const cleared = derive({ ...next, authIntent: "", authContextName: "", returnScreenId: "", returnId: "", returnChannelId: "" });
|
|
108
|
+
return navigate(cleared, target.args ? { tab, screenId: target.screenId, args: target.args } : { tab, screenId: target.screenId });
|
|
109
|
+
}
|
|
110
|
+
if (!target || routeInput().modal === "1") return next.standalone ? navigate(next, { presentation: leaveNav() }) : next;
|
|
86
111
|
routeInputConsumed = true;
|
|
87
112
|
const cleared = derive({ ...next, authIntent: "", authContextName: "", returnScreenId: "", returnId: "", returnChannelId: "" });
|
|
88
113
|
return navigate(cleared, target);
|
|
@@ -96,11 +121,31 @@ function forwardToSignIn(next: S): S {
|
|
|
96
121
|
if (!next.authIntent && !next.returnScreenId) return next;
|
|
97
122
|
routeInputConsumed = true;
|
|
98
123
|
const args: Record<string, string> = { mode: "signin" };
|
|
99
|
-
for (const key of ["authIntent", "authContextName"
|
|
100
|
-
if (next[key]) args[key === "authIntent" ? "intent" :
|
|
124
|
+
for (const key of ["authIntent", "authContextName"] as const) {
|
|
125
|
+
if (next[key]) args[key === "authIntent" ? "intent" : "contextName"] = next[key];
|
|
126
|
+
}
|
|
127
|
+
return openSignIn(derive({ ...next, authIntent: "", authContextName: "", returnScreenId: "", returnId: "", returnChannelId: "" }),
|
|
128
|
+
args, resumeTarget(next));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Account sends a guest to the standalone sign-in screen, with `after`, the member screen to
|
|
132
|
+
* open once signed in. With a `signInPresentation` appear param it opens as that modal, and
|
|
133
|
+
* `after` goes on Account's own tab (`signInReturnTab`) when the modal closes; pushed, the form
|
|
134
|
+
* pushes `after` itself (resumeAfterAuth). */
|
|
135
|
+
function openSignIn(next: S, args: Record<string, string>, after: { screenId: string; args?: Record<string, string> } | null): S {
|
|
136
|
+
const screenId = next.signInScreen || "himi_sign_in";
|
|
137
|
+
const presentation = signInPresentationRequested;
|
|
138
|
+
const back: Record<string, string> = {};
|
|
139
|
+
if (after) {
|
|
140
|
+
back.returnScreenId = after.screenId;
|
|
141
|
+
if (after.args?.id) back.returnId = after.args.id;
|
|
142
|
+
if (after.args?.channelId) back.returnChannelId = after.args.channelId;
|
|
101
143
|
}
|
|
102
|
-
return navigate(
|
|
103
|
-
|
|
144
|
+
if (!presentation) return navigate(next, { screenId, args: { ...args, ...back } });
|
|
145
|
+
const modalArgs: Record<string, string> = { ...args, modal: "1" };
|
|
146
|
+
// With no tab to open it on, a modal has no way to the member screen: it only closes.
|
|
147
|
+
if (after && signInReturnTabRequested) Object.assign(modalArgs, back, { returnTab: signInReturnTabRequested });
|
|
148
|
+
return navigate(next, { screenId, presentation, args: modalArgs });
|
|
104
149
|
}
|
|
105
150
|
|
|
106
151
|
/** After a load: the standalone sign-in screen sends a member back (a stale link, or a
|
|
@@ -128,8 +173,11 @@ function settle(next: S, arg: unknown, latest = true): S {
|
|
|
128
173
|
// The appear refresh returns `_nav`, which every host applies — binaries from before
|
|
129
174
|
// worker nav dispatch included. Only an arg-less load, whose result iOS
|
|
130
175
|
// discards, dispatches.
|
|
131
|
-
if (strField(arg, "standalone") === "1") return navigate(cleared, { presentation:
|
|
132
|
-
|
|
176
|
+
if (strField(arg, "standalone") === "1") return navigate(cleared, { presentation: leaveNav() });
|
|
177
|
+
// Not from a modal: nothing pushed over it comes back to it, and on iOS the closing modal's
|
|
178
|
+
// own screen reloads here once, after it has asked to close — a late dismiss would close
|
|
179
|
+
// whatever modal is open by then.
|
|
180
|
+
if (routeInput().modal !== "1") void dispatch("himi.open", { presentation: leaveNav() });
|
|
133
181
|
return cleared;
|
|
134
182
|
}
|
|
135
183
|
// Account forwards only on an appear refresh: the boot `load()` has no params and its
|
|
@@ -180,6 +228,10 @@ let appliedSeq = 0;
|
|
|
180
228
|
// The appear params belong to the worker session too, like the two flags above: a probe
|
|
181
229
|
// dropped because the visitor typed must not take them with it.
|
|
182
230
|
let signInScreenRequested = "";
|
|
231
|
+
/** Account only: how it opens the standalone sign-in screen ("" = push). */
|
|
232
|
+
let signInPresentationRequested: "" | "sheet" | "full_screen" = "";
|
|
233
|
+
/** Account only: its tab, where a member screen opens after a modal sign-in. */
|
|
234
|
+
let signInReturnTabRequested = "";
|
|
183
235
|
let standaloneRequested = false;
|
|
184
236
|
let pollIdentityRequested = false;
|
|
185
237
|
// Bumped by every mode switch, so a dropped probe never puts back a mode the visitor left.
|
|
@@ -210,6 +262,9 @@ function appearConfig(s: S, arg: unknown): AppearConfig {
|
|
|
210
262
|
passwordDraft = "";
|
|
211
263
|
}
|
|
212
264
|
signInScreenRequested ||= strField(arg, "signInScreen") || s.signInScreen;
|
|
265
|
+
const presentation = strField(arg, "signInPresentation");
|
|
266
|
+
if (presentation === "sheet" || presentation === "full_screen") signInPresentationRequested = presentation;
|
|
267
|
+
signInReturnTabRequested ||= strField(arg, "signInReturnTab");
|
|
213
268
|
// Only the sign-in screen's route carries `mode`, so it marks the form from the boot load on.
|
|
214
269
|
standaloneRequested ||= s.standalone || appearing || (!routeInputConsumed && !!routeInput().mode);
|
|
215
270
|
pollIdentityRequested ||= s.pollIdentity || strField(arg, "pollIdentity") === "1";
|
|
@@ -676,6 +731,7 @@ const svc = defineService<S, {
|
|
|
676
731
|
signOut: (s: S) => Promise<S>;
|
|
677
732
|
sync: (s: S) => Promise<S | undefined>;
|
|
678
733
|
openMember: (s: S, arg?: unknown) => Promise<S>;
|
|
734
|
+
leave: (s: S) => S;
|
|
679
735
|
restorePublish: (s: S) => S;
|
|
680
736
|
iapRestore: (s: S) => Promise<undefined>;
|
|
681
737
|
}>("himiStoreAccount", {
|
|
@@ -756,7 +812,8 @@ const svc = defineService<S, {
|
|
|
756
812
|
return "next" in r ? r.next : undefined;
|
|
757
813
|
},
|
|
758
814
|
// A row to a member-only screen shows to a guest too. A member opens it; a guest signs
|
|
759
|
-
// in first and the sign-in screen
|
|
815
|
+
// in first, and the sign-in screen then opens the row's screen — as a modal, by closing
|
|
816
|
+
// and pushing it on this tab (openSignIn) — so Back returns here either way.
|
|
760
817
|
openMember: async (s, arg): Promise<S> => {
|
|
761
818
|
const screenId = strField(arg, "screenId");
|
|
762
819
|
if (!screenId) return s;
|
|
@@ -764,8 +821,10 @@ const svc = defineService<S, {
|
|
|
764
821
|
// From the state as it is now: a probe may have landed during the identity read.
|
|
765
822
|
const now = svc.getState();
|
|
766
823
|
if (member) return navigate(now, { screenId });
|
|
767
|
-
return
|
|
824
|
+
return openSignIn(now, { mode: "signin" }, { screenId });
|
|
768
825
|
},
|
|
826
|
+
// The standalone form's Continue: leaves the form the way it was opened.
|
|
827
|
+
leave: (s) => navigate(s, { presentation: leaveNav() }),
|
|
769
828
|
// Typing means any focus request was delivered: clear the tokens (safe while mounted, since
|
|
770
829
|
// bumpToken never repeats), so a visit rarely ends — and a pooled form rarely reopens —
|
|
771
830
|
// holding one.
|