@wix/himalaya-cli 0.1496.0 → 0.1498.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/attendance-classifier.d.ts +37 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/catalog-pricing-contract.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/index.d.ts +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +11 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +27 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-contract.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-verticals/attendance.d.ts +10 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-verticals/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/index.d.ts +33 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +346 -26
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +132 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +366 -48
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +5 -0
- package/dist/cli.mjs +817 -666
- package/guides/iap-products.md +7 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +394 -0
- package/templates/beauty-salon/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/beauty-salon/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/beauty-salon/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +52 -7
- package/templates/beauty-salon-owner/dev/index.ts +571 -0
- package/templates/beauty-salon-owner/himalaya.content.json +6 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/branded-lite/dev/index.ts +1429 -278
- package/templates/branded-lite/tier5-src/_shared/business-chat-presenter.ts +46 -8
- package/templates/branded-lite/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/branded-lite/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/branded-lite/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/branded-lite/tier5-src/business-chat/index.ts +3 -2
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +52 -7
- package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/community-club/dev/index.ts +397 -2
- package/templates/community-club/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/community-club/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/community-club/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/community-club/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/community-club-owner/dev/index.ts +571 -0
- package/templates/community-club-owner/himalaya.content.json +6 -0
- package/templates/community-club-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/community-club-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/community-club-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/events-meetups/dev/index.ts +397 -2
- package/templates/events-meetups/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/events-meetups/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/events-meetups/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/events-meetups-owner/dev/index.ts +571 -0
- package/templates/events-meetups-owner/himalaya.content.json +6 -0
- package/templates/events-meetups-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/events-meetups-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/gym-fitness/dev/index.ts +828 -39
- package/templates/gym-fitness/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/gym-fitness/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/gym-fitness/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +52 -7
- package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/gym-fitness-owner/dev/index.ts +571 -0
- package/templates/gym-fitness-owner/himalaya.content.json +6 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/nonprofit-cause/dev/index.ts +397 -2
- package/templates/nonprofit-cause/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/nonprofit-cause/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/nonprofit-cause/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/nonprofit-cause-owner/dev/index.ts +571 -0
- package/templates/nonprofit-cause-owner/himalaya.content.json +6 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/owner-lite/dev/index.ts +571 -0
- package/templates/owner-lite/himalaya.content.json +6 -0
- package/templates/owner-lite/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/owner-lite/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/owner-lite/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/podcast-creator/dev/index.ts +397 -2
- package/templates/podcast-creator/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/podcast-creator/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/podcast-creator/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/podcast-creator-owner/dev/index.ts +571 -0
- package/templates/podcast-creator-owner/himalaya.content.json +6 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/portfolio-creative/dev/index.ts +397 -2
- package/templates/portfolio-creative/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/portfolio-creative/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/portfolio-creative/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/portfolio-creative-owner/dev/index.ts +571 -0
- package/templates/portfolio-creative-owner/himalaya.content.json +6 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/restaurant/dev/index.ts +397 -2
- package/templates/restaurant/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/restaurant/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/restaurant/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/restaurant/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/restaurant-owner/dev/index.ts +571 -0
- package/templates/restaurant-owner/himalaya.content.json +6 -0
- package/templates/restaurant-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/restaurant-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/retail-store-owner/dev/index.ts +571 -0
- package/templates/retail-store-owner/himalaya.content.json +6 -0
- package/templates/retail-store-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/retail-store-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
- package/templates/yoga-studio/dev/index.ts +828 -39
- package/templates/yoga-studio/tier5-src/_shared/iap-attendance-form.ts +106 -0
- package/templates/yoga-studio/tier5-src/_shared/iap-attendance-purchase.ts +211 -0
- package/templates/yoga-studio/tier5-src/_shared/iap-attendance.ts +38 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +52 -7
- package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +112 -21
- package/templates/yoga-studio-owner/dev/index.ts +571 -0
- package/templates/yoga-studio-owner/himalaya.content.json +6 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-today-rollup.ts +307 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-widget-reads.ts +23 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-today/index.ts +8 -20
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-today-rollup/index.ts +121 -0
|
@@ -36,6 +36,23 @@ import {
|
|
|
36
36
|
} from "../_shared/himi-events";
|
|
37
37
|
import { initials } from "../_shared/himi-text.js";
|
|
38
38
|
import { hostedSitePageOpener, isHostedWorker } from "../_shared/hosted-checkout.js";
|
|
39
|
+
import { mayUseRegularTicketCheckout } from "../_shared/iap-attendance.js";
|
|
40
|
+
import { ATTENDANCE_INITIAL, ATTENDANCE_NOT_HYDRATED, createAttendancePurchase, type AttendancePurchaseFields } from "../_shared/iap-attendance-purchase.js";
|
|
41
|
+
import { resetUnhydratedKeysOnOlderRuntime } from "../_shared/iap-worker.js";
|
|
42
|
+
|
|
43
|
+
let ticketCheckoutAllowed = false;
|
|
44
|
+
let paymentEvent: unknown;
|
|
45
|
+
let paymentTickets = new Map<string, WixAvailableTicket>();
|
|
46
|
+
let ticketSelectionVersion = 0;
|
|
47
|
+
let lastReady: S | undefined;
|
|
48
|
+
const applePurchase = createAttendancePurchase({ kind: "eventsTicket", prefix: "event", pollAction: "himiEventDetail.iapPoll", onChange: () => { void svc.iapPublish(); } });
|
|
49
|
+
|
|
50
|
+
async function priceTicket(event: unknown, id: string, version: number): Promise<boolean> {
|
|
51
|
+
const available = paymentTickets.get(id);
|
|
52
|
+
if (version !== ticketSelectionVersion) return false;
|
|
53
|
+
await applePurchase.ticket(id, event, available);
|
|
54
|
+
return version === ticketSelectionVersion;
|
|
55
|
+
}
|
|
39
56
|
|
|
40
57
|
/** A hosted signed-in event-page open is in flight (see openRegistration). */
|
|
41
58
|
let hostedOpenInFlight = false;
|
|
@@ -88,7 +105,7 @@ async function writeCachedRow(row: EventRow): Promise<void> {
|
|
|
88
105
|
try { await upsert(ENTITY, row as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
|
|
89
106
|
}
|
|
90
107
|
|
|
91
|
-
interface S {
|
|
108
|
+
interface S extends AttendancePurchaseFields {
|
|
92
109
|
status: "loading" | "ready";
|
|
93
110
|
id: string;
|
|
94
111
|
title: string;
|
|
@@ -139,6 +156,8 @@ interface S {
|
|
|
139
156
|
/** The tier the CTA will reserve. Defaults to the cheapest on-sale tier so the
|
|
140
157
|
* button is never dead, and follows the buyer's tap after that. */
|
|
141
158
|
selectedTierId: string;
|
|
159
|
+
ticketPurchaseBlocked: boolean;
|
|
160
|
+
regularTicketsHidden: boolean;
|
|
142
161
|
/** "General · $25" — echoed next to the CTA so the choice is visible. */
|
|
143
162
|
selectedTierLabel: string;
|
|
144
163
|
/** External/ticketed registration URL when the payload carries one. */
|
|
@@ -179,7 +198,7 @@ function tierPrice(t: WixAvailableTicket): string {
|
|
|
179
198
|
}
|
|
180
199
|
|
|
181
200
|
function tierAvailable(t: WixAvailableTicket): boolean {
|
|
182
|
-
return !!t.id && !/SALE_ENDED|CANCELED|SOLD_OUT/i.test(t.saleStatus ?? "");
|
|
201
|
+
return !!t.id && !/SALE_SCHEDULED|SALE_ENDED|CANCELED|SOLD_OUT/i.test(t.saleStatus ?? "");
|
|
183
202
|
}
|
|
184
203
|
|
|
185
204
|
/** Map the buyer-visible tiers onto rows, cheapest first (so the default pick is
|
|
@@ -205,26 +224,36 @@ function tierRows(defs: WixAvailableTicket[], selectedId: string): TicketTierRow
|
|
|
205
224
|
}
|
|
206
225
|
|
|
207
226
|
/** Best-effort tier read — never sinks the screen if the tier endpoint fails. */
|
|
208
|
-
async function loadTiers(eventId: string): Promise<TicketTierRow[]> {
|
|
227
|
+
async function loadTiers(eventId: string): Promise<{ rows: TicketTierRow[]; tickets: Map<string, WixAvailableTicket> }> {
|
|
209
228
|
try {
|
|
210
229
|
const response = await queryAvailableTickets(eventId);
|
|
211
230
|
const defs = response.definitions ?? [];
|
|
231
|
+
const tickets = new Map(defs.filter((t) => t.id).map((t) => [t.id!, t]));
|
|
212
232
|
const cheapestAvailable = defs
|
|
213
233
|
.filter(tierAvailable)
|
|
214
234
|
.slice()
|
|
215
235
|
.sort((a, b) => Number(a.price?.amount ?? 0) - Number(b.price?.amount ?? 0))[0];
|
|
216
|
-
return tierRows(defs, cheapestAvailable?.id ?? "");
|
|
236
|
+
return { rows: tierRows(defs, cheapestAvailable?.id ?? ""), tickets };
|
|
217
237
|
} catch {
|
|
218
|
-
return [];
|
|
238
|
+
return { rows: [], tickets: new Map() };
|
|
219
239
|
}
|
|
220
240
|
}
|
|
221
241
|
|
|
222
242
|
function derive(s: S): S {
|
|
243
|
+
const regular = ticketCheckoutAllowed || applePurchase.usesRegularPlatform();
|
|
223
244
|
const hasContent = !!s.title;
|
|
224
245
|
const hasMapMarkers = s.mapMarkers.length > 0;
|
|
225
246
|
const hasAttendees = s.attendeeAvatars.length > 0;
|
|
226
|
-
|
|
247
|
+
const purchase = applePurchase.fields(!!s.selectedTierId);
|
|
248
|
+
const tiers = s.ticketTiers.map((t) => ({ ...t, priceLine: regular ? tierPrice(paymentTickets.get(t.id) ?? {}) : t.id === s.selectedTierId ? purchase.iapPrice : "" }));
|
|
249
|
+
const next = {
|
|
227
250
|
...s,
|
|
251
|
+
_poll: undefined,
|
|
252
|
+
...purchase,
|
|
253
|
+
actionMessage: regular && !ticketCheckoutAllowed && s.actionMessage === copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") ? "" : s.actionMessage,
|
|
254
|
+
ticketTiers: tiers,
|
|
255
|
+
regularTicketsHidden: s.registrationKind !== "tickets" || !purchase.iapBuyHidden,
|
|
256
|
+
ticketPurchaseBlocked: s.registrationKind === "tickets" && !regular,
|
|
228
257
|
hasDescriptionJson: s.descriptionJson !== "",
|
|
229
258
|
noMap: !s.mapUrl,
|
|
230
259
|
hasMapMarkers,
|
|
@@ -239,8 +268,8 @@ function derive(s: S): S {
|
|
|
239
268
|
showTierPicker: s.ticketTiers.length > 1,
|
|
240
269
|
hideTierPicker: s.ticketTiers.length <= 1,
|
|
241
270
|
selectedTierLabel: (() => {
|
|
242
|
-
const picked =
|
|
243
|
-
return picked ?
|
|
271
|
+
const picked = tiers.find((t) => t.id === s.selectedTierId);
|
|
272
|
+
return picked ? [picked.name, picked.priceLine].filter(Boolean).join(" · ") : "";
|
|
244
273
|
})(),
|
|
245
274
|
showTickets: s.registrationKind === "tickets",
|
|
246
275
|
hideTickets: s.registrationKind !== "tickets",
|
|
@@ -256,6 +285,8 @@ function derive(s: S): S {
|
|
|
256
285
|
? copyParam("event.errorText", "Event could not be loaded.")
|
|
257
286
|
: copyParam("event.notFoundText", "Event not found.")),
|
|
258
287
|
};
|
|
288
|
+
if (next.status === "ready") lastReady = next;
|
|
289
|
+
return next;
|
|
259
290
|
}
|
|
260
291
|
|
|
261
292
|
function calendarStamp(ms: number): string {
|
|
@@ -288,7 +319,7 @@ function calendarFallbackUrl(s: S, end: number): string {
|
|
|
288
319
|
|
|
289
320
|
/** The Events v3 fieldsets the detail reads (see `WixEventFieldset`). DETAILS carries mainImage and
|
|
290
321
|
* shortDescription: REGISTRATION fills eventType, which skips the query enrichment that used to supply them. */
|
|
291
|
-
export const EVENT_DETAIL_FIELDSETS: WixEventFieldset[] = ["DETAILS", "TEXTS", "REGISTRATION", "URLS"];
|
|
322
|
+
export const EVENT_DETAIL_FIELDSETS: WixEventFieldset[] = ["DETAILS", "TEXTS", "REGISTRATION", "URLS", "FORM"];
|
|
292
323
|
|
|
293
324
|
/** Map the decoded registration/eventType onto the CTA variant. The decoded
|
|
294
325
|
* `eventType` already folds registration.type / registration.initialType /
|
|
@@ -401,16 +432,23 @@ async function enrichRegistration(id: string, e: WixEvent): Promise<WixEvent> {
|
|
|
401
432
|
}
|
|
402
433
|
|
|
403
434
|
const svc = defineService<S, {
|
|
404
|
-
load: (s: S, arg?: unknown) => Promise<S>;
|
|
435
|
+
load: (s: S, arg?: unknown) => Promise<S | undefined>;
|
|
405
436
|
openMap: (s: S) => Promise<S>;
|
|
406
|
-
selectTier: (s: S, arg?: unknown) => Promise<S>;
|
|
437
|
+
selectTier: (s: S, arg?: unknown) => Promise<S | undefined>;
|
|
407
438
|
openRegistration: (s: S) => Promise<S>;
|
|
408
439
|
share: (s: S) => Promise<S>;
|
|
409
440
|
addToCalendar: (s: S) => Promise<S>;
|
|
410
441
|
/** [rico] #3372 — RichContent's on_link: `{ url }` of the tapped link. */
|
|
411
442
|
openLink: (s: S, arg?: unknown) => Promise<S>;
|
|
443
|
+
buyApple: (s: S) => Promise<S>;
|
|
444
|
+
setIapField: (s: S, arg?: unknown) => S;
|
|
445
|
+
iapPublish: (s: S) => S;
|
|
446
|
+
iapRefresh: (s: S) => Promise<S>;
|
|
447
|
+
iapPoll: (s: S) => Promise<S>;
|
|
412
448
|
}>("himiEventDetail", {
|
|
449
|
+
notHydrated: [...ATTENDANCE_NOT_HYDRATED, "ticketPurchaseBlocked"],
|
|
413
450
|
state: derive({
|
|
451
|
+
...ATTENDANCE_INITIAL,
|
|
414
452
|
status: "loading",
|
|
415
453
|
id: inputId(),
|
|
416
454
|
title: "",
|
|
@@ -433,6 +471,8 @@ const svc = defineService<S, {
|
|
|
433
471
|
hasAttendees: false,
|
|
434
472
|
noAttendees: true,
|
|
435
473
|
registrationKind: "rsvp",
|
|
474
|
+
ticketPurchaseBlocked: true,
|
|
475
|
+
regularTicketsHidden: true,
|
|
436
476
|
showRsvp: true,
|
|
437
477
|
hideRsvp: false,
|
|
438
478
|
showTickets: false,
|
|
@@ -462,7 +502,19 @@ const svc = defineService<S, {
|
|
|
462
502
|
noEmpty: true,
|
|
463
503
|
}),
|
|
464
504
|
actions: {
|
|
465
|
-
|
|
505
|
+
iapPublish: (s) => derive(lastReady ?? s),
|
|
506
|
+
iapRefresh: async (): Promise<S> => { await applePurchase.refresh(); return derive(svc.getState()); },
|
|
507
|
+
iapPoll: async (): Promise<S> => { await applePurchase.poll(); return derive(svc.getState()); },
|
|
508
|
+
setIapField: (s, arg) => { applePurchase.change(arg); return derive(s); },
|
|
509
|
+
buyApple: async (s: S): Promise<S> => {
|
|
510
|
+
if (!s.selectedTierId || !s.ticketTiers.some((t) => t.id === s.selectedTierId && t.available)) return derive(s);
|
|
511
|
+
await applePurchase.buy({ key: s.selectedTierId, eventId: s.id });
|
|
512
|
+
return derive(svc.getState());
|
|
513
|
+
},
|
|
514
|
+
load: async (s: S, arg?: unknown): Promise<S | undefined> => {
|
|
515
|
+
const selectionVersion = ++ticketSelectionVersion;
|
|
516
|
+
ticketCheckoutAllowed = false;
|
|
517
|
+
applePurchase.invalidate();
|
|
466
518
|
stashCopy(arg);
|
|
467
519
|
const id = s.id || inputId();
|
|
468
520
|
if (!id) return derive({ ...s, status: "ready", errored: true });
|
|
@@ -479,7 +531,15 @@ const svc = defineService<S, {
|
|
|
479
531
|
// screen BEFORE the CTA is tapped. Best-effort: a tier read that fails
|
|
480
532
|
// leaves the picker collapsed and the CTA falls back to its own read.
|
|
481
533
|
const kind = registrationKindOf(e);
|
|
482
|
-
const
|
|
534
|
+
const loaded = kind === "tickets" ? await loadTiers(id) : { rows: [], tickets: new Map<string, WixAvailableTicket>() };
|
|
535
|
+
const tiers = loaded.rows;
|
|
536
|
+
const selectedTierId = tiers.find((t) => t.isSelected)?.id ?? tiers.find((t) => t.available)?.id ?? "";
|
|
537
|
+
const regular = kind !== "tickets" || await mayUseRegularTicketCheckout(e, loaded.tickets.get(selectedTierId));
|
|
538
|
+
if (selectionVersion !== ticketSelectionVersion) return undefined;
|
|
539
|
+
paymentEvent = e;
|
|
540
|
+
paymentTickets = loaded.tickets;
|
|
541
|
+
ticketCheckoutAllowed = regular;
|
|
542
|
+
if (kind === "tickets" && !await priceTicket(e, selectedTierId, selectionVersion)) return undefined;
|
|
483
543
|
// Write-through: cache the fetched row (same EventRow shape as the list) so a
|
|
484
544
|
// later offline open of this detail can fall back to it.
|
|
485
545
|
await writeCachedRow(normalizeEvent(e));
|
|
@@ -493,7 +553,7 @@ const svc = defineService<S, {
|
|
|
493
553
|
ticketTiers: tiers,
|
|
494
554
|
// Default the pick to the cheapest AVAILABLE tier so the CTA is never
|
|
495
555
|
// dead; the buyer's tap overrides it from there.
|
|
496
|
-
selectedTierId
|
|
556
|
+
selectedTierId,
|
|
497
557
|
title,
|
|
498
558
|
initial: (title.trim()[0] || "E").toUpperCase(),
|
|
499
559
|
when: eventWhen(e),
|
|
@@ -514,11 +574,12 @@ const svc = defineService<S, {
|
|
|
514
574
|
shareUrl: eventPageUrlOf(e),
|
|
515
575
|
calendarStart: eventStartMillis(e) ?? 0,
|
|
516
576
|
calendarEnd: eventEndMillis(e) ?? 0,
|
|
517
|
-
actionMessage: "",
|
|
577
|
+
actionMessage: ticketCheckoutAllowed || !applePurchase.fields(true, false).iapBuyHidden ? "" : copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable."),
|
|
518
578
|
statusLabel: titleCase(e.eventStatus) || titleCase((e as unknown as { status?: string }).status),
|
|
519
579
|
});
|
|
520
580
|
} catch {
|
|
521
581
|
// Offline / fetch failure: fall back to the last-synced cached row before erroring.
|
|
582
|
+
if (selectionVersion !== ticketSelectionVersion) return undefined;
|
|
522
583
|
const cached = await readCachedRow(id);
|
|
523
584
|
if (cached) {
|
|
524
585
|
const title = cached.title || "Event";
|
|
@@ -552,22 +613,46 @@ const svc = defineService<S, {
|
|
|
552
613
|
return derive({ ...s, actionMessage: copyParam("event.mapOpenFailed", "Could not open maps on this device.") });
|
|
553
614
|
}
|
|
554
615
|
},
|
|
555
|
-
selectTier: async (s, arg) => {
|
|
616
|
+
selectTier: async (s: S, arg?: unknown): Promise<S | undefined> => {
|
|
556
617
|
const id = typeof arg === "string" ? arg : (arg as { id?: unknown } | undefined)?.id;
|
|
557
618
|
const wanted = typeof id === "string" ? id : "";
|
|
558
619
|
const tier = s.ticketTiers.find((t) => t.id === wanted);
|
|
559
620
|
// Ignore a tap on an off-sale row rather than letting the CTA promise a
|
|
560
621
|
// ticket it cannot reserve.
|
|
561
622
|
if (!tier || !tier.available) return s;
|
|
623
|
+
const selectionVersion = ++ticketSelectionVersion;
|
|
624
|
+
ticketCheckoutAllowed = false;
|
|
625
|
+
applePurchase.invalidate();
|
|
626
|
+
const regular = await mayUseRegularTicketCheckout(paymentEvent, paymentTickets.get(wanted));
|
|
627
|
+
if (selectionVersion !== ticketSelectionVersion) return undefined;
|
|
628
|
+
ticketCheckoutAllowed = regular;
|
|
629
|
+
if (!await priceTicket(paymentEvent, wanted, selectionVersion)) return undefined;
|
|
562
630
|
return derive({
|
|
563
631
|
...s,
|
|
564
632
|
selectedTierId: wanted,
|
|
565
633
|
ticketTiers: s.ticketTiers.map((t) => ({ ...t, isSelected: t.id === wanted, notSelected: t.id !== wanted })),
|
|
566
634
|
// A new pick invalidates whatever the last attempt said.
|
|
567
|
-
actionMessage: "",
|
|
635
|
+
actionMessage: ticketCheckoutAllowed || !applePurchase.fields(true, false).iapBuyHidden ? "" : copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable."),
|
|
568
636
|
});
|
|
569
637
|
},
|
|
570
|
-
openRegistration: async (s) => {
|
|
638
|
+
openRegistration: async (s): Promise<S> => {
|
|
639
|
+
let eventPageAllowed = true;
|
|
640
|
+
let checkoutEvent: WixEvent | undefined;
|
|
641
|
+
if (s.registrationKind === "tickets") {
|
|
642
|
+
try {
|
|
643
|
+
const current = await getEvent(s.id, { fields: EVENT_DETAIL_FIELDSETS });
|
|
644
|
+
const event = ((current as unknown as { event?: WixEvent }).event ?? current) as WixEvent;
|
|
645
|
+
checkoutEvent = event;
|
|
646
|
+
eventPageAllowed = await mayUseRegularTicketCheckout(event, undefined);
|
|
647
|
+
ticketCheckoutAllowed = eventPageAllowed;
|
|
648
|
+
if (!ticketCheckoutAllowed) {
|
|
649
|
+
const tickets = await queryAvailableTickets(s.id);
|
|
650
|
+
const selected = (tickets.definitions ?? []).find((ticket) => ticket.id === s.selectedTierId);
|
|
651
|
+
ticketCheckoutAllowed = await mayUseRegularTicketCheckout(event, selected);
|
|
652
|
+
}
|
|
653
|
+
if (!ticketCheckoutAllowed) return derive({ ...s, actionMessage: copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") });
|
|
654
|
+
} catch { return derive({ ...s, actionMessage: copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") }); }
|
|
655
|
+
}
|
|
571
656
|
// Phase 2c — NATIVE ticket purchase. Reserve the cheapest available tier,
|
|
572
657
|
// turn the hold into an order, then settle it on the shared in-app pay rail
|
|
573
658
|
// (@wix/himalaya/checkout): wallet where the app has one, in-app Wix cashier
|
|
@@ -598,9 +683,12 @@ const svc = defineService<S, {
|
|
|
598
683
|
// picker is collapsed.
|
|
599
684
|
const tickets = await queryAvailableTickets(s.id);
|
|
600
685
|
const live = (tickets.definitions ?? []).filter(tierAvailable);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
686
|
+
// A recovered first read must show the offer before it can be sold.
|
|
687
|
+
if (live.length > 0 && !s.selectedTierId && s.ticketTiers.length === 0) return svc.load();
|
|
688
|
+
const tier = live.find((t) => t.id === s.selectedTierId);
|
|
689
|
+
if (!tier) return derive({ ...s, actionMessage: copyParam("event.ticketChanged", "That ticket is no longer available. Choose a ticket again.") });
|
|
690
|
+
ticketCheckoutAllowed = await mayUseRegularTicketCheckout(checkoutEvent, tier);
|
|
691
|
+
if (!ticketCheckoutAllowed) return derive({ ...s, actionMessage: copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") });
|
|
604
692
|
if (tier?.id) {
|
|
605
693
|
const held = await createTicketReservation(s.id, [{ ticketDefinitionId: tier.id, quantity: 1 }]);
|
|
606
694
|
reservationId = held.id ?? "";
|
|
@@ -643,6 +731,7 @@ const svc = defineService<S, {
|
|
|
643
731
|
// fall through to the hosted rail below
|
|
644
732
|
}
|
|
645
733
|
// Hosted eventsCheckout — pinned to the live reservation when we have one.
|
|
734
|
+
if (!eventPageAllowed && !reservationId) return derive({ ...s, actionMessage: copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") });
|
|
646
735
|
try {
|
|
647
736
|
const params = reservationId ? { reservationId } : s.eventSlug ? { eventSlug: s.eventSlug } : undefined;
|
|
648
737
|
if (params) {
|
|
@@ -667,6 +756,7 @@ const svc = defineService<S, {
|
|
|
667
756
|
// page → nothing) on its own. Nothing here can change between its prepare and its open (the event
|
|
668
757
|
// is fixed and the page is where the member chooses and pays), so the guard has nothing to re-read.
|
|
669
758
|
// A host that refused or failed leaves the visitor page below.
|
|
759
|
+
if (!eventPageAllowed) return derive({ ...s, actionMessage: copyParam("event.purchaseUnavailable", "Purchasing is temporarily unavailable.") });
|
|
670
760
|
if (isHostedWorker() && s.id && (s.registrationKind === "tickets" || s.registrationKind === "rsvp")) {
|
|
671
761
|
// One signed-in open at a time: the host keeps a single one-time ticket, so a second tap would
|
|
672
762
|
// replace the first tap's ticket and drop that tap into the signed-OUT visitor page below.
|
|
@@ -747,5 +837,6 @@ const svc = defineService<S, {
|
|
|
747
837
|
}),
|
|
748
838
|
},
|
|
749
839
|
});
|
|
840
|
+
resetUnhydratedKeysOnOlderRuntime(svc, { ...svc.getState(), ...ATTENDANCE_INITIAL, ticketPurchaseBlocked: true }, [...ATTENDANCE_NOT_HYDRATED, "ticketPurchaseBlocked"]);
|
|
750
841
|
svc.load();
|
|
751
842
|
export { svc };
|