@wix/himalaya-cli 0.1631.0 → 0.1633.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/iap/src/wix-payments-contract.d.ts +4 -14
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-wire.d.ts +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments.d.ts +1 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +26 -13
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-core.d.ts +0 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/checkout-source.d.ts +3 -10
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-core.d.ts +0 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-order-backend.d.ts +0 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-verticals/stores.d.ts +2 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +2 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +64 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-v1/src/index.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +13 -45
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +2 -4
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +7 -11
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +39 -0
- package/dist/cli.mjs +258 -150
- package/dist/preview-assets.generated.bin +0 -0
- package/fixtures/wix-canned.json +3 -0
- package/guides/getting-started.md +2 -1
- package/guides/himi-json-output.md +6 -0
- package/guides/himi-skill.md +2 -1
- package/guides/iap-screen-adoption.md +4 -4
- package/guides/importable-sdks.md +1 -1
- package/guides/one-app-section-mappings.md +3 -3
- package/guides/sdk-reference.json +8829 -4386
- package/guides/skill.md +11 -1
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/branded-lite/dev/index.ts +2924 -2110
- package/templates/branded-lite/l10n/en.json +5 -3
- package/templates/branded-lite/tier5-src/_shared/loyalty-offerings.ts +73 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/earning.ts +148 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +57 -31
- package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty-rewards/index.ts +208 -0
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +1 -1
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +1 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// Member rewards use their own service, so a public offering can never hydrate a
|
|
2
|
+
// balance or coupon. All private state is online-only, and every completion checks
|
|
3
|
+
// the principal and business. Navigation parameters provide an ID, never a price.
|
|
4
|
+
import { defineService, navigate } from "@himalaya/state";
|
|
5
|
+
import { getLoyaltyProgram, listLoyaltyRewards, getCurrentMemberLoyaltyAccount, listMyLoyaltyCoupons, listMyReferralRewards, redeemMyLoyaltyReward,
|
|
6
|
+
type WixLoyaltyReward, type WixLoyaltyAccount, type WixLoyaltyCoupon, type WixLoyaltyProgram, type WixReferralReward } from "@himalaya/wix-loyalty";
|
|
7
|
+
import { memberAccess, assertMemberAccess, type MemberAccess } from "../_shared/member-access.js";
|
|
8
|
+
import { withOnlineWrites } from "../_shared/online-actions.js";
|
|
9
|
+
import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
|
|
10
|
+
import { offeringRewardLabel, memberRewardCost, pointLabel } from "../_shared/loyalty-offerings.js";
|
|
11
|
+
|
|
12
|
+
interface MemberRow { id: string; name: string; subtitle: string; eligibility: string; code: string; isCoupon: boolean; notCoupon: boolean; section: string }
|
|
13
|
+
interface S {
|
|
14
|
+
hideLoading: boolean; hideContent: boolean; hideSignIn: boolean; hideError: boolean; error: string;
|
|
15
|
+
points: string; items: MemberRow[]; emptyText: string;
|
|
16
|
+
confirming: boolean; confirmation: string; selectedId: string; writeBusy: boolean; message: string;
|
|
17
|
+
referralError: string; resultCode: string; resultName: string;
|
|
18
|
+
}
|
|
19
|
+
const INITIAL: S = { hideLoading: false, hideContent: true, hideSignIn: true, hideError: true, error: "", points: "", items: [], emptyText: "",
|
|
20
|
+
referralError: "", confirming: false, confirmation: "", selectedId: "", writeBusy: false, message: "", resultCode: "", resultName: "" };
|
|
21
|
+
const PRIVATE_KEYS = Object.keys(INITIAL) as (keyof S)[];
|
|
22
|
+
const input = () => (globalThis as { himalaya?: { input?: Record<string, unknown>; readLifecycleVersion?: number } }).himalaya;
|
|
23
|
+
const business = () => input()?.input?.__himiPreferenceBusiness;
|
|
24
|
+
const object = (arg: unknown): Record<string, unknown> => arg && typeof arg === "object" ? arg as Record<string, unknown> : {};
|
|
25
|
+
let generation = 0, writing = false, reviewing = false;
|
|
26
|
+
let currency = "", restaurantScreen = "";
|
|
27
|
+
let context: { member: MemberAccess; business: unknown; program: WixLoyaltyProgram; account: WixLoyaltyAccount; rewards: WixLoyaltyReward[]; coupons: WixLoyaltyCoupon[]; referrals: WixReferralReward[]; referralKnown: boolean } | undefined;
|
|
28
|
+
let confirmation: { id: string; member: MemberAccess; business: unknown; cost: number } | undefined;
|
|
29
|
+
let result: { generation: number; message: string; coupon?: WixLoyaltyCoupon } | undefined;
|
|
30
|
+
// One confirmed write may await two independently replicated reads. Keep its
|
|
31
|
+
// coupon and stop further spending until both reads reflect the transaction.
|
|
32
|
+
let confirmed: { coupon: WixLoyaltyCoupon; balanceAfter?: number; redeemedAfter?: number } | undefined;
|
|
33
|
+
const pointAmount = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
34
|
+
// An ambiguous write cannot be retried by another tap or refresh in this session.
|
|
35
|
+
const uncertain = new Set<string>();
|
|
36
|
+
const MAX_UNCERTAIN_REWARDS = 64;
|
|
37
|
+
let uncertaintyOverflow = false;
|
|
38
|
+
const blocked = (id: string) => !!confirmed || uncertaintyOverflow || uncertain.has(id);
|
|
39
|
+
let uncertainPrincipal = "";
|
|
40
|
+
const stamp = (member: MemberAccess) => JSON.stringify([member.email, member.scope, business()]);
|
|
41
|
+
const couponReward = (reward: WixLoyaltyReward) => reward.type === "COUPON_REWARD" || reward.type === "COUPON";
|
|
42
|
+
// These responses confirm the write was rejected. Timeouts (including HTTP 408),
|
|
43
|
+
// 5xx and unclassified errors leave its outcome uncertain and must stay blocked.
|
|
44
|
+
function definitiveRejection(error: unknown): boolean {
|
|
45
|
+
const status = /\bHTTP\s+(\d{3})\b/.exec(String(error))?.[1];
|
|
46
|
+
return !!status && ["400", "401", "403", "404", "409", "412", "422", "428", "429"].includes(status);
|
|
47
|
+
}
|
|
48
|
+
const guard = async (c: NonNullable<typeof context>) => {
|
|
49
|
+
await assertMemberAccess(c.member);
|
|
50
|
+
if (context !== c || business() !== c.business) throw new Error("Member access changed");
|
|
51
|
+
};
|
|
52
|
+
const signInState = (): S => ({ ...INITIAL, hideLoading: true, hideSignIn: false });
|
|
53
|
+
function reconcile(c: NonNullable<typeof context>) {
|
|
54
|
+
if (!confirmed) return;
|
|
55
|
+
const points = c.account.points;
|
|
56
|
+
const debited = (confirmed.balanceAfter !== undefined && pointAmount(points?.balance) && points.balance <= confirmed.balanceAfter)
|
|
57
|
+
|| (confirmed.redeemedAfter !== undefined && pointAmount(points?.redeemed) && points.redeemed >= confirmed.redeemedAfter);
|
|
58
|
+
if (debited && c.coupons.some(coupon => coupon.id === confirmed!.coupon.id)) confirmed = undefined;
|
|
59
|
+
}
|
|
60
|
+
function rows(c: NonNullable<typeof context>): Pick<S, "items" | "points" | "emptyText" | "referralError"> {
|
|
61
|
+
const unit = c.program.pointDefinition?.customName ?? "";
|
|
62
|
+
const balance = c.account.points?.balance;
|
|
63
|
+
const ordered = c.rewards.filter(r => r.active === true && !!r.id).map((reward, index) => {
|
|
64
|
+
const cost = memberRewardCost(reward, c.account.tier?.id);
|
|
65
|
+
return { reward, index, available: couponReward(reward) && !blocked(reward.id) && cost !== undefined && typeof balance === "number" && Number.isFinite(balance) && balance >= cost ? 1 : 0 };
|
|
66
|
+
}).sort((a, b) => b.available - a.available || a.index - b.index);
|
|
67
|
+
const rewards = ordered.map(({ reward }, index) => {
|
|
68
|
+
const cost = memberRewardCost(reward, c.account.tier?.id);
|
|
69
|
+
const eligibility = confirmed ? copyParam("loyalty.redeemedRefreshFailed", "Reward redeemed. Your balance couldn't be refreshed; refresh before redeeming again.")
|
|
70
|
+
: blocked(reward.id) ? copyParam("loyalty.redemptionUncertain", "Check your coupons: this redemption could not be confirmed.")
|
|
71
|
+
: reward.type === "DISCOUNT_AMOUNT" ? copyParam("loyalty.orderToRedeem", "Use this reward when placing an order.")
|
|
72
|
+
: !couponReward(reward) ? copyParam("loyalty.checkoutReward", "Use this reward at checkout.")
|
|
73
|
+
: cost === undefined ? copyParam("loyalty.notOnTier", "This reward is not available on your tier.")
|
|
74
|
+
: typeof balance !== "number" || !Number.isFinite(balance) ? copyParam("loyalty.pointsUnavailable", "Your points aren't available yet.")
|
|
75
|
+
: balance < cost ? copyTemplate("loyalty.pointsNeeded", "{points} more needed", { points: pointLabel(cost - balance, unit) })
|
|
76
|
+
: copyParam("loyalty.readyToRedeem", "Available to redeem");
|
|
77
|
+
return { id: reward.id, code: "", isCoupon: false, notCoupon: true, section: index === 0 ? copyParam("loyalty.rewardsHeading", "Rewards") : "", name: reward.name || copyParam("loyalty.rewardFallback", "Reward"), subtitle: offeringRewardLabel(reward, c.account.tier?.id, unit, currency), eligibility };
|
|
78
|
+
});
|
|
79
|
+
const knownCoupons = confirmed && !c.coupons.some(coupon => coupon.id === confirmed!.coupon.id) ? [...c.coupons, confirmed.coupon] : c.coupons;
|
|
80
|
+
const coupons = knownCoupons.filter(c => c.status === "ACTIVE" && !c.couponReference?.deleted && !!c.id && !!c.couponReference?.code)
|
|
81
|
+
.map(c => ({ id: c.id!, name: c.rewardName || copyParam("loyalty.rewardFallback", "Reward"), code: c.couponReference!.code! }));
|
|
82
|
+
const referralCoupons = c.referrals.filter(r => r.rewardType === "COUPON" && r.coupon?.status === "ACTIVE" && !!r.id && !!r.coupon.code)
|
|
83
|
+
.map(r => ({ id: `referral:${r.id}`, name: r.coupon!.couponSpecification?.name || copyParam("loyalty.referralReward", "Referral reward"), code: r.coupon!.code! }));
|
|
84
|
+
const allCoupons = [...coupons, ...referralCoupons];
|
|
85
|
+
const items: MemberRow[] = [...allCoupons.map((coupon, index) => ({ ...coupon, id: `coupon:${coupon.id}`, isCoupon: true, notCoupon: false, subtitle: "", eligibility: "", section: index === 0 ? copyParam("loyalty.claimedRewards", "Your coupons") : "" })), ...rewards];
|
|
86
|
+
return { items, referralError: c.referralKnown ? "" : copyParam("loyalty.referralsError", "Referral rewards couldn't be verified. Refresh to try again."), points: !confirmed && typeof balance === "number" && Number.isFinite(balance) ? pointLabel(balance, unit) : "",
|
|
87
|
+
emptyText: rewards.length || allCoupons.length ? "" : copyParam("loyalty.emptyText", "No rewards to redeem yet.") };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function redeem(c: NonNullable<typeof context>, selected: NonNullable<typeof confirmation>, version: number) {
|
|
91
|
+
let coupon: WixLoyaltyCoupon | undefined;
|
|
92
|
+
let message = "";
|
|
93
|
+
try {
|
|
94
|
+
await guard(c);
|
|
95
|
+
const before = c.account.points;
|
|
96
|
+
// The server validates current member, active reward, tier and cost atomically.
|
|
97
|
+
const response = await redeemMyLoyaltyReward(selected.id);
|
|
98
|
+
await guard(c);
|
|
99
|
+
coupon = response.coupon;
|
|
100
|
+
if (!coupon?.id || !coupon.couponReference?.code) throw new Error("Redemption was not confirmed");
|
|
101
|
+
confirmed = { coupon, balanceAfter: pointAmount(before?.balance) ? Math.max(0, before.balance - selected.cost) : undefined,
|
|
102
|
+
redeemedAfter: pointAmount(before?.redeemed) ? before.redeemed + selected.cost : undefined };
|
|
103
|
+
message = copyParam("loyalty.redeemed", "Reward redeemed. Use this coupon at checkout.");
|
|
104
|
+
const [account, coupons] = await Promise.allSettled([getCurrentMemberLoyaltyAccount(), listMyLoyaltyCoupons()]);
|
|
105
|
+
await guard(c);
|
|
106
|
+
// A failed follow-up read cannot erase the successful coupon or retain a stale spendable balance.
|
|
107
|
+
c.account = account.status === "fulfilled" ? account.value.account ?? {} : {};
|
|
108
|
+
c.coupons = coupons.status === "fulfilled" ? coupons.value.loyaltyCoupons ?? [] : [];
|
|
109
|
+
reconcile(c);
|
|
110
|
+
if (confirmed || account.status === "rejected" || coupons.status === "rejected") message = copyParam("loyalty.redeemedRefreshFailed", "Reward redeemed. Your balance couldn't be refreshed; refresh before redeeming again.");
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (definitiveRejection(error)) {
|
|
113
|
+
c.account = {}; // The eligibility snapshot may have changed since confirmation.
|
|
114
|
+
message = copyParam("loyalty.cannotRedeem", "This reward can't be redeemed with your current points and tier.");
|
|
115
|
+
} else {
|
|
116
|
+
if (uncertain.size < MAX_UNCERTAIN_REWARDS) uncertain.add(selected.id);
|
|
117
|
+
else uncertaintyOverflow = true; // Fail closed instead of evicting an ambiguous operation.
|
|
118
|
+
message = copyParam("loyalty.redemptionFailed", "Couldn't confirm redemption. Check your coupons and balance before redeeming again. This action won't be retried automatically.");
|
|
119
|
+
}
|
|
120
|
+
} finally { writing = false; }
|
|
121
|
+
if (version !== generation || context !== c) { await svc.load(); return; }
|
|
122
|
+
try { await guard(c); result = { generation: version, message, coupon }; await svc.finishRedemption(); }
|
|
123
|
+
catch { await svc.load(); }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const register = withOnlineWrites(defineService, ["confirmRedemption"], { messageFields: ["message"] });
|
|
127
|
+
const svc = register<S, {
|
|
128
|
+
prepare: (s: S) => S; load: (s: S, arg?: unknown) => Promise<S | undefined>;
|
|
129
|
+
reviewReward: (s: S, arg?: unknown) => Promise<S>; cancelRedemption: (s: S) => S;
|
|
130
|
+
confirmRedemption: (s: S) => S; finishRedemption: (s: S) => S;
|
|
131
|
+
}>("himiBrandedLoyaltyRewards", {
|
|
132
|
+
state: INITIAL, notHydrated: PRIVATE_KEYS, notPersisted: PRIVATE_KEYS, perVisit: PRIVATE_KEYS,
|
|
133
|
+
actions: {
|
|
134
|
+
prepare: () => { generation++; context = undefined; confirmation = undefined; result = undefined; return { ...INITIAL }; },
|
|
135
|
+
load: async (s, arg) => {
|
|
136
|
+
stashCopy(arg);
|
|
137
|
+
if (writing) return s;
|
|
138
|
+
const version = ++generation; context = undefined; confirmation = undefined; result = undefined;
|
|
139
|
+
const args = object(arg);
|
|
140
|
+
if ("currency" in args) currency = typeof args.currency === "string" && /^[A-Z]{3}$/.test(args.currency) ? args.currency : "";
|
|
141
|
+
if ("restaurantScreen" in args) restaurantScreen = args.restaurantScreen === "himi_menu" ? "himi_menu" : "";
|
|
142
|
+
const site = business(), member = await memberAccess();
|
|
143
|
+
if (!member.email) return signInState();
|
|
144
|
+
if (!member.scope || (input()?.readLifecycleVersion ?? 0) < 1) return { ...INITIAL, hideLoading: true, hideError: false, error: copyParam("loyalty.updateApp", "Update the app to see your points securely.") };
|
|
145
|
+
if (uncertainPrincipal !== stamp(member)) { uncertain.clear(); uncertaintyOverflow = false; confirmed = undefined; uncertainPrincipal = stamp(member); }
|
|
146
|
+
try {
|
|
147
|
+
const [program, rewards, account, coupons, referrals] = await Promise.all([getLoyaltyProgram(), listLoyaltyRewards(), getCurrentMemberLoyaltyAccount(), listMyLoyaltyCoupons(),
|
|
148
|
+
listMyReferralRewards().then(value => ({ value, failed: false }), () => ({ value: undefined, failed: true }))]);
|
|
149
|
+
await assertMemberAccess(member);
|
|
150
|
+
if (business() !== site || version !== generation) return undefined;
|
|
151
|
+
const p = program.loyaltyProgram ?? program.program;
|
|
152
|
+
if (!p || p.status !== "ACTIVE" || p.premiumFeatures?.loyaltyProgram === false) throw new Error("Program unavailable");
|
|
153
|
+
if ((rewards.rewards !== undefined && !Array.isArray(rewards.rewards)) || (coupons.loyaltyCoupons !== undefined && !Array.isArray(coupons.loyaltyCoupons))) throw new Error("Incomplete member rewards response");
|
|
154
|
+
context = { member, business: site, program: p, account: account.account ?? {}, rewards: rewards.rewards ?? [], coupons: coupons.loyaltyCoupons ?? [], referrals: referrals.value?.referralRewards ?? [], referralKnown: !referrals.failed };
|
|
155
|
+
reconcile(context);
|
|
156
|
+
return { ...INITIAL, hideLoading: true, hideContent: false, ...rows(context) };
|
|
157
|
+
} catch {
|
|
158
|
+
if (version !== generation || business() !== site) return undefined;
|
|
159
|
+
const current = await memberAccess();
|
|
160
|
+
if (!current.email || stamp(current) !== stamp(member)) return signInState();
|
|
161
|
+
return { ...INITIAL, hideLoading: true, hideError: false, error: copyParam("loyalty.memberRewardsError", "Your rewards couldn't be loaded. Try again.") };
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
reviewReward: async (s, arg) => {
|
|
165
|
+
const c = context, id = object(arg).id;
|
|
166
|
+
if (!c || typeof id !== "string" || writing || reviewing || blocked(id)) return s;
|
|
167
|
+
const reward = c.rewards.find(r => r.id === id && r.active === true);
|
|
168
|
+
if (!reward) return s;
|
|
169
|
+
reviewing = true;
|
|
170
|
+
try {
|
|
171
|
+
await guard(c);
|
|
172
|
+
if (reward.type === "DISCOUNT_AMOUNT" && restaurantScreen) return navigate(s, { screenId: restaurantScreen });
|
|
173
|
+
if (!couponReward(reward)) return { ...s, message: copyParam("loyalty.checkoutReward", "Use this reward at checkout.") };
|
|
174
|
+
const [freshRewards, freshAccount] = await Promise.all([listLoyaltyRewards(), getCurrentMemberLoyaltyAccount()]);
|
|
175
|
+
await guard(c);
|
|
176
|
+
const fresh = freshRewards.rewards?.find(r => r.id === id && r.active === true);
|
|
177
|
+
if (!fresh || !freshAccount.account) throw new Error("Reward unavailable");
|
|
178
|
+
c.rewards = freshRewards.rewards!; c.account = freshAccount.account;
|
|
179
|
+
const cost = memberRewardCost(fresh, c.account.tier?.id), balance = c.account.points?.balance;
|
|
180
|
+
if (cost === undefined || typeof balance !== "number" || !Number.isFinite(balance) || balance < cost) return { ...s, ...rows(c), message: copyParam("loyalty.cannotRedeem", "This reward can't be redeemed with your current points and tier.") };
|
|
181
|
+
confirmation = { id, member: c.member, business: c.business, cost };
|
|
182
|
+
return { ...s, ...rows(c), selectedId: id, confirming: true, message: "", confirmation: copyTemplate("loyalty.confirmReward", "Redeem {name} for {points}?", { name: fresh.name || copyParam("loyalty.rewardFallback", "Reward"), points: pointLabel(cost, c.program.pointDefinition?.customName ?? "") }) };
|
|
183
|
+
} catch {
|
|
184
|
+
confirmation = undefined;
|
|
185
|
+
const current = await memberAccess();
|
|
186
|
+
if (context !== c || business() !== c.business || stamp(current) !== stamp(c.member)) return signInState();
|
|
187
|
+
return { ...s, confirming: false, message: copyParam("loyalty.cannotRedeem", "This reward can't be redeemed with your current points and tier.") }; }
|
|
188
|
+
finally { reviewing = false; }
|
|
189
|
+
},
|
|
190
|
+
cancelRedemption: s => { if (writing) return s; confirmation = undefined; return { ...s, confirming: false, selectedId: "", confirmation: "" }; },
|
|
191
|
+
confirmRedemption: s => {
|
|
192
|
+
const c = context, selected = confirmation;
|
|
193
|
+
if (!c || !selected || !s.confirming || writing || blocked(selected.id) || selected.business !== business() || selected.member !== c.member) return s;
|
|
194
|
+
writing = true; confirmation = undefined;
|
|
195
|
+
void redeem(c, selected, generation);
|
|
196
|
+
return { ...s, writeBusy: true, message: copyParam("loyalty.redeeming", "Redeeming…") };
|
|
197
|
+
},
|
|
198
|
+
finishRedemption: s => {
|
|
199
|
+
if (!result || result.generation !== generation || !context) return s;
|
|
200
|
+
const done = result; result = undefined;
|
|
201
|
+
return { ...s, hideLoading: true, hideContent: false, hideSignIn: true, hideError: true, ...rows(context), confirming: false, selectedId: "", confirmation: "", writeBusy: false, message: done.message,
|
|
202
|
+
resultCode: done.coupon?.couponReference?.code ?? "", resultName: done.coupon?.rewardName ?? "" };
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
svc.prepare();
|
|
207
|
+
svc.load();
|
|
208
|
+
export { svc };
|
|
@@ -439,7 +439,7 @@ function derive(s: S): S {
|
|
|
439
439
|
let cartBadgeEpoch = 0;
|
|
440
440
|
|
|
441
441
|
// A digital product with no options sells through the App Store once the platform sells Wix Stores
|
|
442
|
-
// items there (`storesAppleSalesEnabled`)
|
|
442
|
+
// items there (`storesAppleSalesEnabled`): wix-iap StartItemPayment places and charges its order.
|
|
443
443
|
// Until then, and for any other product, an App Store route only blocks the regular checkout.
|
|
444
444
|
const SELLS_THROUGH_APPLE = storesAppleSalesEnabled();
|
|
445
445
|
const WIX_STORES_APP = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|
|
@@ -467,7 +467,7 @@ function derive(s: S): S {
|
|
|
467
467
|
let cartBadgeEpoch = 0;
|
|
468
468
|
|
|
469
469
|
// A digital product with no options sells through the App Store once the platform sells Wix Stores
|
|
470
|
-
// items there (`storesAppleSalesEnabled`)
|
|
470
|
+
// items there (`storesAppleSalesEnabled`): wix-iap StartItemPayment places and charges its order.
|
|
471
471
|
// Until then, and for any other product, an App Store route only blocks the regular checkout.
|
|
472
472
|
const SELLS_THROUGH_APPLE = storesAppleSalesEnabled();
|
|
473
473
|
const WIX_STORES_APP = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|
|
@@ -467,7 +467,7 @@ function derive(s: S): S {
|
|
|
467
467
|
let cartBadgeEpoch = 0;
|
|
468
468
|
|
|
469
469
|
// A digital product with no options sells through the App Store once the platform sells Wix Stores
|
|
470
|
-
// items there (`storesAppleSalesEnabled`)
|
|
470
|
+
// items there (`storesAppleSalesEnabled`): wix-iap StartItemPayment places and charges its order.
|
|
471
471
|
// Until then, and for any other product, an App Store route only blocks the regular checkout.
|
|
472
472
|
const SELLS_THROUGH_APPLE = storesAppleSalesEnabled();
|
|
473
473
|
const WIX_STORES_APP = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|
|
@@ -439,7 +439,7 @@ function derive(s: S): S {
|
|
|
439
439
|
let cartBadgeEpoch = 0;
|
|
440
440
|
|
|
441
441
|
// A digital product with no options sells through the App Store once the platform sells Wix Stores
|
|
442
|
-
// items there (`storesAppleSalesEnabled`)
|
|
442
|
+
// items there (`storesAppleSalesEnabled`): wix-iap StartItemPayment places and charges its order.
|
|
443
443
|
// Until then, and for any other product, an App Store route only blocks the regular checkout.
|
|
444
444
|
const SELLS_THROUGH_APPLE = storesAppleSalesEnabled();
|
|
445
445
|
const WIX_STORES_APP = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|