@wix/himalaya-cli 0.1378.0 → 0.1379.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/sdk/app-info/src/index.d.ts +4 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/ecom/src/extensions.d.ts +113 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/app-info.mjs +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-ecom.mjs +77 -0
- package/dist/cli.mjs +23 -23
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/importable-sdks.md +1 -1
- package/guides/sdk-reference.json +128 -2
- package/guides/wix-api-usage.md +2 -0
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +23 -0
- package/templates/beauty-salon/dev/index.ts +2611 -1
- package/templates/beauty-salon/himalaya.content.json +9 -0
- package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/beauty-salon/tier5-src/_shared/member-access.ts +14 -0
- package/templates/beauty-salon/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/beauty-salon/tier5-src/_shared/member-address.ts +129 -0
- package/templates/beauty-salon/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/beauty-salon-owner/dev/index.ts +5 -27
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/branded-lite/config.ts +23 -0
- package/templates/branded-lite/dev/index.ts +2614 -2
- package/templates/branded-lite/himalaya.content.json +9 -0
- package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/branded-lite/tier5-src/_shared/member-access.ts +14 -0
- package/templates/branded-lite/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/branded-lite/tier5-src/_shared/member-address.ts +129 -0
- package/templates/branded-lite/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/community-club/dev/index.ts +3 -1
- package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/community-club/tier5-src/_shared/member-access.ts +14 -0
- package/templates/community-club/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/community-club/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/community-club-owner/dev/index.ts +5 -27
- package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/community-club-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/community-club-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/events-meetups/dev/index.ts +3 -1
- package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/events-meetups/tier5-src/_shared/member-access.ts +14 -0
- package/templates/events-meetups/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/events-meetups-owner/dev/index.ts +5 -27
- package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/events-meetups-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/events-meetups-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/gym-fitness/config.ts +23 -0
- package/templates/gym-fitness/dev/index.ts +2611 -1
- package/templates/gym-fitness/himalaya.content.json +9 -0
- package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/gym-fitness/tier5-src/_shared/member-access.ts +14 -0
- package/templates/gym-fitness/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/gym-fitness/tier5-src/_shared/member-address.ts +129 -0
- package/templates/gym-fitness/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/gym-fitness-owner/dev/index.ts +5 -27
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/nonprofit-cause/config.ts +7 -0
- package/templates/nonprofit-cause/dev/index.ts +762 -1
- package/templates/nonprofit-cause/himalaya.content.json +3 -0
- package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/nonprofit-cause/tier5-src/_shared/member-access.ts +14 -0
- package/templates/nonprofit-cause/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/nonprofit-cause/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/nonprofit-cause-owner/dev/index.ts +5 -27
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/owner-lite/dev/index.ts +5 -27
- package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/owner-lite/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/owner-lite/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/podcast-creator/config.ts +7 -0
- package/templates/podcast-creator/dev/index.ts +762 -1
- package/templates/podcast-creator/himalaya.content.json +3 -0
- package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/podcast-creator/tier5-src/_shared/member-access.ts +14 -0
- package/templates/podcast-creator/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/podcast-creator/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/podcast-creator-owner/dev/index.ts +5 -27
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/portfolio-creative/config.ts +23 -0
- package/templates/portfolio-creative/dev/index.ts +2611 -1
- package/templates/portfolio-creative/himalaya.content.json +9 -0
- package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/portfolio-creative/tier5-src/_shared/member-access.ts +14 -0
- package/templates/portfolio-creative/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/portfolio-creative/tier5-src/_shared/member-address.ts +129 -0
- package/templates/portfolio-creative/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/portfolio-creative-owner/dev/index.ts +5 -27
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/restaurant/config.ts +23 -0
- package/templates/restaurant/dev/index.ts +2611 -1
- package/templates/restaurant/himalaya.content.json +9 -0
- package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/restaurant/tier5-src/_shared/member-access.ts +14 -0
- package/templates/restaurant/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/restaurant/tier5-src/_shared/member-address.ts +129 -0
- package/templates/restaurant/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/restaurant-owner/dev/index.ts +5 -27
- package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/restaurant-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/restaurant-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/retail-store/config.ts +23 -0
- package/templates/retail-store/dev/index.ts +2611 -1
- package/templates/retail-store/himalaya.content.json +9 -0
- package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/retail-store/tier5-src/_shared/member-access.ts +14 -0
- package/templates/retail-store/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/retail-store/tier5-src/_shared/member-address.ts +129 -0
- package/templates/retail-store/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-address/index.ts +223 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-addresses/index.ts +202 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/retail-store-owner/dev/index.ts +5 -27
- package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/retail-store-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/retail-store-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
- package/templates/yoga-studio/config.ts +7 -0
- package/templates/yoga-studio/dev/index.ts +762 -1
- package/templates/yoga-studio/himalaya.content.json +3 -0
- package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +3 -0
- package/templates/yoga-studio/tier5-src/_shared/member-access.ts +14 -0
- package/templates/yoga-studio/tier5-src/_shared/member-account-routes.ts +43 -0
- package/templates/yoga-studio/tier5-src/_shared/saved-card.ts +20 -0
- package/templates/yoga-studio/tier5-src/himi-branded-lite-wallet/index.ts +217 -0
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +17 -0
- package/templates/yoga-studio-owner/dev/index.ts +5 -27
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +99 -40
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-widget-oauth.ts +42 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-widget-view.ts +6 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +12 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// Tier-5 bundle: Branded Lite — My Wallet (the member's saved payment methods).
|
|
2
|
+
//
|
|
3
|
+
// The cards a member chose to save at checkout, read from Wix Payments on the member's
|
|
4
|
+
// own site (@himalaya/wix-ecom listMySavedPaymentMethods — the native transport routes it there). Like the site's My Wallet
|
|
5
|
+
// page, a member can make one the default for checkout or remove one — there is no
|
|
6
|
+
// "add a card" here: a card is saved while paying. Only the last four digits, the
|
|
7
|
+
// expiry and the cardholder name ever reach the app.
|
|
8
|
+
import { defineService } from "@himalaya/state";
|
|
9
|
+
import {
|
|
10
|
+
deleteSavedPaymentMethod,
|
|
11
|
+
listMySavedPaymentMethods,
|
|
12
|
+
markSavedPaymentMethodPrimary,
|
|
13
|
+
type WixSavedPaymentMethod,
|
|
14
|
+
} from "@himalaya/wix-ecom";
|
|
15
|
+
import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
|
|
16
|
+
import { assertMemberAccess, memberAccess, memberAccessDenied, memberChanged, type MemberAccess } from "../_shared/member-access.js";
|
|
17
|
+
import { memberAccountRoutes } from "../_shared/member-account-routes.js";
|
|
18
|
+
import { cardBrand } from "../_shared/saved-card.js";
|
|
19
|
+
|
|
20
|
+
interface CardRow {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
detail: string;
|
|
24
|
+
isPrimary: boolean;
|
|
25
|
+
notPrimary: boolean;
|
|
26
|
+
confirming: boolean;
|
|
27
|
+
notConfirming: boolean;
|
|
28
|
+
hideActions: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface State {
|
|
32
|
+
status: "loading" | "ready" | "error";
|
|
33
|
+
rows: CardRow[];
|
|
34
|
+
message: string;
|
|
35
|
+
errorText: string;
|
|
36
|
+
needsSignIn: boolean;
|
|
37
|
+
unavailable: boolean;
|
|
38
|
+
noUnavailable: boolean;
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
notLoading: boolean;
|
|
41
|
+
notErrored: boolean;
|
|
42
|
+
noSignIn: boolean;
|
|
43
|
+
hideList: boolean;
|
|
44
|
+
noEmpty: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let member: MemberAccess | undefined;
|
|
48
|
+
let methods: WixSavedPaymentMethod[] = [];
|
|
49
|
+
let confirmId = "";
|
|
50
|
+
let busy = false;
|
|
51
|
+
|
|
52
|
+
function rowOf(method: WixSavedPaymentMethod, now: Date): CardRow {
|
|
53
|
+
const id = method.id ?? "";
|
|
54
|
+
const card = method.paymentMethod?.cardInfo;
|
|
55
|
+
const last4 = card?.lastFourDigits?.trim() ?? "";
|
|
56
|
+
const isPayPal = (method.paymentMethod?.typeId ?? "").toLowerCase() === "paypal";
|
|
57
|
+
const name = isPayPal ? "PayPal" : cardBrand(card?.bin ?? "") || copyParam("wallet.cardLabel", "Card");
|
|
58
|
+
const title = last4 ? `${name} •••• ${last4}` : name;
|
|
59
|
+
const month = card?.expirationMonth, year = card?.expirationYear;
|
|
60
|
+
let expiry = "";
|
|
61
|
+
if (month && year) {
|
|
62
|
+
const mmyy = `${String(month).padStart(2, "0")}/${String(year).slice(-2)}`;
|
|
63
|
+
// A card is good through the last day of its expiry month.
|
|
64
|
+
const expired = year < now.getFullYear() || (year === now.getFullYear() && month < now.getMonth() + 1);
|
|
65
|
+
expiry = expired
|
|
66
|
+
? copyTemplate("wallet.expiredLabel", "Expired {date}", { date: mmyy })
|
|
67
|
+
: copyTemplate("wallet.expiresLabel", "Expires {date}", { date: mmyy });
|
|
68
|
+
}
|
|
69
|
+
const isPrimary = method.primary === true;
|
|
70
|
+
const confirming = id === confirmId;
|
|
71
|
+
return {
|
|
72
|
+
id,
|
|
73
|
+
title,
|
|
74
|
+
detail: [expiry, card?.cardholderName?.trim()].filter(Boolean).join(" · "),
|
|
75
|
+
isPrimary,
|
|
76
|
+
notPrimary: !isPrimary,
|
|
77
|
+
confirming,
|
|
78
|
+
notConfirming: !confirming,
|
|
79
|
+
hideActions: confirming,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function derive(state: State): State {
|
|
84
|
+
const ready = state.status === "ready" && !state.unavailable;
|
|
85
|
+
const now = new Date();
|
|
86
|
+
// The default card leads, like the site's own page.
|
|
87
|
+
const ordered = [...methods].sort((a, b) => Number(b.primary === true) - Number(a.primary === true));
|
|
88
|
+
const rows = ready ? ordered.filter((m) => !!m.id).map((m) => rowOf(m, now)) : [];
|
|
89
|
+
return {
|
|
90
|
+
...state,
|
|
91
|
+
rows,
|
|
92
|
+
noUnavailable: !state.unavailable,
|
|
93
|
+
isLoading: state.status === "loading",
|
|
94
|
+
notLoading: state.status !== "loading",
|
|
95
|
+
notErrored: state.status !== "error",
|
|
96
|
+
noSignIn: !ready || !state.needsSignIn,
|
|
97
|
+
hideList: !ready || state.needsSignIn || rows.length === 0,
|
|
98
|
+
noEmpty: !ready || state.needsSignIn || rows.length > 0,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const INITIAL: State = derive({
|
|
103
|
+
status: "loading", rows: [], message: "", errorText: "", needsSignIn: false, unavailable: false, noUnavailable: true,
|
|
104
|
+
isLoading: true, notLoading: false, notErrored: true, noSignIn: true, hideList: true, noEmpty: true,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// 100 per page is the service maximum; the page cap only stops a cursor that never ends.
|
|
108
|
+
const MAX_PAGES = 10;
|
|
109
|
+
|
|
110
|
+
async function allSavedPaymentMethods(): Promise<WixSavedPaymentMethod[]> {
|
|
111
|
+
const all: WixSavedPaymentMethod[] = [];
|
|
112
|
+
let cursor = "";
|
|
113
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
114
|
+
const response = await listMySavedPaymentMethods({ limit: 100, ...(cursor ? { cursor } : {}) });
|
|
115
|
+
all.push(...(response.savedPaymentMethods ?? []));
|
|
116
|
+
const next = response.pagingMetadata?.cursors?.next ?? "";
|
|
117
|
+
if (response.pagingMetadata?.hasNext === false || !next || next === cursor) break;
|
|
118
|
+
cursor = next;
|
|
119
|
+
}
|
|
120
|
+
return all;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function load(state: State, arg?: unknown): Promise<State> {
|
|
124
|
+
stashCopy(arg);
|
|
125
|
+
confirmId = "";
|
|
126
|
+
if (!(await memberAccountRoutes()).wallet) {
|
|
127
|
+
methods = [];
|
|
128
|
+
return derive({ ...state, status: "ready", unavailable: true, needsSignIn: false, message: "", errorText: "" });
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
member = await memberAccess();
|
|
132
|
+
if (!member.email) {
|
|
133
|
+
methods = [];
|
|
134
|
+
return derive({ ...state, status: "ready", unavailable: false, needsSignIn: true, message: "", errorText: "" });
|
|
135
|
+
}
|
|
136
|
+
const all = await allSavedPaymentMethods();
|
|
137
|
+
await assertMemberAccess(member);
|
|
138
|
+
methods = all;
|
|
139
|
+
// A fresh load drops the last write's confirmation; write() sets it again after this.
|
|
140
|
+
return derive({ ...state, status: "ready", unavailable: false, needsSignIn: false, message: "", errorText: "" });
|
|
141
|
+
} catch (error) {
|
|
142
|
+
methods = [];
|
|
143
|
+
return derive({
|
|
144
|
+
...state,
|
|
145
|
+
status: "error",
|
|
146
|
+
unavailable: false,
|
|
147
|
+
message: "",
|
|
148
|
+
errorText: memberAccessDenied(error)
|
|
149
|
+
? copyParam("wallet.accessErrorText", "Your wallet is unavailable for this account. Try signing in again.")
|
|
150
|
+
: copyParam("wallet.loadErrorText", "Your saved cards could not be loaded."),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function argId(arg: unknown): string {
|
|
156
|
+
const id = (arg as { id?: unknown } | null)?.id;
|
|
157
|
+
return typeof id === "string" ? id : "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function write(state: State, run: () => Promise<unknown>, done: string, failed: string): Promise<State> {
|
|
161
|
+
if (busy || !member?.email) return state;
|
|
162
|
+
busy = true;
|
|
163
|
+
try {
|
|
164
|
+
await assertMemberAccess(member);
|
|
165
|
+
await run();
|
|
166
|
+
const next = await load(state);
|
|
167
|
+
return next.status === "ready" ? { ...next, message: done } : next;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (await memberChanged(member, error)) return load(state);
|
|
170
|
+
return derive({ ...state, message: failed });
|
|
171
|
+
} finally {
|
|
172
|
+
busy = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const svc = defineService<State, {
|
|
177
|
+
load: (state: State, arg?: unknown) => Promise<State>;
|
|
178
|
+
retry: (state: State) => Promise<State>;
|
|
179
|
+
setPrimary: (state: State, arg?: unknown) => Promise<State>;
|
|
180
|
+
askRemove: (state: State, arg?: unknown) => State;
|
|
181
|
+
keep: (state: State) => State;
|
|
182
|
+
remove: (state: State, arg?: unknown) => Promise<State>;
|
|
183
|
+
}>("himiBrandedWallet", {
|
|
184
|
+
state: INITIAL,
|
|
185
|
+
actions: {
|
|
186
|
+
load,
|
|
187
|
+
retry: (state) => load(derive({ ...state, status: "loading", message: "" })),
|
|
188
|
+
setPrimary: (state, arg) => {
|
|
189
|
+
const id = argId(arg);
|
|
190
|
+
const method = methods.find((m) => m.id === id);
|
|
191
|
+
if (!id || !method || method.primary) return Promise.resolve(state);
|
|
192
|
+
return write(state, () => markSavedPaymentMethodPrimary(id),
|
|
193
|
+
copyParam("wallet.primaryDone", "Default card updated."),
|
|
194
|
+
copyParam("wallet.primaryFailed", "The default card could not be changed. Try again."));
|
|
195
|
+
},
|
|
196
|
+
askRemove: (state, arg) => {
|
|
197
|
+
const id = argId(arg);
|
|
198
|
+
if (!methods.some((m) => m.id === id)) return state;
|
|
199
|
+
confirmId = id;
|
|
200
|
+
return derive({ ...state, message: "" });
|
|
201
|
+
},
|
|
202
|
+
keep: (state) => {
|
|
203
|
+
confirmId = "";
|
|
204
|
+
return derive(state);
|
|
205
|
+
},
|
|
206
|
+
remove: (state, arg) => {
|
|
207
|
+
// Only the card the member is confirming — a stale row tap removes nothing.
|
|
208
|
+
const id = argId(arg);
|
|
209
|
+
if (!id || id !== confirmId) return Promise.resolve(state);
|
|
210
|
+
return write(state, () => deleteSavedPaymentMethod(id),
|
|
211
|
+
copyParam("wallet.removeDone", "Card removed."),
|
|
212
|
+
copyParam("wallet.removeFailed", "The card could not be removed. Try again."));
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
export { svc };
|
|
@@ -13,6 +13,7 @@ import { dispatch } from "@himalaya/dispatch";
|
|
|
13
13
|
import { searchOrders, type WixOrder } from "@himalaya/wix-ecom";
|
|
14
14
|
import { guestProfile, loadMemberProfile, strOf, fmtDate, titleCase, type AccountActivityRow } from "../_shared/himi-account";
|
|
15
15
|
import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
|
|
16
|
+
import { memberAccountRoutes } from "../_shared/member-account-routes.js";
|
|
16
17
|
|
|
17
18
|
interface AuthRouteInput {
|
|
18
19
|
intent?: string;
|
|
@@ -205,6 +206,14 @@ interface S {
|
|
|
205
206
|
activityEmptyText: string;
|
|
206
207
|
hasActivity: boolean;
|
|
207
208
|
noActivity: boolean;
|
|
209
|
+
/** Set once a descriptor asks for the member-account links (appear param
|
|
210
|
+
* `memberAccountLinks: "1"`). Only then does the probe read app_info, so a descriptor
|
|
211
|
+
* that renders no such link need not declare that capability. */
|
|
212
|
+
memberAccountLinks: boolean;
|
|
213
|
+
/** Hides My Addresses where this runtime cannot reach the address book. */
|
|
214
|
+
noMemberAddresses: boolean;
|
|
215
|
+
/** Hides My Wallet where this runtime cannot reach saved cards. */
|
|
216
|
+
noMemberWallet: boolean;
|
|
208
217
|
}
|
|
209
218
|
|
|
210
219
|
function derive(s: S): S {
|
|
@@ -278,6 +287,8 @@ async function orderRows(memberEmail: string): Promise<AccountActivityRow[]> {
|
|
|
278
287
|
async function probe(s: S, arg?: unknown): Promise<S> {
|
|
279
288
|
const intent = authIntentFromArg(arg, s);
|
|
280
289
|
const profile = await loadMemberProfile(copyParam("storeAccount.guestDetail", "Sign in to keep your cart and orders connected."));
|
|
290
|
+
const memberAccountLinks = s.memberAccountLinks || strField(arg, "memberAccountLinks") === "1";
|
|
291
|
+
const routes = memberAccountLinks ? await memberAccountRoutes() : { addresses: false, wallet: false };
|
|
281
292
|
let activityRows: AccountActivityRow[] = [];
|
|
282
293
|
if (profile.isMember) {
|
|
283
294
|
try {
|
|
@@ -301,6 +312,9 @@ async function probe(s: S, arg?: unknown): Promise<S> {
|
|
|
301
312
|
noMemberImage: profile.noMemberImage,
|
|
302
313
|
email: profile.memberEmail || s.email,
|
|
303
314
|
message: "",
|
|
315
|
+
memberAccountLinks,
|
|
316
|
+
noMemberAddresses: !routes.addresses,
|
|
317
|
+
noMemberWallet: !routes.wallet,
|
|
304
318
|
activityRows,
|
|
305
319
|
activityTitle: copyParam("storeAccount.activityTitle", "Previous orders"),
|
|
306
320
|
activitySummary: activityRows.length
|
|
@@ -394,6 +408,9 @@ const svc = defineService<S, {
|
|
|
394
408
|
activityEmptyText: "No previous orders for this member yet.",
|
|
395
409
|
hasActivity: false,
|
|
396
410
|
noActivity: true,
|
|
411
|
+
memberAccountLinks: false,
|
|
412
|
+
noMemberAddresses: true,
|
|
413
|
+
noMemberWallet: true,
|
|
397
414
|
}),
|
|
398
415
|
actions: {
|
|
399
416
|
load: (s, arg) => { stashCopy(arg); return probe(s, arg); },
|
|
@@ -3187,6 +3187,7 @@ const SCREENS = runtimeSetting({
|
|
|
3187
3187
|
"onAppear": {
|
|
3188
3188
|
"actionId": "tier5.himiStoreAccount.refresh",
|
|
3189
3189
|
"params": {
|
|
3190
|
+
"memberAccountLinks": "1",
|
|
3190
3191
|
"copy": "{\"account.subtitle\":\"RSVPs, groups and saved content in one place.\",\"storeAccount.authBody\":\"Sign in to continue — RSVPs and groups stay with you.\",\"storeAccount.authBodyRegister\":\"Create a member account to continue — RSVPs and groups stay with you.\"}"
|
|
3191
3192
|
}
|
|
3192
3193
|
}
|
|
@@ -3197,7 +3198,8 @@ const SCREENS = runtimeSetting({
|
|
|
3197
3198
|
"integrity": "",
|
|
3198
3199
|
"contentType": "application/javascript+ts-bundle",
|
|
3199
3200
|
"declaredCapabilities": [
|
|
3200
|
-
"wix_api"
|
|
3201
|
+
"wix_api",
|
|
3202
|
+
"app_info"
|
|
3201
3203
|
],
|
|
3202
3204
|
"minBinaryVersion": "0.2.0",
|
|
3203
3205
|
"bundleVersion": "0.0.1"
|
|
@@ -65,6 +65,8 @@ export const VERTICAL_ROOT_SCREENS: Readonly<Record<string, readonly string[]>>
|
|
|
65
65
|
* (`brandedLiteScreenOwners`, checked by the app's hosted-mode tests), so a screen added
|
|
66
66
|
* to a vertical without being listed here fails the build. */
|
|
67
67
|
export const HOSTED_SCREEN_VERTICALS: Readonly<Record<string, readonly BrandedLiteVertical[]>> = {
|
|
68
|
+
himi_address: ["restaurants", "store"],
|
|
69
|
+
himi_addresses: ["restaurants", "store"],
|
|
68
70
|
himi_badge: ["badges"],
|
|
69
71
|
himi_badges: ["badges"],
|
|
70
72
|
himi_blog: ["blog"],
|
|
@@ -127,6 +129,7 @@ export const HOSTED_SCREEN_VERTICALS: Readonly<Record<string, readonly BrandedLi
|
|
|
127
129
|
himi_video: ["videos"],
|
|
128
130
|
himi_video_channel: ["videos"],
|
|
129
131
|
himi_videos: ["videos"],
|
|
132
|
+
himi_wallet: ["bookings", "plans", "restaurants", "store"],
|
|
130
133
|
};
|
|
131
134
|
|
|
132
135
|
/** The templated (`<prefix>[_/]<id>`) detail routes each vertical owns, pinned the same way. */
|
|
@@ -36,3 +36,17 @@ export async function assertMemberAccess(member: MemberAccess): Promise<void> {
|
|
|
36
36
|
export function memberAccessDenied(error: unknown): boolean {
|
|
37
37
|
return (error as { name?: string } | null)?.name === "MemberAccessChanged" || /(?:HTTP\s*(?:401|403)|READ_ORDER_FORBIDDEN|permission denied|forbidden)/i.test(String(error));
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/** Did this write fail because the member changed (signed out, or another account)? Then
|
|
41
|
+
* the screen reloads for whoever is signed in now. A 401/403 for the SAME member is only a
|
|
42
|
+
* failed write: the caller keeps what the member typed and says so. */
|
|
43
|
+
export async function memberChanged(member: MemberAccess | undefined, error: unknown): Promise<boolean> {
|
|
44
|
+
if ((error as { name?: string } | null)?.name === "MemberAccessChanged") return true;
|
|
45
|
+
if (!member || !memberAccessDenied(error)) return false;
|
|
46
|
+
try {
|
|
47
|
+
await assertMemberAccess(member);
|
|
48
|
+
return false;
|
|
49
|
+
} catch {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Can this host reach the member account routes My Addresses and My Wallet need?
|
|
2
|
+
//
|
|
3
|
+
// Both are served OFF www.wixapis.com (the address book on ecom.wix.com, saved cards on
|
|
4
|
+
// the member's own site), so only a native runtime whose WixApiCapability pins them can
|
|
5
|
+
// call them: HimalayaCore 1.4.0 and later. The web bridges refuse absolute URLs, and a
|
|
6
|
+
// hosted app (Spaces) signs its calls with a capability pinned to www.wixapis.com. Saved
|
|
7
|
+
// cards also need the shell to have bound its own site (app_info `memberSiteBound`): a
|
|
8
|
+
// multi-app host such as Himi Player binds none, so its wallet route has no host. The
|
|
9
|
+
// Account screen hides a link whose route is unreachable, and the screen says so instead
|
|
10
|
+
// of failing a load.
|
|
11
|
+
import { get as getAppInfo } from "@himalaya/app-info";
|
|
12
|
+
import { isHostedWorker } from "./hosted-checkout.js";
|
|
13
|
+
|
|
14
|
+
/** The HimalayaCore version whose WixApiCapability pins these routes. Checked here, at run
|
|
15
|
+
* time: the screens declare no `minBinaryVersion`, because a release takes its highest
|
|
16
|
+
* screen floor as its own and would then refuse every older binary. */
|
|
17
|
+
export const MEMBER_ACCOUNT_ROUTES_MIN_BINARY = "1.4.0";
|
|
18
|
+
|
|
19
|
+
function atLeast(version: string, floor: string): boolean {
|
|
20
|
+
const parts = (v: string) => v.split("-")[0].split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
21
|
+
const a = parts(version), b = parts(floor);
|
|
22
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
23
|
+
const x = a[i] ?? 0, y = b[i] ?? 0;
|
|
24
|
+
if (x !== y) return x > y;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface MemberAccountRoutes {
|
|
30
|
+
/** The address book on ecom.wix.com (My Addresses). */
|
|
31
|
+
addresses: boolean;
|
|
32
|
+
/** Saved cards on the member's own site (My Wallet). */
|
|
33
|
+
wallet: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function memberAccountRoutes(): Promise<MemberAccountRoutes> {
|
|
37
|
+
if (isHostedWorker()) return { addresses: false, wallet: false };
|
|
38
|
+
const info = await getAppInfo().catch(() => undefined);
|
|
39
|
+
if (!info) return { addresses: false, wallet: false };
|
|
40
|
+
const native = info.platform === "ios" || info.platform === "android" || info.platform === "macos";
|
|
41
|
+
const addresses = native && atLeast(info.binaryVersion ?? "", MEMBER_ACCOUNT_ROUTES_MIN_BINARY);
|
|
42
|
+
return { addresses, wallet: addresses && info.memberSiteBound === true };
|
|
43
|
+
}
|
|
@@ -13,6 +13,7 @@ import { dispatch } from "@himalaya/dispatch";
|
|
|
13
13
|
import { searchOrders, type WixOrder } from "@himalaya/wix-ecom";
|
|
14
14
|
import { guestProfile, loadMemberProfile, strOf, fmtDate, titleCase, type AccountActivityRow } from "../_shared/himi-account";
|
|
15
15
|
import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
|
|
16
|
+
import { memberAccountRoutes } from "../_shared/member-account-routes.js";
|
|
16
17
|
|
|
17
18
|
interface AuthRouteInput {
|
|
18
19
|
intent?: string;
|
|
@@ -205,6 +206,14 @@ interface S {
|
|
|
205
206
|
activityEmptyText: string;
|
|
206
207
|
hasActivity: boolean;
|
|
207
208
|
noActivity: boolean;
|
|
209
|
+
/** Set once a descriptor asks for the member-account links (appear param
|
|
210
|
+
* `memberAccountLinks: "1"`). Only then does the probe read app_info, so a descriptor
|
|
211
|
+
* that renders no such link need not declare that capability. */
|
|
212
|
+
memberAccountLinks: boolean;
|
|
213
|
+
/** Hides My Addresses where this runtime cannot reach the address book. */
|
|
214
|
+
noMemberAddresses: boolean;
|
|
215
|
+
/** Hides My Wallet where this runtime cannot reach saved cards. */
|
|
216
|
+
noMemberWallet: boolean;
|
|
208
217
|
}
|
|
209
218
|
|
|
210
219
|
function derive(s: S): S {
|
|
@@ -278,6 +287,8 @@ async function orderRows(memberEmail: string): Promise<AccountActivityRow[]> {
|
|
|
278
287
|
async function probe(s: S, arg?: unknown): Promise<S> {
|
|
279
288
|
const intent = authIntentFromArg(arg, s);
|
|
280
289
|
const profile = await loadMemberProfile(copyParam("storeAccount.guestDetail", "Sign in to keep your cart and orders connected."));
|
|
290
|
+
const memberAccountLinks = s.memberAccountLinks || strField(arg, "memberAccountLinks") === "1";
|
|
291
|
+
const routes = memberAccountLinks ? await memberAccountRoutes() : { addresses: false, wallet: false };
|
|
281
292
|
let activityRows: AccountActivityRow[] = [];
|
|
282
293
|
if (profile.isMember) {
|
|
283
294
|
try {
|
|
@@ -301,6 +312,9 @@ async function probe(s: S, arg?: unknown): Promise<S> {
|
|
|
301
312
|
noMemberImage: profile.noMemberImage,
|
|
302
313
|
email: profile.memberEmail || s.email,
|
|
303
314
|
message: "",
|
|
315
|
+
memberAccountLinks,
|
|
316
|
+
noMemberAddresses: !routes.addresses,
|
|
317
|
+
noMemberWallet: !routes.wallet,
|
|
304
318
|
activityRows,
|
|
305
319
|
activityTitle: copyParam("storeAccount.activityTitle", "Previous orders"),
|
|
306
320
|
activitySummary: activityRows.length
|
|
@@ -394,6 +408,9 @@ const svc = defineService<S, {
|
|
|
394
408
|
activityEmptyText: "No previous orders for this member yet.",
|
|
395
409
|
hasActivity: false,
|
|
396
410
|
noActivity: true,
|
|
411
|
+
memberAccountLinks: false,
|
|
412
|
+
noMemberAddresses: true,
|
|
413
|
+
noMemberWallet: true,
|
|
397
414
|
}),
|
|
398
415
|
actions: {
|
|
399
416
|
load: (s, arg) => { stashCopy(arg); return probe(s, arg); },
|
|
@@ -60950,22 +60950,6 @@ const SCREENS = runtimeSetting({
|
|
|
60950
60950
|
"props": {
|
|
60951
60951
|
"spacing": 8,
|
|
60952
60952
|
"children": [
|
|
60953
|
-
{
|
|
60954
|
-
"id": "",
|
|
60955
|
-
"body": {
|
|
60956
|
-
"package": "himalaya",
|
|
60957
|
-
"type": "Text",
|
|
60958
|
-
"props": {
|
|
60959
|
-
"text": "$service:himiOwnerLiteAria.widget.badge",
|
|
60960
|
-
"style": "footnote",
|
|
60961
|
-
"color": "textSecondary",
|
|
60962
|
-
"maxLines": 12
|
|
60963
|
-
}
|
|
60964
|
-
},
|
|
60965
|
-
"modifiers": {
|
|
60966
|
-
"hiddenPath": "$service:himiOwnerLiteAria.widget.badgeHidden"
|
|
60967
|
-
}
|
|
60968
|
-
},
|
|
60969
60953
|
{
|
|
60970
60954
|
"id": "",
|
|
60971
60955
|
"body": {
|
|
@@ -61002,21 +60986,21 @@ const SCREENS = runtimeSetting({
|
|
|
61002
60986
|
"package": "himalaya",
|
|
61003
60987
|
"type": "Text",
|
|
61004
60988
|
"props": {
|
|
61005
|
-
"text": "$service:himiOwnerLiteAria.widget.
|
|
60989
|
+
"text": "$service:himiOwnerLiteAria.widget.notice",
|
|
61006
60990
|
"style": "footnote",
|
|
61007
60991
|
"color": "textSecondary",
|
|
61008
60992
|
"maxLines": 12
|
|
61009
60993
|
}
|
|
61010
60994
|
},
|
|
61011
60995
|
"modifiers": {
|
|
61012
|
-
"hiddenPath": "$service:himiOwnerLiteAria.widget.
|
|
60996
|
+
"hiddenPath": "$service:himiOwnerLiteAria.widget.noticeHidden"
|
|
61013
60997
|
}
|
|
61014
60998
|
},
|
|
61015
60999
|
{
|
|
61016
61000
|
"id": "himi_owner_lite_aria.widget.OAUTH_REQUIRED.footer",
|
|
61017
61001
|
"body": {
|
|
61018
61002
|
"package": "himalaya",
|
|
61019
|
-
"type": "
|
|
61003
|
+
"type": "VStack",
|
|
61020
61004
|
"props": {
|
|
61021
61005
|
"spacing": 8,
|
|
61022
61006
|
"children": [
|
|
@@ -61028,6 +61012,7 @@ const SCREENS = runtimeSetting({
|
|
|
61028
61012
|
"props": {
|
|
61029
61013
|
"title": "$service:himiOwnerLiteAria.widget.primaryLabel",
|
|
61030
61014
|
"style": "primary",
|
|
61015
|
+
"fullWidth": true,
|
|
61031
61016
|
"action": {
|
|
61032
61017
|
"actionId": "tier5.himiOwnerLiteAria.widgetPrimary"
|
|
61033
61018
|
}
|
|
@@ -61045,6 +61030,7 @@ const SCREENS = runtimeSetting({
|
|
|
61045
61030
|
"props": {
|
|
61046
61031
|
"title": "$service:himiOwnerLiteAria.widget.secondaryLabel",
|
|
61047
61032
|
"style": "secondary",
|
|
61033
|
+
"fullWidth": true,
|
|
61048
61034
|
"action": {
|
|
61049
61035
|
"actionId": "tier5.himiOwnerLiteAria.widgetSecondary"
|
|
61050
61036
|
}
|
|
@@ -61053,14 +61039,6 @@ const SCREENS = runtimeSetting({
|
|
|
61053
61039
|
"modifiers": {
|
|
61054
61040
|
"hiddenPath": "$service:himiOwnerLiteAria.widget.secondaryHidden"
|
|
61055
61041
|
}
|
|
61056
|
-
},
|
|
61057
|
-
{
|
|
61058
|
-
"id": "",
|
|
61059
|
-
"body": {
|
|
61060
|
-
"package": "himalaya",
|
|
61061
|
-
"type": "Spacer",
|
|
61062
|
-
"props": {}
|
|
61063
|
-
}
|
|
61064
61042
|
}
|
|
61065
61043
|
]
|
|
61066
61044
|
}
|