@wix/himalaya-cli 0.1323.0 → 0.1325.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/stdlib/flows/checkout/src/index.d.ts +6 -10
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/order-refs.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/purchase-fields.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/index.d.ts +9 -35
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/comments-v1/src/extensions.d.ts +79 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/groups/src/extensions.d.ts +221 -14
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/groups/src/index.d.ts +0 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/social-feed/src/index.d.ts +38 -21
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-v1/src/display.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/checkout.mjs +30 -13
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +20 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +2890 -54
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-comments.mjs +80 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-groups.mjs +45 -17
- package/dist/cli.mjs +5 -4
- package/fixtures/wix-canned.json +61 -6
- package/guides/iap-pricing.md +9 -0
- package/guides/iap-screen-adoption.md +77 -0
- package/guides/importable-sdks.md +2 -0
- package/guides/index.json +6 -0
- package/guides/release-notes.md +25 -0
- package/guides/sdk-reference.json +539 -32
- package/guides/wix-api-usage.md +5 -0
- package/package.json +2 -2
- package/templates/beauty-salon/config.ts +1 -1
- package/templates/beauty-salon/dev/index.ts +46 -18
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/beauty-salon/tier5-src/_shared/himi-store-collection.ts +1 -1
- package/templates/beauty-salon/tier5-src/_shared/home-service.ts +2 -1
- package/templates/beauty-salon/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/beauty-salon/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +48 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/beauty-salon/tier5-src/himi-branded-lite-order/index.ts +24 -3
- package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +24 -3
- package/templates/beauty-salon/tier5-src/himi-store-saved/index.ts +8 -3
- package/templates/beauty-salon/tier5-src/himi-store-shop/index.ts +10 -0
- package/templates/beauty-salon/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/beauty-salon-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/branded-lite/config.ts +1 -8
- package/templates/branded-lite/dev/index.ts +46 -134
- package/templates/branded-lite/himalaya.content.json +0 -3
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/branded-lite/tier5-src/_shared/himi-store-collection.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/home-service.ts +2 -1
- package/templates/branded-lite/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +48 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-order/index.ts +24 -3
- package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +24 -3
- package/templates/branded-lite/tier5-src/himi-store-saved/index.ts +8 -3
- package/templates/branded-lite/tier5-src/himi-store-shop/index.ts +10 -0
- package/templates/branded-lite/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/community-club/config.ts +1 -8
- package/templates/community-club/dev/index.ts +3 -117
- package/templates/community-club/himalaya.content.json +0 -3
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/community-club/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/community-club/tier5-src/_shared/home-service.ts +2 -1
- package/templates/community-club/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/community-club/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/community-club-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/events-meetups/config.ts +1 -8
- package/templates/events-meetups/dev/index.ts +3 -117
- package/templates/events-meetups/himalaya.content.json +0 -3
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/events-meetups/tier5-src/_shared/home-service.ts +2 -1
- package/templates/events-meetups/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/events-meetups/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/events-meetups-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/gym-fitness/config.ts +1 -1
- package/templates/gym-fitness/dev/index.ts +46 -18
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/gym-fitness/tier5-src/_shared/himi-store-collection.ts +1 -1
- package/templates/gym-fitness/tier5-src/_shared/home-service.ts +2 -1
- package/templates/gym-fitness/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/gym-fitness/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +48 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/gym-fitness/tier5-src/himi-branded-lite-order/index.ts +24 -3
- package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +24 -3
- package/templates/gym-fitness/tier5-src/himi-store-saved/index.ts +8 -3
- package/templates/gym-fitness/tier5-src/himi-store-shop/index.ts +10 -0
- package/templates/gym-fitness/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/gym-fitness-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/nonprofit-cause/config.ts +1 -8
- package/templates/nonprofit-cause/dev/index.ts +29 -129
- package/templates/nonprofit-cause/himalaya.content.json +0 -3
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/nonprofit-cause/tier5-src/_shared/home-service.ts +2 -1
- package/templates/nonprofit-cause/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/nonprofit-cause/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/nonprofit-cause/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/nonprofit-cause-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/owner-lite/tier5-src/_shared/home-service.ts +2 -1
- package/templates/podcast-creator/config.ts +1 -1
- package/templates/podcast-creator/dev/index.ts +29 -13
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/podcast-creator/tier5-src/_shared/home-service.ts +2 -1
- package/templates/podcast-creator/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/podcast-creator/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/podcast-creator/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/podcast-creator-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/portfolio-creative/config.ts +1 -1
- package/templates/portfolio-creative/dev/index.ts +20 -6
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/portfolio-creative/tier5-src/_shared/himi-store-collection.ts +1 -1
- package/templates/portfolio-creative/tier5-src/_shared/home-service.ts +2 -1
- package/templates/portfolio-creative/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/portfolio-creative/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +48 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-order/index.ts +24 -3
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +24 -3
- package/templates/portfolio-creative/tier5-src/himi-store-saved/index.ts +8 -3
- package/templates/portfolio-creative/tier5-src/himi-store-shop/index.ts +10 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/portfolio-creative-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/restaurant/config.ts +1 -1
- package/templates/restaurant/dev/index.ts +3 -1
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/restaurant/tier5-src/_shared/home-service.ts +2 -1
- package/templates/restaurant/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/restaurant/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/restaurant-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/retail-store/config.ts +1 -1
- package/templates/retail-store/dev/index.ts +20 -6
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/retail-store/tier5-src/_shared/himi-store-collection.ts +1 -1
- package/templates/retail-store/tier5-src/_shared/home-service.ts +2 -1
- package/templates/retail-store/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/retail-store/tier5-src/_shared/iap-worker.ts +42 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +48 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/retail-store/tier5-src/himi-branded-lite-order/index.ts +24 -3
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +24 -3
- package/templates/retail-store/tier5-src/himi-store-saved/index.ts +8 -3
- package/templates/retail-store/tier5-src/himi-store-shop/index.ts +10 -0
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/retail-store-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/yoga-studio/config.ts +1 -1
- package/templates/yoga-studio/dev/index.ts +29 -13
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/yoga-studio/tier5-src/_shared/home-service.ts +2 -1
- package/templates/yoga-studio/tier5-src/_shared/iap-presentation.ts +53 -0
- package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +16 -2
- package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +153 -64
- package/templates/yoga-studio/tier5-src/wix-spaces-plan-detail/index.ts +8 -3
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +1 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +3 -2
- package/templates/yoga-studio-owner/tier5-src/_shared/home-service.ts +2 -1
- package/templates/branded-lite/tier5-src/wix-spaces-create-group/index.ts +0 -29
- package/templates/community-club/tier5-src/wix-spaces-create-group/index.ts +0 -29
- package/templates/events-meetups/tier5-src/wix-spaces-create-group/index.ts +0 -29
- package/templates/nonprofit-cause/tier5-src/wix-spaces-create-group/index.ts +0 -29
|
@@ -1,21 +1,13 @@
|
|
|
1
|
-
// Tier-5 bundle: himi-branded-lite — public pricing plans (memberships).
|
|
2
|
-
//
|
|
3
|
-
// Visitors can browse the site's public pricing plans (design §3.5 `plans`
|
|
4
|
-
// vertical). The public GA route works on the anonymous visitor rung, so the
|
|
5
|
-
// list paints with no login. Purchasing is NATIVE (Phase 2b): "Join" creates the
|
|
6
|
-
// member's plan order via createOnlineOrder, then settles any balance on the shared
|
|
7
|
-
// in-app pay rail (@wix/himalaya/checkout) — wallet where the app has one, in-app Wix
|
|
8
|
-
// cashier otherwise. A FREE / fully-discounted plan activates with no payment step at
|
|
9
|
-
// all. A plan-carried purchasable URL still wins when present, and any failure degrades
|
|
10
|
-
// gracefully to the site-directing message rather than a dead button.
|
|
11
|
-
// Four-state (loading / error / rows / empty) like the sibling branded workers.
|
|
12
1
|
import { defineService } from "../_shared/collection-service.js";
|
|
13
2
|
import { createOnlineOrder, listPublicPlans, type WixPlan } from "@himalaya/wix-pricing-plans";
|
|
14
3
|
import { createRedirectSession } from "@himalaya/wix-redirects";
|
|
15
4
|
import { open as openUrl } from "@himalaya/open-url";
|
|
16
5
|
import { session as wixPlatformSession } from "@himalaya/wix-platform";
|
|
17
6
|
import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
|
|
18
|
-
import { payCashierOrder } from "@himalaya/checkout";
|
|
7
|
+
import { activePlanIds, entitlement, payCashierOrder } from "@himalaya/checkout";
|
|
8
|
+
import { hostSessionFromGlobal, iapPriceFields, type IapCatalogItem } from "@himalaya/iap";
|
|
9
|
+
import { createIapCommerce, pricingPlanOrders } from "@himalaya/iap-checkout";
|
|
10
|
+
import { iapPriceCopy, iapPurchaseCopy, resetUnhydratedKeysOnOlderRuntime } from "../_shared/iap-worker.js";
|
|
19
11
|
import { formatCurrency } from "../_shared/engine-intl.js";
|
|
20
12
|
|
|
21
13
|
/** Wix Pricing Plans appDefId — the vertical that owns a plan order, so the `appId` its
|
|
@@ -57,6 +49,11 @@ interface PlanRow {
|
|
|
57
49
|
hasBadge: boolean;
|
|
58
50
|
/** Purchasable URL when the plan data carries one; "" otherwise. */
|
|
59
51
|
joinUrl: string;
|
|
52
|
+
joined: boolean;
|
|
53
|
+
appleSupported: boolean;
|
|
54
|
+
joinLabel: string;
|
|
55
|
+
joinDisabled: boolean;
|
|
56
|
+
joinNote: string;
|
|
60
57
|
}
|
|
61
58
|
|
|
62
59
|
interface State {
|
|
@@ -130,7 +127,7 @@ function planRow(plan: WixPlan): PlanRow {
|
|
|
130
127
|
const trialDays = plan.pricing?.freeTrialDays ?? 0;
|
|
131
128
|
const trialBadge = trialDays > 0 ? copyTemplate("plans.trialBadge", "{days}-day free trial", { days: trialDays }) : "";
|
|
132
129
|
return {
|
|
133
|
-
id: plan.id ||
|
|
130
|
+
id: plan.id || "",
|
|
134
131
|
name,
|
|
135
132
|
description: (plan.description ?? "").trim(),
|
|
136
133
|
trialBadge,
|
|
@@ -145,6 +142,8 @@ function planRow(plan: WixPlan): PlanRow {
|
|
|
145
142
|
noBadge: !badge,
|
|
146
143
|
hasBadge: !!badge,
|
|
147
144
|
joinUrl: joinUrl(plan),
|
|
145
|
+
appleSupported: plan.pricing?.singlePaymentUnlimited === true,
|
|
146
|
+
joined: false, joinLabel: copyParam("plans.joinCta", "Join"), joinDisabled: true, joinNote: "",
|
|
148
147
|
};
|
|
149
148
|
}
|
|
150
149
|
|
|
@@ -170,9 +169,97 @@ function idOf(arg: unknown): string {
|
|
|
170
169
|
return typeof value === "string" ? value : "";
|
|
171
170
|
}
|
|
172
171
|
|
|
172
|
+
const commerce = createIapCommerce({ adapters: [pricingPlanOrders], onChange: () => { void svc.pricingPublish(); } });
|
|
173
|
+
let rows: PlanRow[] = [];
|
|
174
|
+
let items: IapCatalogItem[] = [];
|
|
175
|
+
let message = "";
|
|
176
|
+
let started = false;
|
|
177
|
+
let loading = 0;
|
|
178
|
+
let contentReady = false;
|
|
179
|
+
const joining = new Set<string>();
|
|
180
|
+
const memberSession = hostSessionFromGlobal();
|
|
181
|
+
let regularGeneration = -1;
|
|
182
|
+
let regularAccess = new Set<string>();
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
function pricedState(state: State): State {
|
|
186
|
+
if (!contentReady) return state;
|
|
187
|
+
const priced = rows.map(row => {
|
|
188
|
+
const reference = { kind: "pricingPlan", id: row.id };
|
|
189
|
+
const view = commerce.pricing.view(reference);
|
|
190
|
+
const price = iapPriceFields(view, iapPriceCopy("plans"));
|
|
191
|
+
const purchase = commerce.purchaseFields(reference, iapPurchaseCopy("plans"));
|
|
192
|
+
const apple = purchase.appleRoute;
|
|
193
|
+
const regularReady = regularGeneration === memberSession.current().generation && (!memberSession.identityBound || memberSession.current().kind === "member");
|
|
194
|
+
const joined = apple ? purchase.accessReady : regularReady && regularAccess.has(row.id);
|
|
195
|
+
return { ...row, priceLine: view.route === "disabled" ? row.priceLine : price.priceText,
|
|
196
|
+
periodLine: apple ? price.priceNote : view.route === "regular" || view.route === "disabled" ? row.periodLine : "",
|
|
197
|
+
trialBadge: apple || price.actionDisabled ? "" : row.trialBadge,
|
|
198
|
+
noTrialBadge: apple || price.actionDisabled || row.noTrialBadge,
|
|
199
|
+
joined,
|
|
200
|
+
joinLabel: joined ? copyParam("plans.joinedLabel", "Current plan") : apple ? purchase.buyLabel : row.joinLabel,
|
|
201
|
+
joinDisabled: joined || (apple ? purchase.buyDisabled || !row.appleSupported : price.actionDisabled || !regularReady) || joining.has(row.id),
|
|
202
|
+
joinNote: apple ? row.appleSupported ? purchase.buyNote : iapPriceCopy("plans").purchaseUnavailable : price.actionNote };
|
|
203
|
+
});
|
|
204
|
+
const owned = priced.find(row => row.joined);
|
|
205
|
+
const poll = commerce.pollDirective("himiBrandedPlans.iapPoll");
|
|
206
|
+
return { ...state, ...ready(priced, owned ? copyTemplate("plans.joinedMessage", "You've joined {name}.", { name: owned.name }) : message), ...(poll ? { _poll: poll } : {}) };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function regularJoinMessage(row: PlanRow, reference: { kind: string; id: string }): Promise<string> {
|
|
210
|
+
const generation = memberSession.current().generation;
|
|
211
|
+
if (row.joinUrl) {
|
|
212
|
+
try {
|
|
213
|
+
const result = await openUrl(row.joinUrl, "in_app_browser");
|
|
214
|
+
if (result.opened) { return ""; }
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const created = await createOnlineOrder(row.id);
|
|
220
|
+
const snapshotId = created.purchaseFlowId;
|
|
221
|
+
if (generation !== memberSession.current().generation) return "";
|
|
222
|
+
if (created.order?.status === "ACTIVE") {
|
|
223
|
+
regularAccess.add(row.id);
|
|
224
|
+
return copyTemplate("plans.joinedMessage", "You've joined {name}.", { name: row.name });
|
|
225
|
+
}
|
|
226
|
+
const pay = await payCashierOrder({
|
|
227
|
+
appId: WIX_PRICING_PLANS_APP_ID,
|
|
228
|
+
snapshotId: snapshotId ?? "",
|
|
229
|
+
msid: await resolveMsid(),
|
|
230
|
+
mayCharge: () => commerce.pricing.continueCheckoutGuard(reference).allowed,
|
|
231
|
+
cashierUrl: async () => {
|
|
232
|
+
if (!commerce.pricing.continueCheckoutGuard(reference).allowed) return undefined;
|
|
233
|
+
const redirect = await createRedirectSession({
|
|
234
|
+
paidPlansCheckout: { planId: row.id },
|
|
235
|
+
callbacks: { postFlowUrl: "himalaya-himi-branded-lite://screen/himi_plans" },
|
|
236
|
+
});
|
|
237
|
+
return redirect.redirectSession?.fullUrl;
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
if (pay.kind === "paid") {
|
|
241
|
+
const access = await entitlement(row.id);
|
|
242
|
+
if (generation !== memberSession.current().generation) return "";
|
|
243
|
+
if (access.entitled) regularAccess.add(row.id);
|
|
244
|
+
return access.entitled
|
|
245
|
+
? copyTemplate("plans.joinedMessage", "You've joined {name}.", { name: row.name })
|
|
246
|
+
: copyParam("plans.purchaseProcessingText", "Processing your purchase…");
|
|
247
|
+
}
|
|
248
|
+
if (pay.kind === "handoff") { return ""; }
|
|
249
|
+
if (pay.kind === "cancelled") {
|
|
250
|
+
return copyParam("plans.joinCancelledMessage", "Payment cancelled — you haven't joined.");
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
return copyTemplate("plans.joinOnSiteMessage", "Memberships are purchased on the website — visit the site to join {name}.", { name: row.name });
|
|
255
|
+
}
|
|
256
|
+
|
|
173
257
|
const svc = defineService<State, {
|
|
174
|
-
load: (state: State, arg?: unknown) => Promise<State>;
|
|
175
|
-
|
|
258
|
+
load: (state: State, arg?: unknown) => Promise<State | undefined>;
|
|
259
|
+
pricingPublish: (state: State) => State;
|
|
260
|
+
pricingRefresh: (state: State) => Promise<undefined>;
|
|
261
|
+
iapPoll: (state: State) => Promise<undefined>;
|
|
262
|
+
join: (state: State, arg?: unknown) => Promise<State | undefined>;
|
|
176
263
|
}>("himiBrandedPlans", {
|
|
177
264
|
state: {
|
|
178
265
|
status: "loading",
|
|
@@ -187,13 +274,38 @@ const svc = defineService<State, {
|
|
|
187
274
|
noRows: true,
|
|
188
275
|
noEmpty: true,
|
|
189
276
|
},
|
|
277
|
+
notHydrated: ["rows", "actionMessage"],
|
|
190
278
|
actions: {
|
|
279
|
+
pricingPublish: pricedState,
|
|
280
|
+
pricingRefresh: async () => { await commerce.loadPrices(items); return undefined; },
|
|
281
|
+
iapPoll: async () => { await commerce.poll(); void svc.pricingPublish(); return undefined; },
|
|
191
282
|
load: async (state, arg) => {
|
|
192
283
|
stashCopy(arg);
|
|
284
|
+
const seq = ++loading;
|
|
285
|
+
const generation = memberSession.current().generation;
|
|
286
|
+
regularGeneration = -1;
|
|
287
|
+
regularAccess = new Set();
|
|
193
288
|
try {
|
|
194
289
|
const response = await listPublicPlans();
|
|
195
|
-
|
|
290
|
+
if (seq !== loading) return undefined;
|
|
291
|
+
message = "";
|
|
292
|
+
contentReady = true;
|
|
293
|
+
rows = (response.plans ?? []).filter(plan => !plan.archived).map(planRow);
|
|
294
|
+
items = rows.map(row => ({ reference: { kind: "pricingPlan", id: row.id }, commerceDisplayPrice: row.priceLine }));
|
|
295
|
+
void svc.pricingPublish();
|
|
296
|
+
const access = rows.length > 0 && memberSession.current().kind === "member" ? await activePlanIds() : [];
|
|
297
|
+
if (seq !== loading || generation !== memberSession.current().generation) return undefined;
|
|
298
|
+
regularAccess = new Set(access);
|
|
299
|
+
regularGeneration = generation;
|
|
300
|
+
await commerce.loadPrices(items);
|
|
301
|
+
await (started ? commerce.reconcile() : commerce.start());
|
|
302
|
+
if (seq !== loading || generation !== memberSession.current().generation) return undefined;
|
|
303
|
+
started = true;
|
|
304
|
+
void svc.pricingPublish();
|
|
305
|
+
return undefined;
|
|
196
306
|
} catch {
|
|
307
|
+
if (seq !== loading || generation !== memberSession.current().generation) return undefined;
|
|
308
|
+
contentReady = false;
|
|
197
309
|
// Bridge errors (e.g. a 501 from a serve bridge without the route) land
|
|
198
310
|
// here — a graceful error card with retry, never a dead screen.
|
|
199
311
|
return {
|
|
@@ -209,57 +321,26 @@ const svc = defineService<State, {
|
|
|
209
321
|
},
|
|
210
322
|
join: async (state, arg) => {
|
|
211
323
|
const row = state.rows.find((candidate) => candidate.id === idOf(arg));
|
|
212
|
-
if (!row) return
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// fall through to the redirect-session rail below
|
|
222
|
-
}
|
|
324
|
+
if (!row || joining.has(row.id)) return undefined;
|
|
325
|
+
const reference = { kind: "pricingPlan", id: row.id };
|
|
326
|
+
const purchase = commerce.purchaseFields(reference, iapPurchaseCopy("plans"));
|
|
327
|
+
if (purchase.accessReady) return undefined;
|
|
328
|
+
if (purchase.appleRoute) {
|
|
329
|
+
if (!row.appleSupported) return undefined;
|
|
330
|
+
await commerce.buy({ reference });
|
|
331
|
+
void svc.pricingPublish();
|
|
332
|
+
return undefined;
|
|
223
333
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// the case the hosted redirect used to make needlessly heavy.
|
|
334
|
+
if (regularGeneration !== memberSession.current().generation || (memberSession.identityBound && memberSession.current().kind !== "member") || regularAccess.has(row.id) || !commerce.pricing.checkoutGuard(reference).allowed) return undefined;
|
|
335
|
+
joining.add(row.id);
|
|
336
|
+
void svc.pricingPublish();
|
|
228
337
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
const pay = await payCashierOrder({
|
|
236
|
-
appId: WIX_PRICING_PLANS_APP_ID,
|
|
237
|
-
snapshotId,
|
|
238
|
-
msid: await resolveMsid(),
|
|
239
|
-
// Wallet-less apps keep the hosted plans checkout, IN-APP — so a site with no
|
|
240
|
-
// provisioned wallet can still sell memberships (see @wix/himalaya/checkout).
|
|
241
|
-
cashierUrl: async () => {
|
|
242
|
-
const redirect = await createRedirectSession({
|
|
243
|
-
paidPlansCheckout: { planId: row.id },
|
|
244
|
-
callbacks: { postFlowUrl: "himalaya-himi-branded-lite://screen/himi_plans" },
|
|
245
|
-
});
|
|
246
|
-
return redirect.redirectSession?.fullUrl;
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
if (pay.kind === "paid") {
|
|
250
|
-
return { ...state, actionMessage: copyTemplate("plans.joinedMessage", "You've joined {name}.", { name: row.name }) };
|
|
251
|
-
}
|
|
252
|
-
if (pay.kind === "handoff") return { ...state, actionMessage: "" };
|
|
253
|
-
if (pay.kind === "cancelled") {
|
|
254
|
-
return { ...state, actionMessage: copyParam("plans.joinCancelledMessage", "Payment cancelled — you haven't joined.") };
|
|
255
|
-
}
|
|
256
|
-
} catch {
|
|
257
|
-
// Order/pay failure → graceful site-directing fallback below.
|
|
338
|
+
message = await regularJoinMessage(row, reference);
|
|
339
|
+
return undefined;
|
|
340
|
+
} finally {
|
|
341
|
+
joining.delete(row.id);
|
|
342
|
+
void svc.pricingPublish();
|
|
258
343
|
}
|
|
259
|
-
return {
|
|
260
|
-
...state,
|
|
261
|
-
actionMessage: copyTemplate("plans.joinOnSiteMessage", "Memberships are purchased on the website — visit the site to join {name}.", { name: row.name }),
|
|
262
|
-
};
|
|
263
344
|
},
|
|
264
345
|
},
|
|
265
346
|
});
|
|
@@ -270,5 +351,13 @@ const svc = defineService<State, {
|
|
|
270
351
|
// loading skeleton indefinitely on iOS. onAppear still fires afterwards and
|
|
271
352
|
// re-loads with the screen's copy pack; it passes no required params here
|
|
272
353
|
// (`appear(..., undefined, "<prefix>.")`), so a param-less first load is safe.
|
|
354
|
+
resetUnhydratedKeysOnOlderRuntime(svc, { ...svc.getState(), rows: [], actionMessage: "" }, ["rows", "actionMessage"]);
|
|
355
|
+
memberSession.subscribe(() => {
|
|
356
|
+
message = "";
|
|
357
|
+
regularGeneration = -1;
|
|
358
|
+
regularAccess = new Set();
|
|
359
|
+
void svc.pricingPublish();
|
|
360
|
+
void svc.load();
|
|
361
|
+
});
|
|
273
362
|
svc.load();
|
|
274
363
|
export { svc };
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
// Tier-5 bundle: Wix Spaces clone — Pricing plan detail (ON-DEVICE, site-scoped).
|
|
2
2
|
// himalaya.input.id carries the plan id; fetched via getPlan.
|
|
3
|
-
import {
|
|
3
|
+
import { withIapPresentation } from "../_shared/iap-presentation.js";
|
|
4
4
|
import { getPlan, type WixPlan } from "@himalaya/wix-pricing-plans";
|
|
5
5
|
import { presence, presenceAfterError, detailInputId, type PresenceFlags } from "../_shared/detail-presence.js";
|
|
6
6
|
|
|
7
7
|
interface S extends PresenceFlags { status: "loading" | "ready"; name: string; price: string; description: string; perks: string }
|
|
8
8
|
|
|
9
9
|
function priceOf(p: WixPlan): string {
|
|
10
|
-
const m = p.pricing?.price as unknown as { formattedAmount?: string; amount?: string; currency?: string } | undefined;
|
|
10
|
+
const m = p.pricing?.price as unknown as { formattedAmount?: string; amount?: string; value?: string; currency?: string } | undefined;
|
|
11
11
|
if (!m) return p.pricing?.freeTrialDays ? "Free trial" : "";
|
|
12
|
-
return m.formattedAmount || [m.amount, m.currency].filter(Boolean).join(" ");
|
|
12
|
+
return m.formattedAmount || [m.amount ?? m.value, m.currency].filter(Boolean).join(" ");
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
const defineService = withIapPresentation<S>({
|
|
16
|
+
prefix: "plans", transientKeys: ["price"], contentActions: ["load"],
|
|
17
|
+
items: state => detailInputId() ? [{ reference: { kind: "pricingPlan", id: detailInputId() }, commerceDisplayPrice: state.price }] : [],
|
|
18
|
+
present: (state, price) => ({ ...state, price: price(detailInputId()) }),
|
|
19
|
+
});
|
|
15
20
|
const svc = defineService<S, { load: (s: S) => Promise<S> }>("spacesPlanDetail", {
|
|
16
21
|
state: { status: "loading", name: "", price: "", description: "", perks: "", ...presence("loading") },
|
|
17
22
|
actions: {
|
|
@@ -87,7 +87,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
|
|
|
87
87
|
himiBrandedOrders: { rows: 'rows', title: 'title', subtitle: 'subtitle', view: 'list', backendQuery: true,
|
|
88
88
|
searchPlaceholder: 'Search by order number', countNoun: ['order', 'orders'], filterValues: ['Not fulfilled', 'Partially fulfilled', 'Fulfilled'],
|
|
89
89
|
sortLabels: { default: 'Newest', az: 'Oldest', za: 'Order # ↓' } },
|
|
90
|
-
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
90
|
+
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3', 'joinNote'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
91
91
|
himiBrandedPrograms: { rows: 'rows', title: 'name', subtitle: 'description', image: 'image', view: 'grid' },
|
|
92
92
|
himiBrandedCoupons: { rows: 'coupons', title: 'name', subtitle: 'subtitle', view: 'list', primaryVerb: { label: 'Get code' } },
|
|
93
93
|
himiBrandedNotifications: { rows: 'items', title: 'name', subtitle: 'subtitle', image: 'photo', metadata: ['unreadDot'], view: 'list' },
|
|
@@ -323,6 +323,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
|
|
|
323
323
|
/** Domain-owned page source with shared query controls. Publishing uses a normal
|
|
324
324
|
* reducer and reads the private controller snapshot, never an SDUI payload. */
|
|
325
325
|
export function defineBackendCollection<S extends object, Row extends object>(name: string, options: {
|
|
326
|
+
register?: typeof register;
|
|
326
327
|
/** Revalidate already opened pages on navigation return; explicit refresh resets. */
|
|
327
328
|
restorePagesOnLoad?: boolean;
|
|
328
329
|
/** The load action's argument (onAppear params beyond `copy`), before the query runs — for a
|
|
@@ -342,7 +343,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
342
343
|
controller: controller as unknown as BackendCollection['controller'],
|
|
343
344
|
apply: (state, page) => options.apply(state as S, page as unknown as CollectionQueryState<Row>) as State,
|
|
344
345
|
});
|
|
345
|
-
const handle = register(name, definition);
|
|
346
|
+
const handle = (options.register ?? register)(name, definition);
|
|
346
347
|
publish = () => handle.collectionDataChanged();
|
|
347
348
|
return handle;
|
|
348
349
|
}
|
|
@@ -350,7 +351,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
350
351
|
/** Keep the domain service's existing TypeScript API. Extra collection verbs are
|
|
351
352
|
* dispatched through SDUI and do not widen the native capability surface. */
|
|
352
353
|
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
353
|
-
register(name, decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }))) as typeof register;
|
|
354
|
+
register(name, { ...def, ...decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }) } as ServiceDefinition<State>)) as typeof register;
|
|
354
355
|
|
|
355
356
|
/** Domains can supply their existing saved-items store without putting domain
|
|
356
357
|
* data or mutations in the shared collection layer. */
|
|
@@ -87,4 +87,5 @@ export function decorateHome(def: { state: State; actions?: Record<string, Actio
|
|
|
87
87
|
actions.homeMoveDown = change(id => { const index = prefs.order.indexOf(id); if (index >= 0 && index < prefs.order.length - 1) [prefs.order[index], prefs.order[index + 1]] = [prefs.order[index + 1], prefs.order[index]]; });
|
|
88
88
|
return { state: derive(def.state), actions };
|
|
89
89
|
}
|
|
90
|
-
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
90
|
+
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
91
|
+
register(name, { ...def, ...decorateHome(def as unknown as { state: State; actions?: Record<string, Action> }) })) as typeof register;
|
|
@@ -87,7 +87,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
|
|
|
87
87
|
himiBrandedOrders: { rows: 'rows', title: 'title', subtitle: 'subtitle', view: 'list', backendQuery: true,
|
|
88
88
|
searchPlaceholder: 'Search by order number', countNoun: ['order', 'orders'], filterValues: ['Not fulfilled', 'Partially fulfilled', 'Fulfilled'],
|
|
89
89
|
sortLabels: { default: 'Newest', az: 'Oldest', za: 'Order # ↓' } },
|
|
90
|
-
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
90
|
+
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3', 'joinNote'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
91
91
|
himiBrandedPrograms: { rows: 'rows', title: 'name', subtitle: 'description', image: 'image', view: 'grid' },
|
|
92
92
|
himiBrandedCoupons: { rows: 'coupons', title: 'name', subtitle: 'subtitle', view: 'list', primaryVerb: { label: 'Get code' } },
|
|
93
93
|
himiBrandedNotifications: { rows: 'items', title: 'name', subtitle: 'subtitle', image: 'photo', metadata: ['unreadDot'], view: 'list' },
|
|
@@ -323,6 +323,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
|
|
|
323
323
|
/** Domain-owned page source with shared query controls. Publishing uses a normal
|
|
324
324
|
* reducer and reads the private controller snapshot, never an SDUI payload. */
|
|
325
325
|
export function defineBackendCollection<S extends object, Row extends object>(name: string, options: {
|
|
326
|
+
register?: typeof register;
|
|
326
327
|
/** Revalidate already opened pages on navigation return; explicit refresh resets. */
|
|
327
328
|
restorePagesOnLoad?: boolean;
|
|
328
329
|
/** The load action's argument (onAppear params beyond `copy`), before the query runs — for a
|
|
@@ -342,7 +343,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
342
343
|
controller: controller as unknown as BackendCollection['controller'],
|
|
343
344
|
apply: (state, page) => options.apply(state as S, page as unknown as CollectionQueryState<Row>) as State,
|
|
344
345
|
});
|
|
345
|
-
const handle = register(name, definition);
|
|
346
|
+
const handle = (options.register ?? register)(name, definition);
|
|
346
347
|
publish = () => handle.collectionDataChanged();
|
|
347
348
|
return handle;
|
|
348
349
|
}
|
|
@@ -350,7 +351,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
350
351
|
/** Keep the domain service's existing TypeScript API. Extra collection verbs are
|
|
351
352
|
* dispatched through SDUI and do not widen the native capability surface. */
|
|
352
353
|
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
353
|
-
register(name, decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }))) as typeof register;
|
|
354
|
+
register(name, { ...def, ...decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }) } as ServiceDefinition<State>)) as typeof register;
|
|
354
355
|
|
|
355
356
|
/** Domains can supply their existing saved-items store without putting domain
|
|
356
357
|
* data or mutations in the shared collection layer. */
|
|
@@ -87,4 +87,5 @@ export function decorateHome(def: { state: State; actions?: Record<string, Actio
|
|
|
87
87
|
actions.homeMoveDown = change(id => { const index = prefs.order.indexOf(id); if (index >= 0 && index < prefs.order.length - 1) [prefs.order[index], prefs.order[index + 1]] = [prefs.order[index + 1], prefs.order[index]]; });
|
|
88
88
|
return { state: derive(def.state), actions };
|
|
89
89
|
}
|
|
90
|
-
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
90
|
+
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
91
|
+
register(name, { ...def, ...decorateHome(def as unknown as { state: State; actions?: Record<string, Action> }) })) as typeof register;
|
|
@@ -37,7 +37,7 @@ export default defineApp({
|
|
|
37
37
|
actions: "http://localhost:8190/v1/actions",
|
|
38
38
|
sync: "http://localhost:8190/v1/sync",
|
|
39
39
|
},
|
|
40
|
-
capabilities: ["live_activity","push","share","secure_storage","open_url","calendar","local_database","media_playback","wix_api","wix_platform","app_info","release_control","clipboard"],
|
|
40
|
+
capabilities: ["live_activity","push","share","secure_storage","open_url","calendar","local_database","media_playback","wix_api","wix_platform","app_info","iap","release_control","clipboard"],
|
|
41
41
|
designTokensPath: "./tokens.json",
|
|
42
42
|
navigation: {
|
|
43
43
|
"navKind": "responsive",
|
|
@@ -2063,7 +2063,9 @@ const SCREENS = runtimeSetting({
|
|
|
2063
2063
|
"integrity": "",
|
|
2064
2064
|
"contentType": "application/javascript+ts-bundle",
|
|
2065
2065
|
"declaredCapabilities": [
|
|
2066
|
-
"wix_api"
|
|
2066
|
+
"wix_api",
|
|
2067
|
+
"iap",
|
|
2068
|
+
"app_info"
|
|
2067
2069
|
],
|
|
2068
2070
|
"minBinaryVersion": "0.2.0",
|
|
2069
2071
|
"bundleVersion": "0.0.1"
|
|
@@ -5554,7 +5556,8 @@ const SCREENS = runtimeSetting({
|
|
|
5554
5556
|
"package": "himalaya",
|
|
5555
5557
|
"type": "Button",
|
|
5556
5558
|
"props": {
|
|
5557
|
-
"title": "
|
|
5559
|
+
"title": "$item.joinLabel",
|
|
5560
|
+
"disabledPath": "$item.joinDisabled",
|
|
5558
5561
|
"style": "primary",
|
|
5559
5562
|
"fullWidth": true,
|
|
5560
5563
|
"action": {
|
|
@@ -5575,7 +5578,8 @@ const SCREENS = runtimeSetting({
|
|
|
5575
5578
|
"package": "himalaya",
|
|
5576
5579
|
"type": "Button",
|
|
5577
5580
|
"props": {
|
|
5578
|
-
"title": "
|
|
5581
|
+
"title": "$item.joinLabel",
|
|
5582
|
+
"disabledPath": "$item.joinDisabled",
|
|
5579
5583
|
"style": "secondary",
|
|
5580
5584
|
"fullWidth": true,
|
|
5581
5585
|
"action": {
|
|
@@ -5756,7 +5760,8 @@ const SCREENS = runtimeSetting({
|
|
|
5756
5760
|
"package": "himalaya",
|
|
5757
5761
|
"type": "Button",
|
|
5758
5762
|
"props": {
|
|
5759
|
-
"title": "
|
|
5763
|
+
"title": "$item.joinLabel",
|
|
5764
|
+
"disabledPath": "$item.joinDisabled",
|
|
5760
5765
|
"style": "primary",
|
|
5761
5766
|
"fullWidth": true,
|
|
5762
5767
|
"action": {
|
|
@@ -5777,7 +5782,8 @@ const SCREENS = runtimeSetting({
|
|
|
5777
5782
|
"package": "himalaya",
|
|
5778
5783
|
"type": "Button",
|
|
5779
5784
|
"props": {
|
|
5780
|
-
"title": "
|
|
5785
|
+
"title": "$item.joinLabel",
|
|
5786
|
+
"disabledPath": "$item.joinDisabled",
|
|
5781
5787
|
"style": "secondary",
|
|
5782
5788
|
"fullWidth": true,
|
|
5783
5789
|
"action": {
|
|
@@ -6182,7 +6188,8 @@ const SCREENS = runtimeSetting({
|
|
|
6182
6188
|
"package": "himalaya",
|
|
6183
6189
|
"type": "Button",
|
|
6184
6190
|
"props": {
|
|
6185
|
-
"title": "
|
|
6191
|
+
"title": "$item.joinLabel",
|
|
6192
|
+
"disabledPath": "$item.joinDisabled",
|
|
6186
6193
|
"style": "primary",
|
|
6187
6194
|
"fullWidth": true,
|
|
6188
6195
|
"action": {
|
|
@@ -6203,7 +6210,8 @@ const SCREENS = runtimeSetting({
|
|
|
6203
6210
|
"package": "himalaya",
|
|
6204
6211
|
"type": "Button",
|
|
6205
6212
|
"props": {
|
|
6206
|
-
"title": "
|
|
6213
|
+
"title": "$item.joinLabel",
|
|
6214
|
+
"disabledPath": "$item.joinDisabled",
|
|
6207
6215
|
"style": "secondary",
|
|
6208
6216
|
"fullWidth": true,
|
|
6209
6217
|
"action": {
|
|
@@ -6384,7 +6392,8 @@ const SCREENS = runtimeSetting({
|
|
|
6384
6392
|
"package": "himalaya",
|
|
6385
6393
|
"type": "Button",
|
|
6386
6394
|
"props": {
|
|
6387
|
-
"title": "
|
|
6395
|
+
"title": "$item.joinLabel",
|
|
6396
|
+
"disabledPath": "$item.joinDisabled",
|
|
6388
6397
|
"style": "primary",
|
|
6389
6398
|
"fullWidth": true,
|
|
6390
6399
|
"action": {
|
|
@@ -6405,7 +6414,8 @@ const SCREENS = runtimeSetting({
|
|
|
6405
6414
|
"package": "himalaya",
|
|
6406
6415
|
"type": "Button",
|
|
6407
6416
|
"props": {
|
|
6408
|
-
"title": "
|
|
6417
|
+
"title": "$item.joinLabel",
|
|
6418
|
+
"disabledPath": "$item.joinDisabled",
|
|
6409
6419
|
"style": "secondary",
|
|
6410
6420
|
"fullWidth": true,
|
|
6411
6421
|
"action": {
|
|
@@ -6983,7 +6993,8 @@ const SCREENS = runtimeSetting({
|
|
|
6983
6993
|
"package": "himalaya",
|
|
6984
6994
|
"type": "Button",
|
|
6985
6995
|
"props": {
|
|
6986
|
-
"title": "
|
|
6996
|
+
"title": "$item.joinLabel",
|
|
6997
|
+
"disabledPath": "$item.joinDisabled",
|
|
6987
6998
|
"style": "primary",
|
|
6988
6999
|
"fullWidth": true,
|
|
6989
7000
|
"action": {
|
|
@@ -7004,7 +7015,8 @@ const SCREENS = runtimeSetting({
|
|
|
7004
7015
|
"package": "himalaya",
|
|
7005
7016
|
"type": "Button",
|
|
7006
7017
|
"props": {
|
|
7007
|
-
"title": "
|
|
7018
|
+
"title": "$item.joinLabel",
|
|
7019
|
+
"disabledPath": "$item.joinDisabled",
|
|
7008
7020
|
"style": "secondary",
|
|
7009
7021
|
"fullWidth": true,
|
|
7010
7022
|
"action": {
|
|
@@ -7282,7 +7294,9 @@ const SCREENS = runtimeSetting({
|
|
|
7282
7294
|
"wix_api",
|
|
7283
7295
|
"wix_cashier",
|
|
7284
7296
|
"open_url",
|
|
7285
|
-
"wix_platform"
|
|
7297
|
+
"wix_platform",
|
|
7298
|
+
"iap",
|
|
7299
|
+
"app_info"
|
|
7286
7300
|
],
|
|
7287
7301
|
"minBinaryVersion": "0.1.0",
|
|
7288
7302
|
"bundleVersion": "0.0.1"
|
|
@@ -7538,7 +7552,9 @@ const SCREENS = runtimeSetting({
|
|
|
7538
7552
|
"integrity": "",
|
|
7539
7553
|
"contentType": "application/javascript+ts-bundle",
|
|
7540
7554
|
"declaredCapabilities": [
|
|
7541
|
-
"wix_api"
|
|
7555
|
+
"wix_api",
|
|
7556
|
+
"iap",
|
|
7557
|
+
"app_info"
|
|
7542
7558
|
],
|
|
7543
7559
|
"minBinaryVersion": "0.1.0",
|
|
7544
7560
|
"bundleVersion": "0.0.1"
|
|
@@ -87,7 +87,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
|
|
|
87
87
|
himiBrandedOrders: { rows: 'rows', title: 'title', subtitle: 'subtitle', view: 'list', backendQuery: true,
|
|
88
88
|
searchPlaceholder: 'Search by order number', countNoun: ['order', 'orders'], filterValues: ['Not fulfilled', 'Partially fulfilled', 'Fulfilled'],
|
|
89
89
|
sortLabels: { default: 'Newest', az: 'Oldest', za: 'Order # ↓' } },
|
|
90
|
-
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
90
|
+
himiBrandedPlans: { rows: 'rows', title: 'name', subtitle: 'description', metadata: ['badge', 'priceLine', 'periodLine', 'trialBadge', 'perk1', 'perk2', 'perk3', 'joinNote'], view: 'grid', gridColumns: 1, metaMaxLines: 8, countNoun: ['plan', 'plans'] },
|
|
91
91
|
himiBrandedPrograms: { rows: 'rows', title: 'name', subtitle: 'description', image: 'image', view: 'grid' },
|
|
92
92
|
himiBrandedCoupons: { rows: 'coupons', title: 'name', subtitle: 'subtitle', view: 'list', primaryVerb: { label: 'Get code' } },
|
|
93
93
|
himiBrandedNotifications: { rows: 'items', title: 'name', subtitle: 'subtitle', image: 'photo', metadata: ['unreadDot'], view: 'list' },
|
|
@@ -323,6 +323,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
|
|
|
323
323
|
/** Domain-owned page source with shared query controls. Publishing uses a normal
|
|
324
324
|
* reducer and reads the private controller snapshot, never an SDUI payload. */
|
|
325
325
|
export function defineBackendCollection<S extends object, Row extends object>(name: string, options: {
|
|
326
|
+
register?: typeof register;
|
|
326
327
|
/** Revalidate already opened pages on navigation return; explicit refresh resets. */
|
|
327
328
|
restorePagesOnLoad?: boolean;
|
|
328
329
|
/** The load action's argument (onAppear params beyond `copy`), before the query runs — for a
|
|
@@ -342,7 +343,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
342
343
|
controller: controller as unknown as BackendCollection['controller'],
|
|
343
344
|
apply: (state, page) => options.apply(state as S, page as unknown as CollectionQueryState<Row>) as State,
|
|
344
345
|
});
|
|
345
|
-
const handle = register(name, definition);
|
|
346
|
+
const handle = (options.register ?? register)(name, definition);
|
|
346
347
|
publish = () => handle.collectionDataChanged();
|
|
347
348
|
return handle;
|
|
348
349
|
}
|
|
@@ -350,7 +351,7 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
350
351
|
/** Keep the domain service's existing TypeScript API. Extra collection verbs are
|
|
351
352
|
* dispatched through SDUI and do not widen the native capability surface. */
|
|
352
353
|
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
353
|
-
register(name, decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }))) as typeof register;
|
|
354
|
+
register(name, { ...def, ...decorateCollection(name, def as unknown as { state: State; actions?: Record<string, Reducer> }) } as ServiceDefinition<State>)) as typeof register;
|
|
354
355
|
|
|
355
356
|
/** Domains can supply their existing saved-items store without putting domain
|
|
356
357
|
* data or mutations in the shared collection layer. */
|
|
@@ -87,4 +87,5 @@ export function decorateHome(def: { state: State; actions?: Record<string, Actio
|
|
|
87
87
|
actions.homeMoveDown = change(id => { const index = prefs.order.indexOf(id); if (index >= 0 && index < prefs.order.length - 1) [prefs.order[index], prefs.order[index + 1]] = [prefs.order[index + 1], prefs.order[index]]; });
|
|
88
88
|
return { state: derive(def.state), actions };
|
|
89
89
|
}
|
|
90
|
-
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
90
|
+
export const defineService: typeof register = ((name: string, def: ServiceDefinition<unknown>) =>
|
|
91
|
+
register(name, { ...def, ...decorateHome(def as unknown as { state: State; actions?: Record<string, Action> }) })) as typeof register;
|