@riverbankcms/sdk 0.136.0 → 0.137.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/CHANGELOG.md +101 -0
- package/dist/{PreviewEditorSidebar-BU5ZlhQR.mjs → PreviewEditorSidebar-Bn6cONPa.mjs} +8 -8
- package/dist/{PreviewEditorUI-9XkHL-bC.mjs → PreviewEditorUI-LAwXZPSx.mjs} +3 -3
- package/dist/{PreviewQueryProvider-wbEpXryy.mjs → PreviewQueryProvider-ztQUdsNo.mjs} +1 -1
- package/dist/{SdkPreviewModeRuntime-CnWmj-2B.mjs → SdkPreviewModeRuntime-BbbGsI_v.mjs} +596 -164
- package/dist/{SiteChromeCustomizeContext-B6d5zkog.mjs → SiteChromeCustomizeContext-BbkNSt5a.mjs} +2888 -1404
- package/dist/_dts/ai/src/contracts/proposals.d.ts +12 -298
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +21 -14
- package/dist/_dts/ai/src/designer/themePatch.d.ts +5 -10
- package/dist/_dts/api/src/accessAdmin.d.ts +1 -9
- package/dist/_dts/api/src/accountApi.d.ts +49 -2
- package/dist/_dts/api/src/contentRuntime.d.ts +1 -4
- package/dist/_dts/api/src/domainConnection.d.ts +41 -0
- package/dist/_dts/api/src/endpoints.d.ts +194 -181
- package/dist/_dts/api/src/index.d.ts +4 -3
- package/dist/_dts/api/src/media.d.ts +19 -2
- package/dist/_dts/api/src/sdkContracts.d.ts +2 -15
- package/dist/_dts/api/src/sdkMediaContracts.d.ts +40 -0
- package/dist/_dts/api/src/sdkMediaEndpointDefinitions.d.ts +61 -0
- package/dist/_dts/api/src/sdkThemeWire.d.ts +15 -4
- package/dist/_dts/api/src/siteInfrastructure.d.ts +17 -23
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +7 -21
- package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +27 -3
- package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +37 -17
- package/dist/_dts/api/src/types.d.ts +1 -1
- package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -2
- package/dist/_dts/blocks/src/index.d.ts +1 -1
- package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +9 -0
- package/dist/_dts/blocks/src/pageRendererBlockSupport.d.ts +75 -0
- package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +2 -0
- package/dist/_dts/blocks/src/server.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -3
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +34 -22
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/ErrorStep.d.ts +3 -5
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.d.ts +25 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +7 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +5 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useWaitlistClaimRestoration.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/capacity.d.ts +164 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/cta.d.ts +29 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +47 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +14 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/people.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/pricing.d.ts +31 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/OfferingTitle.d.ts +11 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +3 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listingLayout.d.ts +23 -0
- package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +57 -0
- package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +8 -40
- package/dist/_dts/db/src/index.d.ts +1 -0
- package/dist/_dts/db/src/utils/postgrestFilter.d.ts +2 -0
- package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +4 -0
- package/dist/_dts/media-core/src/fileDomain.d.ts +3 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
- package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +3 -2
- package/dist/_dts/preview-next/src/client/preview/siteChromeBrandPreferences.d.ts +1 -1
- package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +2 -0
- package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlSaveRequest.d.ts +51 -0
- package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +24 -2
- package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +23 -1
- package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +8 -0
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/gradients/types.d.ts +5 -0
- package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +25 -2
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +3 -3
- package/dist/_dts/theme-core/src/schema.d.ts +12 -11
- package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +43 -3
- package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +10 -0
- package/dist/_dts/theme-core/src/site-styles/headerBrandPresentation.d.ts +63 -0
- package/dist/_dts/theme-core/src/site-styles/headerBytesComparison.d.ts +30 -0
- package/dist/_dts/theme-core/src/site-styles/headerInteractionPalette.d.ts +50 -1
- package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +48 -9
- package/dist/_dts/theme-core/src/site-styles/headerPreferences.d.ts +162 -0
- package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +73 -0
- package/dist/_dts/theme-core/src/site-styles/headerRecompile.d.ts +118 -0
- package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +10 -1
- package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +7 -0
- package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
- package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
- package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +20 -1
- package/dist/_dts/theme-core/src/site-styles/siteChromeNavPreferences.d.ts +43 -2
- package/dist/client/{BookingConsentAgreement-DCch21a6.mjs → BookingConsentAgreement--_fUCZe-.mjs} +2 -2
- package/dist/client/{DiscountCodeDisclosure-DIj1T59K.mjs → DiscountCodeDisclosure-BMipSoDJ.mjs} +1 -1
- package/dist/client/{EventCombined.client-BWVNlXTx.mjs → EventCombined.client-CwJOxn7A.mjs} +154 -178
- package/dist/client/{EventListing.client-DVFCDe3i.mjs → EventListing.client-eVwiylPW.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-BY5mIHw9.mjs → LeafletStaticMap-IKenna5u.mjs} +1 -1
- package/dist/client/{accordion-CK29E8rG.mjs → accordion-MGAO3PuE.mjs} +1 -1
- package/dist/client/{bookingForm-DFvnet-N.mjs → bookingForm-CudlQPUu.mjs} +5 -5
- package/dist/client/bookings.mjs +418 -79
- package/dist/client/capacity-BW00PO7s.mjs +271 -0
- package/dist/client/{carousel-BVU5NQlb.mjs → carousel-BrbGJ2Jl.mjs} +1 -1
- package/dist/client/{cart-BNItcZVa.mjs → cart-Bq5eU0xZ.mjs} +3 -3
- package/dist/client/{checkout-Bu6iCdkP.mjs → checkout-BAFVRdrK.mjs} +3 -3
- package/dist/client/client.mjs +2919 -1918
- package/dist/client/{context-BImarOAq.mjs → context-DCkiHVdD.mjs} +8 -5
- package/dist/client/dates-2RPXHQy4.mjs +264 -0
- package/dist/client/{eventCalendar-DS2h-UXD.mjs → eventCalendar-B0O-hPF7.mjs} +10 -17
- package/dist/client/{eventCombined-Drt4Oq9p.mjs → eventCombined-DCkDaoDI.mjs} +3 -3
- package/dist/client/{eventDetails-Bl2vWgTX.mjs → eventDetails-D8GG2dnD.mjs} +5 -3
- package/dist/client/{eventListing-CS7PHY7v.mjs → eventListing-3ssV_bxz.mjs} +3 -3
- package/dist/client/{eventRegistration-D-j8eNy2.mjs → eventRegistration-bPQo3kVw.mjs} +562 -309
- package/dist/client/{form-RMpoLTyr.mjs → form-qMv8RDkk.mjs} +2 -2
- package/dist/client/{headerSection-BYE3Lb3k.mjs → headerSection-CH0Sc5hX.mjs} +2 -2
- package/dist/client/hooks.mjs +289 -32
- package/dist/client/{locationMap-BxSr7Kkh.mjs → locationMap-0_xlBnNI.mjs} +2 -2
- package/dist/client/{newsletterForm-DerbXwFC.mjs → newsletterForm-NUW7m9RI.mjs} +2 -2
- package/dist/client/{productDetail-4SZCLhAf.mjs → productDetail-FBEOM7jW.mjs} +3 -3
- package/dist/client/{productList-D7AP4GNq.mjs → productList-R0OSGhnn.mjs} +3 -3
- package/dist/client/{propsDecoder-pzBeCh14.mjs → propsDecoder-pYvx_Srl.mjs} +88 -380
- package/dist/client/rendering/client.mjs +2616 -1637
- package/dist/client/rendering/islands.mjs +17 -17
- package/dist/client/rendering.mjs +2710 -1702
- package/dist/client/{scrollToBlock-CduAKf8T.mjs → scrollToBlock-ByQv96M2.mjs} +1 -1
- package/dist/client/{shop-Cp5p_kGe.mjs → shop-RUG9DmRE.mjs} +6 -6
- package/dist/client/{shop-commerce-DicXYaYX.mjs → shop-commerce-B76Jz23B.mjs} +5 -5
- package/dist/client/{shop-commerce-store-CGWnpY4K.mjs → shop-commerce-store-QuQNdDsD.mjs} +1 -1
- package/dist/client/{shopShared-BDf9ljkm.mjs → shopShared-vXU1omwJ.mjs} +3 -3
- package/dist/client/{useEventFilters-DeeyGYuk.mjs → useEventFilters-ByuU6HLA.mjs} +33 -18
- package/dist/preview-next/before-render.mjs +79 -51
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/keepAlive.mjs +79 -51
- package/dist/preview-next/middleware.mjs +79 -51
- package/dist/{previewAuthStore-DbqBol0V.mjs → previewAuthStore-L_cKW8Sb.mjs} +79 -51
- package/dist/{sdk-runtime-19MO27F0.mjs → sdk-runtime-sUMr5d70.mjs} +2 -2
- package/dist/{separator-DaPLtJ1f.mjs → separator-BIHkie5i.mjs} +1 -1
- package/dist/server/components.mjs +2077 -1274
- package/dist/server/config-validation.mjs +289 -32
- package/dist/server/config.mjs +289 -32
- package/dist/server/data.mjs +289 -32
- package/dist/server/index.mjs +80 -52
- package/dist/server/next.mjs +1822 -1111
- package/dist/server/page-converter.mjs +167 -31
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +1988 -1286
- package/dist/server/rendering.mjs +1943 -1182
- package/dist/server/routing.mjs +351 -86
- package/dist/server/server.mjs +293 -128
- package/dist/server/theme-bridge.mjs +52 -8
- package/dist/server/theme.mjs +27 -8
- package/dist/styles/index.css +15 -0
- package/package.json +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +0 -48
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/pricing.d.ts +0 -17
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +0 -100
- /package/dist/_dts/blocks/src/system/runtime/nodes/events/{shared → domain}/destination.d.ts +0 -0
package/dist/client/bookings.mjs
CHANGED
|
@@ -2838,10 +2838,11 @@ function encodePublicProductCategorySelector(selector) {
|
|
|
2838
2838
|
* Error thrown when an API request fails
|
|
2839
2839
|
*/
|
|
2840
2840
|
var BlockApiError = class extends Error {
|
|
2841
|
-
constructor(message, status, code) {
|
|
2841
|
+
constructor(message, status, code, tag) {
|
|
2842
2842
|
super(message);
|
|
2843
2843
|
this.status = status;
|
|
2844
2844
|
this.code = code;
|
|
2845
|
+
this.tag = tag;
|
|
2845
2846
|
this.name = "BlockApiError";
|
|
2846
2847
|
}
|
|
2847
2848
|
};
|
|
@@ -2873,7 +2874,8 @@ function getBlockApiErrorDetails(data) {
|
|
|
2873
2874
|
const nestedError = isRecord$7(data.error) ? data.error : void 0;
|
|
2874
2875
|
return {
|
|
2875
2876
|
message: typeof nestedError?.message === "string" ? nestedError.message : typeof data.message === "string" ? data.message : void 0,
|
|
2876
|
-
code: typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0
|
|
2877
|
+
code: typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0,
|
|
2878
|
+
tag: typeof nestedError?.tag === "string" ? nestedError.tag : void 0
|
|
2877
2879
|
};
|
|
2878
2880
|
}
|
|
2879
2881
|
function buildUnexpectedJsonResponseMessage(parseResult) {
|
|
@@ -2892,7 +2894,8 @@ async function extractErrorDetails(response) {
|
|
|
2892
2894
|
const details = getBlockApiErrorDetails(parseResult.value);
|
|
2893
2895
|
return {
|
|
2894
2896
|
message: details.message ?? fallbackMessage,
|
|
2895
|
-
code: details.code
|
|
2897
|
+
code: details.code,
|
|
2898
|
+
tag: details.tag
|
|
2896
2899
|
};
|
|
2897
2900
|
}
|
|
2898
2901
|
case "invalid-json": return { message: `${fallbackMessage} (received invalid JSON)` };
|
|
@@ -2989,7 +2992,7 @@ function createBlockApi(config) {
|
|
|
2989
2992
|
const response = await fetch(url, fetchOptions);
|
|
2990
2993
|
if (!response.ok) {
|
|
2991
2994
|
const details = await extractErrorDetails(response);
|
|
2992
|
-
throw new BlockApiError(details.message, response.status, details.code);
|
|
2995
|
+
throw new BlockApiError(details.message, response.status, details.code, details.tag);
|
|
2993
2996
|
}
|
|
2994
2997
|
const json = await parseJsonApiResponse(response);
|
|
2995
2998
|
if (isApiSuccessResponse(json)) return json.data;
|
|
@@ -3823,6 +3826,18 @@ function isRecord$6(value) {
|
|
|
3823
3826
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3824
3827
|
}
|
|
3825
3828
|
//#endregion
|
|
3829
|
+
//#region ../core/src/money-input.ts
|
|
3830
|
+
function unsafeAsNonNegativeCents(value) {
|
|
3831
|
+
return value;
|
|
3832
|
+
}
|
|
3833
|
+
/**
|
|
3834
|
+
* Normalizes a derived amount to non-negative whole cents. This intentionally
|
|
3835
|
+
* clamps negatives to zero; use parseNonNegativeCents for validation.
|
|
3836
|
+
*/
|
|
3837
|
+
function toNonNegativeCents(value) {
|
|
3838
|
+
return unsafeAsNonNegativeCents(Math.max(0, Math.trunc(value)));
|
|
3839
|
+
}
|
|
3840
|
+
//#endregion
|
|
3826
3841
|
//#region ../core/src/booking-flexible-balance.ts
|
|
3827
3842
|
function clampFlexibleBalanceConfiguredAmount(amountCents, totalAmountCents) {
|
|
3828
3843
|
return Math.max(0, Math.min(amountCents, totalAmountCents));
|
|
@@ -8783,6 +8798,11 @@ const gradientConfigSchema = z.object({
|
|
|
8783
8798
|
position: z.string().optional(),
|
|
8784
8799
|
stops: z.array(gradientStopSchema).min(2)
|
|
8785
8800
|
});
|
|
8801
|
+
const gradientsSchema = z.object({
|
|
8802
|
+
button: z.string().min(1).nullable().optional(),
|
|
8803
|
+
hero: z.string().min(1).nullable().optional(),
|
|
8804
|
+
background: z.string().min(1).nullable().optional()
|
|
8805
|
+
});
|
|
8786
8806
|
//#endregion
|
|
8787
8807
|
//#region ../theme-core/src/interactive/baseSchema.ts
|
|
8788
8808
|
/**
|
|
@@ -9448,11 +9468,30 @@ const headerContainerSchema = z.object({
|
|
|
9448
9468
|
tint: z.string().nullable().optional(),
|
|
9449
9469
|
opacity: z.number().min(0).max(1).default(.12)
|
|
9450
9470
|
}).optional();
|
|
9451
|
-
|
|
9471
|
+
//#endregion
|
|
9472
|
+
//#region ../theme-core/src/header/interactionPalette.ts
|
|
9473
|
+
/**
|
|
9474
|
+
* The palettes that fill the nav link with a colour on hover and focus. Each
|
|
9475
|
+
* one names a background/foreground token pair.
|
|
9476
|
+
*/
|
|
9477
|
+
const headerInteractionPillPaletteValues = [
|
|
9452
9478
|
"primary",
|
|
9453
9479
|
"secondary",
|
|
9454
9480
|
"accent"
|
|
9455
|
-
]
|
|
9481
|
+
];
|
|
9482
|
+
/**
|
|
9483
|
+
* "No pill": the nav link keeps whatever hover treatment its recipe compiled,
|
|
9484
|
+
* and the palette step writes nothing at all (#1318 Phase 4c decision 2).
|
|
9485
|
+
*
|
|
9486
|
+
* It exists because "a colour change on hover, no filled background" was not
|
|
9487
|
+
* expressible in the vocabulary, and it is what
|
|
9488
|
+
* `anna-raven-therapy-and-yoga` and `kirtan-lucy` have rendered since before
|
|
9489
|
+
* the palette existed. Without it those two rows can only be classified as a
|
|
9490
|
+
* conscious visual change.
|
|
9491
|
+
*/
|
|
9492
|
+
const headerInteractionQuietPalette = "quiet";
|
|
9493
|
+
const headerInteractionPaletteValues = [...headerInteractionPillPaletteValues, headerInteractionQuietPalette];
|
|
9494
|
+
const headerInteractionPaletteSchema = z.enum(headerInteractionPaletteValues);
|
|
9456
9495
|
//#endregion
|
|
9457
9496
|
//#region ../theme-core/src/boxBackgroundSchema.ts
|
|
9458
9497
|
const boxBackgroundOverlaySchema = z.preprocess(normalizeAuthoringOpacity, z.discriminatedUnion("type", [
|
|
@@ -9973,7 +10012,7 @@ const headerSchema = z.object({
|
|
|
9973
10012
|
variant: headerVariantWithLegacyAliasSchema,
|
|
9974
10013
|
positioning: headerPositioning,
|
|
9975
10014
|
shrinkOnScroll: z.boolean(),
|
|
9976
|
-
maxWidth: headerMaxWidth,
|
|
10015
|
+
maxWidth: headerMaxWidth.default("container"),
|
|
9977
10016
|
scrollTreatment: headerScrollTreatmentSchema,
|
|
9978
10017
|
background: headerBackgroundSchema.default({
|
|
9979
10018
|
type: "color",
|
|
@@ -10172,11 +10211,6 @@ const bodyTextSchema = z.object({ intro: z.object({
|
|
|
10172
10211
|
paragraphSize: bodyTextIntroTypographySizeSchema.optional(),
|
|
10173
10212
|
headingSize: bodyTextIntroTypographySizeSchema.optional()
|
|
10174
10213
|
}).optional() }).optional();
|
|
10175
|
-
const gradientsSchema = z.object({
|
|
10176
|
-
button: z.string().min(1).nullable().optional(),
|
|
10177
|
-
hero: z.string().min(1).nullable().optional(),
|
|
10178
|
-
background: z.string().min(1).nullable().optional()
|
|
10179
|
-
});
|
|
10180
10214
|
/**
|
|
10181
10215
|
* Testimonial quote-mark treatment, owned by the site style (analogous to the
|
|
10182
10216
|
* accordion icon). `style` is the coarse selector; the optional fields fine-tune
|
|
@@ -14300,7 +14334,113 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
|
|
|
14300
14334
|
});
|
|
14301
14335
|
};
|
|
14302
14336
|
//#endregion
|
|
14303
|
-
//#region ../blocks/src/system/runtime/nodes/
|
|
14337
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorRecovery.ts
|
|
14338
|
+
function resolveRegistrationRecoveryAction(step, action) {
|
|
14339
|
+
if (step === "payment-failed") return "payment-options";
|
|
14340
|
+
if (step === "verifying-payment" || step === "verifying-timeout" || step === "redirecting") return "payment-status";
|
|
14341
|
+
return action;
|
|
14342
|
+
}
|
|
14343
|
+
function canRecoverToWaitlist(eligibility) {
|
|
14344
|
+
return Boolean(eligibility?.isFull && eligibility.canJoinWaitlist);
|
|
14345
|
+
}
|
|
14346
|
+
function shouldRefreshAfterRegistrationError(step, action, enabled) {
|
|
14347
|
+
return enabled || step === "error" && action === "places";
|
|
14348
|
+
}
|
|
14349
|
+
function resetRegistrationAfterExpiry(input) {
|
|
14350
|
+
input.dispatchFlow({
|
|
14351
|
+
type: "reset",
|
|
14352
|
+
hasPreSelectedContext: input.hasPreSelectedContext
|
|
14353
|
+
});
|
|
14354
|
+
input.setSelectedTicketLines([]);
|
|
14355
|
+
input.setSelectedSlidingAmountInput("");
|
|
14356
|
+
const mode = input.preSelectedEvent?.deliveryMode;
|
|
14357
|
+
input.setSelectedAttendanceMode(mode === "online" || mode === "in_person" ? mode : null);
|
|
14358
|
+
input.setErrorMessage("");
|
|
14359
|
+
input.setPendingRegistrationReference(null);
|
|
14360
|
+
}
|
|
14361
|
+
/** Recovery never starts another payment. Unknown payment outcomes go to the portal. */
|
|
14362
|
+
function recoverRegistrationError(action, handlers) {
|
|
14363
|
+
switch (action) {
|
|
14364
|
+
case "none": return;
|
|
14365
|
+
case "portal":
|
|
14366
|
+
case "payment-status":
|
|
14367
|
+
window.location.assign("/portal");
|
|
14368
|
+
return;
|
|
14369
|
+
case "event":
|
|
14370
|
+
window.location.assign(window.location.pathname);
|
|
14371
|
+
return;
|
|
14372
|
+
case "retry":
|
|
14373
|
+
window.location.reload();
|
|
14374
|
+
return;
|
|
14375
|
+
case "details":
|
|
14376
|
+
handlers.clearError();
|
|
14377
|
+
handlers.setStep("enter-details");
|
|
14378
|
+
return;
|
|
14379
|
+
case "payment-options":
|
|
14380
|
+
case "places":
|
|
14381
|
+
handlers.refreshOptions();
|
|
14382
|
+
handlers.clearError();
|
|
14383
|
+
handlers.setStep(action === "places" ? handlers.canJoinWaitlist ? "enter-details" : "select-tickets" : "select-payment");
|
|
14384
|
+
return;
|
|
14385
|
+
case "start":
|
|
14386
|
+
handlers.refreshOptions();
|
|
14387
|
+
handlers.reset();
|
|
14388
|
+
return;
|
|
14389
|
+
}
|
|
14390
|
+
}
|
|
14391
|
+
//#endregion
|
|
14392
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/capacity.ts
|
|
14393
|
+
/**
|
|
14394
|
+
* Compute remaining spots for an event from `availableSpots` with a fallback
|
|
14395
|
+
* to `capacity - registeredCount`. Returns `{ available: null, isFull: false }`
|
|
14396
|
+
* for uncapped events so call sites can render no capacity indicator at all.
|
|
14397
|
+
*
|
|
14398
|
+
* The single source of truth for capacity math across event cards, agenda
|
|
14399
|
+
* rows, and timetable cells — keep wording variations in the call sites.
|
|
14400
|
+
*/
|
|
14401
|
+
function getEventAvailability(event) {
|
|
14402
|
+
if (event.capacity == null) return {
|
|
14403
|
+
available: null,
|
|
14404
|
+
isFull: false
|
|
14405
|
+
};
|
|
14406
|
+
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
14407
|
+
if (available <= 0) return {
|
|
14408
|
+
available: 0,
|
|
14409
|
+
isFull: true
|
|
14410
|
+
};
|
|
14411
|
+
return {
|
|
14412
|
+
available,
|
|
14413
|
+
isFull: false
|
|
14414
|
+
};
|
|
14415
|
+
}
|
|
14416
|
+
/**
|
|
14417
|
+
* Pick the capacity row a booking decision should read: the selected
|
|
14418
|
+
* attendance mode's availability when the visitor has chosen one and the
|
|
14419
|
+
* event publishes it, otherwise the event-level aggregate.
|
|
14420
|
+
*
|
|
14421
|
+
* The mode row is used wholesale. A mode with `capacity: null` on a capped
|
|
14422
|
+
* event is uncapped *by design*: the registration write path applies the
|
|
14423
|
+
* same rule via `getEffectiveOccurrenceCapacityForAttendanceMode`, so falling
|
|
14424
|
+
* back to the event's `availableSpots` here would block bookings the server
|
|
14425
|
+
* accepts. (Waitlist claims are still occurrence-scoped; see issue 1377.)
|
|
14426
|
+
*/
|
|
14427
|
+
function selectEventCapacitySource(event, attendanceMode) {
|
|
14428
|
+
if (!attendanceMode) return event;
|
|
14429
|
+
return (event.attendanceModes ?? []).find((mode) => mode.mode === attendanceMode) ?? event;
|
|
14430
|
+
}
|
|
14431
|
+
/**
|
|
14432
|
+
* Whether the visitor's next step is the waitlist: the source is full *and*
|
|
14433
|
+
* a waitlist is open. The one place this is decided — cards, rows, the
|
|
14434
|
+
* wizard's steps and its action bar all route through here so they agree,
|
|
14435
|
+
* including for producers that omit `availableSpots` and rely on the
|
|
14436
|
+
* `capacity - registeredCount` fallback.
|
|
14437
|
+
*/
|
|
14438
|
+
function canJoinEventWaitlist(event, options) {
|
|
14439
|
+
const source = selectEventCapacitySource(event, options?.attendanceMode);
|
|
14440
|
+
return getEventAvailability(source).isFull && source.waitlistEnabled === true;
|
|
14441
|
+
}
|
|
14442
|
+
//#endregion
|
|
14443
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
|
|
14304
14444
|
function isRecord$2(value) {
|
|
14305
14445
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14306
14446
|
}
|
|
@@ -14318,7 +14458,7 @@ function resolveRuntimeEventDestination(event) {
|
|
|
14318
14458
|
};
|
|
14319
14459
|
}
|
|
14320
14460
|
//#endregion
|
|
14321
|
-
//#region ../blocks/src/system/runtime/nodes/events/
|
|
14461
|
+
//#region ../blocks/src/system/runtime/nodes/events/domain/pricing.ts
|
|
14322
14462
|
const DEFAULT_EVENT_CURRENCY = "USD";
|
|
14323
14463
|
function resolveRuntimeEventPricing(event) {
|
|
14324
14464
|
if (isPublicEventPricing(event.pricing)) return event.pricing;
|
|
@@ -14828,11 +14968,11 @@ function useEligibilityWithDeps(params, deps) {
|
|
|
14828
14968
|
type: "resolved",
|
|
14829
14969
|
eligibility: transformRegistrationOptionsResponse(result)
|
|
14830
14970
|
});
|
|
14831
|
-
} catch
|
|
14971
|
+
} catch {
|
|
14832
14972
|
if (cancelled || requestIdRef.current !== requestId) return;
|
|
14833
14973
|
dispatch({
|
|
14834
14974
|
type: "failed",
|
|
14835
|
-
message:
|
|
14975
|
+
message: "We couldn’t load the booking options for this event. Please refresh this page and try again. If this keeps happening, contact the organiser for help."
|
|
14836
14976
|
});
|
|
14837
14977
|
}
|
|
14838
14978
|
}
|
|
@@ -14844,6 +14984,7 @@ function useEligibilityWithDeps(params, deps) {
|
|
|
14844
14984
|
}, [
|
|
14845
14985
|
api,
|
|
14846
14986
|
params.enabled,
|
|
14987
|
+
params.refreshKey,
|
|
14847
14988
|
params.subject?.kind,
|
|
14848
14989
|
params.subject?.kind === "occurrence" ? params.subject.occurrenceId : params.subject?.eventSeriesId,
|
|
14849
14990
|
params.attendanceMode,
|
|
@@ -14953,8 +15094,122 @@ function logoutPortal(anchorId) {
|
|
|
14953
15094
|
form.submit();
|
|
14954
15095
|
}
|
|
14955
15096
|
//#endregion
|
|
15097
|
+
//#region ../commerce/src/purchase/checkoutSessionMetadata.ts
|
|
15098
|
+
const datedOfferingSharedEngineMetadataShape = {
|
|
15099
|
+
datedOfferingEngineContractVersion: z.literal("shared_v1"),
|
|
15100
|
+
datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
|
|
15101
|
+
datedOfferingCapacityHoldId: z.string().uuid(),
|
|
15102
|
+
datedOfferingCapacityHoldAuditRef: z.string().uuid(),
|
|
15103
|
+
customerId: z.string().uuid(),
|
|
15104
|
+
eventSeriesId: z.string().uuid()
|
|
15105
|
+
};
|
|
15106
|
+
z.object(datedOfferingSharedEngineMetadataShape);
|
|
15107
|
+
const orderCheckoutSessionMetadataBaseShape = {
|
|
15108
|
+
type: z.literal("order"),
|
|
15109
|
+
site_id: z.string().uuid(),
|
|
15110
|
+
order_id: z.string().uuid().optional(),
|
|
15111
|
+
customer_email: z.string().email(),
|
|
15112
|
+
customer_name: z.string().optional(),
|
|
15113
|
+
product_id: z.string().uuid().optional(),
|
|
15114
|
+
attendee_id: z.string().uuid().optional(),
|
|
15115
|
+
occurrence_id: z.string().uuid().optional(),
|
|
15116
|
+
tickets_count: z.string().optional(),
|
|
15117
|
+
notes: z.string().optional(),
|
|
15118
|
+
discount_redemption_id: z.string().uuid().optional(),
|
|
15119
|
+
discount_code_id: z.string().uuid().optional(),
|
|
15120
|
+
discount_code: z.string().optional(),
|
|
15121
|
+
discount_public_label: z.string().optional(),
|
|
15122
|
+
credit_reservation_id: z.string().uuid().optional(),
|
|
15123
|
+
credit_reserved_cents: z.string().optional(),
|
|
15124
|
+
discount_code_amount_cents: z.string().optional(),
|
|
15125
|
+
order_payment_reason: z.enum([
|
|
15126
|
+
"instalment_payoff",
|
|
15127
|
+
"flexible_balance_initial",
|
|
15128
|
+
"flexible_balance_paydown"
|
|
15129
|
+
]).optional(),
|
|
15130
|
+
order_payment_plan_id: z.string().uuid().optional(),
|
|
15131
|
+
order_flexible_balance_contract_id: z.string().uuid().optional()
|
|
15132
|
+
};
|
|
15133
|
+
const absentDatedOfferingSharedEngineMetadataShape = {
|
|
15134
|
+
datedOfferingEngineContractVersion: z.never().optional(),
|
|
15135
|
+
datedOfferingEngineRouteKind: z.never().optional(),
|
|
15136
|
+
datedOfferingCapacityHoldId: z.never().optional(),
|
|
15137
|
+
datedOfferingCapacityHoldAuditRef: z.never().optional(),
|
|
15138
|
+
customerId: z.never().optional(),
|
|
15139
|
+
eventSeriesId: z.never().optional()
|
|
15140
|
+
};
|
|
15141
|
+
const LegacyOrderCheckoutSessionMetadataSchema = z.object({
|
|
15142
|
+
...orderCheckoutSessionMetadataBaseShape,
|
|
15143
|
+
...absentDatedOfferingSharedEngineMetadataShape
|
|
15144
|
+
});
|
|
15145
|
+
const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
|
|
15146
|
+
...orderCheckoutSessionMetadataBaseShape,
|
|
15147
|
+
...datedOfferingSharedEngineMetadataShape
|
|
15148
|
+
});
|
|
15149
|
+
z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
|
|
15150
|
+
toNonNegativeCents(0);
|
|
15151
|
+
//#endregion
|
|
15152
|
+
//#region ../commerce/src/purchase/event-registration-errors.ts
|
|
15153
|
+
const eventRegistrationErrors = {
|
|
15154
|
+
registrationClosed: {
|
|
15155
|
+
message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
|
|
15156
|
+
action: "none"
|
|
15157
|
+
},
|
|
15158
|
+
paymentUncertain: {
|
|
15159
|
+
message: "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.",
|
|
15160
|
+
action: "payment-status"
|
|
15161
|
+
},
|
|
15162
|
+
paymentPageUnavailable: {
|
|
15163
|
+
message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
|
|
15164
|
+
action: "retry"
|
|
15165
|
+
},
|
|
15166
|
+
paymentUnavailable: {
|
|
15167
|
+
message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
|
|
15168
|
+
action: "none"
|
|
15169
|
+
},
|
|
15170
|
+
capacityChanged: {
|
|
15171
|
+
message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
|
|
15172
|
+
action: "places"
|
|
15173
|
+
},
|
|
15174
|
+
selectionChanged: {
|
|
15175
|
+
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
15176
|
+
action: "places"
|
|
15177
|
+
},
|
|
15178
|
+
registrationPreparationChanged: {
|
|
15179
|
+
message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
|
|
15180
|
+
action: "places"
|
|
15181
|
+
},
|
|
15182
|
+
registrationAlreadyExists: {
|
|
15183
|
+
message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
|
|
15184
|
+
action: "portal"
|
|
15185
|
+
},
|
|
15186
|
+
holdExpired: {
|
|
15187
|
+
message: "Your reservation has timed out. Please check availability and choose your places again.",
|
|
15188
|
+
action: "start"
|
|
15189
|
+
},
|
|
15190
|
+
waitlistUnavailable: {
|
|
15191
|
+
message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
|
|
15192
|
+
action: "event"
|
|
15193
|
+
},
|
|
15194
|
+
paymentContextMismatch: {
|
|
15195
|
+
message: "The payment options for this event have changed. Please check the latest options before continuing.",
|
|
15196
|
+
action: "payment-options"
|
|
15197
|
+
},
|
|
15198
|
+
idempotencyConflict: {
|
|
15199
|
+
message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
|
|
15200
|
+
action: "portal"
|
|
15201
|
+
},
|
|
15202
|
+
invalidCommitInput: {
|
|
15203
|
+
message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
|
|
15204
|
+
action: "details"
|
|
15205
|
+
}
|
|
15206
|
+
};
|
|
15207
|
+
function parseEventRegistrationErrorReason(value) {
|
|
15208
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
|
|
15209
|
+
}
|
|
15210
|
+
//#endregion
|
|
14956
15211
|
//#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
|
|
14957
|
-
const DEFAULT_WAITLIST_CLAIM_ERROR = "
|
|
15212
|
+
const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
|
|
14958
15213
|
function createInitialWaitlistClaimState(hasToken) {
|
|
14959
15214
|
return hasToken ? { kind: "resolving" } : { kind: "idle" };
|
|
14960
15215
|
}
|
|
@@ -14970,14 +15225,13 @@ function waitlistClaimReducer(_state, action) {
|
|
|
14970
15225
|
}
|
|
14971
15226
|
}
|
|
14972
15227
|
function toWaitlistClaimResolveFailure(error) {
|
|
14973
|
-
const message = error instanceof Error ? error.message : DEFAULT_WAITLIST_CLAIM_ERROR;
|
|
14974
15228
|
if (isUnauthorizedBlockApiError(error)) return {
|
|
14975
15229
|
kind: "portal-login-required",
|
|
14976
|
-
message
|
|
15230
|
+
message: "Please log in to continue with your waiting list invitation."
|
|
14977
15231
|
};
|
|
14978
15232
|
return {
|
|
14979
15233
|
kind: "error",
|
|
14980
|
-
message
|
|
15234
|
+
message: hasStatus(error) && (error.status === 404 || error.status === 409 || error.status === 410) ? eventRegistrationErrors.waitlistUnavailable.message : DEFAULT_WAITLIST_CLAIM_ERROR
|
|
14981
15235
|
};
|
|
14982
15236
|
}
|
|
14983
15237
|
function isUnauthorizedBlockApiError(error) {
|
|
@@ -15338,11 +15592,21 @@ function cleanupStaleRegistrations() {
|
|
|
15338
15592
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.ts
|
|
15339
15593
|
const eventRegistrationStripeReturnDeps = {
|
|
15340
15594
|
usePaymentVerification,
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15595
|
+
readReturnParams: () => {
|
|
15596
|
+
const params = new URLSearchParams(window.location.search);
|
|
15597
|
+
return {
|
|
15598
|
+
registration: params.get("registration"),
|
|
15599
|
+
registration_attempt: params.get(EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM),
|
|
15600
|
+
session_id: params.get("session_id")
|
|
15601
|
+
};
|
|
15602
|
+
},
|
|
15603
|
+
clearReturnParams: () => {
|
|
15604
|
+
consumeSearchParams([
|
|
15605
|
+
"registration",
|
|
15606
|
+
EVENT_REGISTRATION_CHECKOUT_ATTEMPT_PARAM,
|
|
15607
|
+
"session_id"
|
|
15608
|
+
]);
|
|
15609
|
+
},
|
|
15346
15610
|
scrollToBlock,
|
|
15347
15611
|
cleanupStaleRegistrations,
|
|
15348
15612
|
clearPendingRegistration,
|
|
@@ -15363,52 +15627,66 @@ function showReturnReconciliation(options, message) {
|
|
|
15363
15627
|
options.setErrorMessage(message);
|
|
15364
15628
|
options.setStep("verifying-timeout");
|
|
15365
15629
|
}
|
|
15630
|
+
function checkoutReturnCommand(params) {
|
|
15631
|
+
const checkoutAttemptId = params.registration_attempt;
|
|
15632
|
+
if (!checkoutAttemptId) return null;
|
|
15633
|
+
if (params.registration === "cancelled") return {
|
|
15634
|
+
kind: "abandon",
|
|
15635
|
+
checkoutAttemptId
|
|
15636
|
+
};
|
|
15637
|
+
if (params.registration === "success" && params.session_id) return {
|
|
15638
|
+
kind: "resolveSuccess",
|
|
15639
|
+
checkoutAttemptId,
|
|
15640
|
+
sessionId: params.session_id
|
|
15641
|
+
};
|
|
15642
|
+
return null;
|
|
15643
|
+
}
|
|
15366
15644
|
async function handleCheckoutReturn(options, deps, checkoutAttemptIdRef) {
|
|
15367
15645
|
deps.cleanupStaleRegistrations();
|
|
15368
|
-
const params = deps.
|
|
15369
|
-
if (params.registration !== "cancelled" && params.registration !== "success") return;
|
|
15646
|
+
const params = deps.readReturnParams();
|
|
15647
|
+
if (params.registration !== "cancelled" && params.registration !== "success") return "settled";
|
|
15370
15648
|
deps.scrollToBlock(EVENT_REGISTRATION_ANCHOR_ID);
|
|
15371
15649
|
const siteId = options.api.config.siteId;
|
|
15372
|
-
const
|
|
15373
|
-
if (!siteId) return;
|
|
15374
|
-
if (!
|
|
15375
|
-
showReturnReconciliation(options, "We
|
|
15376
|
-
return;
|
|
15650
|
+
const command = checkoutReturnCommand(params);
|
|
15651
|
+
if (!siteId) return "settled";
|
|
15652
|
+
if (!command) {
|
|
15653
|
+
showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
|
|
15654
|
+
return "settled";
|
|
15377
15655
|
}
|
|
15656
|
+
const { checkoutAttemptId } = command;
|
|
15378
15657
|
const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
|
|
15379
15658
|
checkoutAttemptIdRef.current = checkoutAttemptId;
|
|
15380
15659
|
if (pending) restorePendingPresentation(options, pending);
|
|
15660
|
+
options.setStep("verifying-payment");
|
|
15381
15661
|
try {
|
|
15382
|
-
const outcome =
|
|
15383
|
-
kind: "resolveSuccess",
|
|
15384
|
-
checkoutAttemptId,
|
|
15385
|
-
sessionId: params.session_id
|
|
15386
|
-
}) : { kind: "notFound" } : await options.api.resolveEventCheckoutReturn({
|
|
15387
|
-
kind: "abandon",
|
|
15388
|
-
checkoutAttemptId
|
|
15389
|
-
});
|
|
15662
|
+
const outcome = await options.api.resolveEventCheckoutReturn(command);
|
|
15390
15663
|
switch (outcome.kind) {
|
|
15391
15664
|
case "resolved":
|
|
15665
|
+
deps.clearReturnParams();
|
|
15392
15666
|
options.setPendingRegistrationReference(outcome.reference);
|
|
15393
15667
|
options.setStep("verifying-payment");
|
|
15394
|
-
return;
|
|
15668
|
+
return "settled";
|
|
15395
15669
|
case "abandoned":
|
|
15670
|
+
deps.clearReturnParams();
|
|
15396
15671
|
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
15397
15672
|
options.setStep("select-payment");
|
|
15398
|
-
return;
|
|
15673
|
+
return "settled";
|
|
15399
15674
|
case "notFound":
|
|
15400
15675
|
if (params.registration === "cancelled" && (options.registrationSubject?.kind === "occurrence" || pending?.reference.scope === "occurrence")) {
|
|
15676
|
+
deps.clearReturnParams();
|
|
15401
15677
|
options.setErrorMessage("Your payment was cancelled. You can choose a payment option and try again.");
|
|
15402
15678
|
options.setStep("select-payment");
|
|
15403
|
-
return;
|
|
15679
|
+
return "settled";
|
|
15404
15680
|
}
|
|
15405
|
-
|
|
15681
|
+
showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
|
|
15682
|
+
return "settled";
|
|
15406
15683
|
case "reconciliationRequired": break;
|
|
15407
15684
|
}
|
|
15408
|
-
showReturnReconciliation(options, "We’re checking your payment. Please
|
|
15685
|
+
showReturnReconciliation(options, "We’re checking your booking and payment. Please don’t try to book again yet. If you’ve already paid, you don’t need to pay again.");
|
|
15409
15686
|
} catch {
|
|
15410
|
-
showReturnReconciliation(options, "We
|
|
15687
|
+
showReturnReconciliation(options, "We couldn’t check your payment just now. Please check again in a moment. Don’t make another booking while we’re checking.");
|
|
15411
15688
|
}
|
|
15689
|
+
return "retryable";
|
|
15412
15690
|
}
|
|
15413
15691
|
function useEventRegistrationStripeReturn(options) {
|
|
15414
15692
|
return useEventRegistrationStripeReturnWithDeps(options, eventRegistrationStripeReturnDeps);
|
|
@@ -15416,10 +15694,34 @@ function useEventRegistrationStripeReturn(options) {
|
|
|
15416
15694
|
function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
15417
15695
|
const { api, pendingRegistrationReference, setErrorMessage, setRegistrationResult, setStep, step } = options;
|
|
15418
15696
|
const checkoutAttemptIdRef = useRef(null);
|
|
15697
|
+
const lookupInFlightRef = useRef(false);
|
|
15698
|
+
const [lookupState, setLookupState] = useState("settled");
|
|
15699
|
+
const resolveReturn = useCallback(async () => {
|
|
15700
|
+
if (lookupInFlightRef.current) return;
|
|
15701
|
+
lookupInFlightRef.current = true;
|
|
15702
|
+
setLookupState("loading");
|
|
15703
|
+
try {
|
|
15704
|
+
setLookupState(await handleCheckoutReturn(options, deps, checkoutAttemptIdRef));
|
|
15705
|
+
} finally {
|
|
15706
|
+
lookupInFlightRef.current = false;
|
|
15707
|
+
}
|
|
15708
|
+
}, [options, deps]);
|
|
15419
15709
|
const verificationConfig = useMemo(() => step === "verifying-payment" && pendingRegistrationReference ? { reference: pendingRegistrationReference } : null, [step, pendingRegistrationReference]);
|
|
15420
15710
|
const verification = deps.usePaymentVerification(verificationConfig);
|
|
15711
|
+
const hasVerificationTimeout = step === "verifying-timeout" && pendingRegistrationReference !== null;
|
|
15712
|
+
const retry = useCallback(() => {
|
|
15713
|
+
if (hasVerificationTimeout) {
|
|
15714
|
+
setStep("verifying-payment");
|
|
15715
|
+
return;
|
|
15716
|
+
}
|
|
15717
|
+
verification.retry();
|
|
15718
|
+
}, [
|
|
15719
|
+
hasVerificationTimeout,
|
|
15720
|
+
setStep,
|
|
15721
|
+
verification.retry
|
|
15722
|
+
]);
|
|
15421
15723
|
useEffect(() => {
|
|
15422
|
-
|
|
15724
|
+
resolveReturn();
|
|
15423
15725
|
}, []);
|
|
15424
15726
|
useEffect(() => {
|
|
15425
15727
|
if (verification.status === "completed") {
|
|
@@ -15429,7 +15731,7 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
|
15429
15731
|
setRegistrationResult({ status: "confirmed" });
|
|
15430
15732
|
setStep("success");
|
|
15431
15733
|
} else if (verification.status === "failed") {
|
|
15432
|
-
setErrorMessage(
|
|
15734
|
+
setErrorMessage("Please try again or choose another payment option. If this keeps happening, contact the organiser for help.");
|
|
15433
15735
|
setStep("payment-failed");
|
|
15434
15736
|
} else if (verification.status === "timeout") setStep("verifying-timeout");
|
|
15435
15737
|
}, [
|
|
@@ -15442,7 +15744,22 @@ function useEventRegistrationStripeReturnWithDeps(options, deps) {
|
|
|
15442
15744
|
setRegistrationResult,
|
|
15443
15745
|
setStep
|
|
15444
15746
|
]);
|
|
15445
|
-
return
|
|
15747
|
+
return {
|
|
15748
|
+
...verification,
|
|
15749
|
+
status: hasVerificationTimeout ? "timeout" : verification.status,
|
|
15750
|
+
retry,
|
|
15751
|
+
retryReturn: lookupState === "retryable" ? () => {
|
|
15752
|
+
resolveReturn();
|
|
15753
|
+
} : void 0
|
|
15754
|
+
};
|
|
15755
|
+
}
|
|
15756
|
+
//#endregion
|
|
15757
|
+
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationErrorPresentation.ts
|
|
15758
|
+
function registrationErrorPresentation(error) {
|
|
15759
|
+
const reason = error instanceof BlockApiError ? parseEventRegistrationErrorReason(error.tag) : null;
|
|
15760
|
+
if (reason) return eventRegistrationErrors[reason];
|
|
15761
|
+
if (error instanceof BlockApiError && error.status < 500) return eventRegistrationErrors.invalidCommitInput;
|
|
15762
|
+
return eventRegistrationErrors.paymentUncertain;
|
|
15446
15763
|
}
|
|
15447
15764
|
//#endregion
|
|
15448
15765
|
//#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
|
|
@@ -15531,7 +15848,8 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
|
|
|
15531
15848
|
outcome: { kind: "completed" }
|
|
15532
15849
|
};
|
|
15533
15850
|
} catch (error) {
|
|
15534
|
-
const message
|
|
15851
|
+
const { message, action } = registrationErrorPresentation(error);
|
|
15852
|
+
options.setErrorAction?.(action);
|
|
15535
15853
|
options.setErrorMessage(message);
|
|
15536
15854
|
options.setStep("error");
|
|
15537
15855
|
return {
|
|
@@ -16616,12 +16934,12 @@ function getEventRegistrationOverrideInput(props) {
|
|
|
16616
16934
|
if (!props.siteId) return {
|
|
16617
16935
|
ok: false,
|
|
16618
16936
|
reason: "missing-site-id",
|
|
16619
|
-
message: "
|
|
16937
|
+
message: "Online booking is unavailable right now. Please contact the organiser for help with booking."
|
|
16620
16938
|
};
|
|
16621
16939
|
if (!props.apiBaseUrl) return {
|
|
16622
16940
|
ok: false,
|
|
16623
16941
|
reason: "missing-api-base-url",
|
|
16624
|
-
message: "
|
|
16942
|
+
message: "Online booking is unavailable right now. Please contact the organiser for help with booking."
|
|
16625
16943
|
};
|
|
16626
16944
|
const content = props.content ?? {};
|
|
16627
16945
|
const data = isRecord(props.data) ? props.data : {};
|
|
@@ -16808,7 +17126,8 @@ function resolveHeadlessEventRegistrationStatus(wizard) {
|
|
|
16808
17126
|
} : { tag: "ready" };
|
|
16809
17127
|
case "error": return {
|
|
16810
17128
|
tag: "error",
|
|
16811
|
-
message: wizard.errorMessage
|
|
17129
|
+
message: wizard.errorMessage,
|
|
17130
|
+
...wizard.errorAction ? { action: wizard.errorAction } : {}
|
|
16812
17131
|
};
|
|
16813
17132
|
case "select-event":
|
|
16814
17133
|
case "select-tickets":
|
|
@@ -16823,7 +17142,7 @@ function resolveHeadlessEventRegistrationView(wizard) {
|
|
|
16823
17142
|
};
|
|
16824
17143
|
if (!wizard.scopedEvents.some(isEventRegistrationAvailable) && !wizard.occurrenceContext) return {
|
|
16825
17144
|
kind: "unavailable",
|
|
16826
|
-
message: "
|
|
17145
|
+
message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more."
|
|
16827
17146
|
};
|
|
16828
17147
|
switch (wizard.step) {
|
|
16829
17148
|
case "verifying-payment": return {
|
|
@@ -16841,7 +17160,7 @@ function resolveHeadlessEventRegistrationView(wizard) {
|
|
|
16841
17160
|
};
|
|
16842
17161
|
case "verifying-timeout": return {
|
|
16843
17162
|
kind: "verifying",
|
|
16844
|
-
message: "Your
|
|
17163
|
+
message: "Your booking is not confirmed yet. Please don’t make another booking while we check. You can check your payment status again in a moment."
|
|
16845
17164
|
};
|
|
16846
17165
|
case "select-event":
|
|
16847
17166
|
case "select-tickets":
|
|
@@ -17078,6 +17397,13 @@ function toWholeSeriesRegistrationEvents(offerings) {
|
|
|
17078
17397
|
}
|
|
17079
17398
|
//#endregion
|
|
17080
17399
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationWizardContext.ts
|
|
17400
|
+
function getEventSelectionDefaults(event) {
|
|
17401
|
+
const suggestedAmount = getSlidingScaleForEvent(event)?.suggestedAmount;
|
|
17402
|
+
return {
|
|
17403
|
+
slidingAmountInput: suggestedAmount == null ? "" : formatCentsAsCurrencyInput(suggestedAmount),
|
|
17404
|
+
attendanceMode: event.deliveryMode === "hybrid" ? null : event.deliveryMode ?? "in_person"
|
|
17405
|
+
};
|
|
17406
|
+
}
|
|
17081
17407
|
function parseCurrencyInputToCents(value) {
|
|
17082
17408
|
const trimmed = value.trim();
|
|
17083
17409
|
if (!trimmed) return null;
|
|
@@ -17125,7 +17451,7 @@ function resolveWaitlistClaimRestoration(input) {
|
|
|
17125
17451
|
const event = findEventByOccurrenceId(input.scopedEvents, subject.occurrenceId);
|
|
17126
17452
|
if (!event && input.occurrenceContextId !== subject.occurrenceId) return {
|
|
17127
17453
|
ok: false,
|
|
17128
|
-
message: "This
|
|
17454
|
+
message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
|
|
17129
17455
|
};
|
|
17130
17456
|
return {
|
|
17131
17457
|
ok: true,
|
|
@@ -17142,7 +17468,7 @@ function resolveWaitlistClaimRestoration(input) {
|
|
|
17142
17468
|
const event = input.scopedEvents.find((candidate) => candidate.registrationSubject.kind === "wholeSeries" && candidate.registrationSubject.eventSeriesId === subject.eventSeriesId);
|
|
17143
17469
|
if (!event) return {
|
|
17144
17470
|
ok: false,
|
|
17145
|
-
message: "This
|
|
17471
|
+
message: "This waiting list invitation is for a different event. Please open the link in your invitation email."
|
|
17146
17472
|
};
|
|
17147
17473
|
return {
|
|
17148
17474
|
ok: true,
|
|
@@ -17175,6 +17501,7 @@ function useWaitlistClaimRestoration(input) {
|
|
|
17175
17501
|
occurrenceContextId: input.occurrenceContextId
|
|
17176
17502
|
});
|
|
17177
17503
|
if (!restoration.ok) {
|
|
17504
|
+
input.setters.setErrorAction?.("none");
|
|
17178
17505
|
input.setters.setErrorMessage(restoration.message);
|
|
17179
17506
|
input.setters.setStep("error");
|
|
17180
17507
|
return;
|
|
@@ -17253,6 +17580,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17253
17580
|
});
|
|
17254
17581
|
const [registrationResult, setRegistrationResult] = useState(null);
|
|
17255
17582
|
const [errorMessage, setErrorMessage] = useState("");
|
|
17583
|
+
const [errorAction, setErrorAction] = useState("retry");
|
|
17584
|
+
const [optionsRefreshKey, setOptionsRefreshKey] = useState(0);
|
|
17256
17585
|
const [altchaSolution, setAltchaSolution] = useState(null);
|
|
17257
17586
|
const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
|
|
17258
17587
|
const waitlistClaim = deps.useWaitlistClaim();
|
|
@@ -17282,10 +17611,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17282
17611
|
const currentEvent = selectedEvent ?? preSelectedEvent;
|
|
17283
17612
|
const currentEventPricing = currentEvent ? resolveRuntimeEventPricing(currentEvent) : null;
|
|
17284
17613
|
const currentEventUsesTicketTypes = currentEventPricing !== null && publicEventPricingMode(currentEventPricing) === "ticket_types";
|
|
17285
|
-
const
|
|
17286
|
-
const
|
|
17287
|
-
const currentWaitlistEnabled = selectedModeAvailability?.waitlistEnabled ?? currentEvent?.waitlistEnabled ?? false;
|
|
17288
|
-
const usesTicketTypeSelections = currentEventUsesTicketTypes && !(currentAvailableSpots === 0 && currentWaitlistEnabled === true);
|
|
17614
|
+
const currentCanJoinWaitlist = currentEvent ? canJoinEventWaitlist(currentEvent, { attendanceMode: selectedAttendanceMode }) : false;
|
|
17615
|
+
const usesTicketTypeSelections = currentEventUsesTicketTypes && !currentCanJoinWaitlist;
|
|
17289
17616
|
const eventTicketTypesForSelection = useMemo(() => getVisibleTicketTypes({
|
|
17290
17617
|
event: currentEvent,
|
|
17291
17618
|
eligibility: null,
|
|
@@ -17316,7 +17643,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17316
17643
|
});
|
|
17317
17644
|
}, [flowState.ticketsCount, ticketsCount]);
|
|
17318
17645
|
const eligibilityResult = deps.useEligibility({
|
|
17319
|
-
|
|
17646
|
+
refreshKey: optionsRefreshKey,
|
|
17647
|
+
enabled: shouldRefreshAfterRegistrationError(step, errorAction, shouldLoadRegistrationOptions(portalAuthState, step)),
|
|
17320
17648
|
subject: registrationTarget?.subject ?? null,
|
|
17321
17649
|
attendanceMode: selectedAttendanceMode,
|
|
17322
17650
|
ticketSelections,
|
|
@@ -17345,6 +17673,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17345
17673
|
});
|
|
17346
17674
|
}, [waitlistClaim.claim]);
|
|
17347
17675
|
const waitlistRestorationSetters = useMemo(() => ({
|
|
17676
|
+
setErrorAction,
|
|
17348
17677
|
setErrorMessage,
|
|
17349
17678
|
setStep,
|
|
17350
17679
|
setSelectedEvent,
|
|
@@ -17368,6 +17697,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17368
17697
|
if (waitlistClaim.requiresPortalLogin) return;
|
|
17369
17698
|
if (!waitlistClaim.error) return;
|
|
17370
17699
|
setErrorMessage(waitlistClaim.error);
|
|
17700
|
+
setErrorAction("event");
|
|
17371
17701
|
setStep("error");
|
|
17372
17702
|
}, [
|
|
17373
17703
|
waitlistClaim.error,
|
|
@@ -17470,8 +17800,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17470
17800
|
const event = currentEvent;
|
|
17471
17801
|
if (!event || publicEventPricingMode(resolveRuntimeEventPricing(event)) !== "ticket_types") return false;
|
|
17472
17802
|
if ((event.deliveryMode ?? "in_person") === "hybrid" && !selectedAttendanceMode) return false;
|
|
17473
|
-
|
|
17474
|
-
return !((selectedModeAvailability?.availableSpots ?? event.availableSpots) === 0 && (selectedModeAvailability?.waitlistEnabled ?? event.waitlistEnabled) === true);
|
|
17803
|
+
return !canJoinEventWaitlist(event, { attendanceMode: selectedAttendanceMode });
|
|
17475
17804
|
}, [currentEvent, selectedAttendanceMode]);
|
|
17476
17805
|
const hasValidTicketSelection = !ticketTypeSelectionRequired || normalizedSelectedTicketLines.length > 0 && normalizedSelectedTicketLines.every((line) => {
|
|
17477
17806
|
if (!line.ticketTypeId) return false;
|
|
@@ -17552,6 +17881,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17552
17881
|
]);
|
|
17553
17882
|
const handleDetailsComplete = async () => {
|
|
17554
17883
|
if (ticketTypeSelectionRequired && !hasValidTicketSelection) {
|
|
17884
|
+
setErrorAction("places");
|
|
17555
17885
|
const message = "Choose at least one available ticket to continue.";
|
|
17556
17886
|
setErrorMessage(message);
|
|
17557
17887
|
setStep("error");
|
|
@@ -17562,6 +17892,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17562
17892
|
};
|
|
17563
17893
|
}
|
|
17564
17894
|
if (slidingScaleSelectionMessage) {
|
|
17895
|
+
setErrorAction("places");
|
|
17565
17896
|
setErrorMessage(slidingScaleSelectionMessage);
|
|
17566
17897
|
setStep("error");
|
|
17567
17898
|
return {
|
|
@@ -17579,7 +17910,8 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17579
17910
|
};
|
|
17580
17911
|
}
|
|
17581
17912
|
if (waitlistClaim.claim === null && eligibility?.isFull && !eligibility.canJoinWaitlist) {
|
|
17582
|
-
const message = "
|
|
17913
|
+
const message = "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.";
|
|
17914
|
+
setErrorAction("places");
|
|
17583
17915
|
setErrorMessage(message);
|
|
17584
17916
|
setStep("error");
|
|
17585
17917
|
return {
|
|
@@ -17695,6 +18027,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17695
18027
|
const selectionMethod = paymentSelection.method;
|
|
17696
18028
|
const shouldShowDiscountToggle = discountContext !== null && discountUi.manualCodeEntryAllowed && (selectionMethod === "stripe" || selectionMethod === "pass_bundle" || selectionMethod === "membership_bundle");
|
|
17697
18029
|
const handleSubmit = deps.useEventRegistrationSubmit({
|
|
18030
|
+
setErrorAction,
|
|
17698
18031
|
api,
|
|
17699
18032
|
registrationTarget,
|
|
17700
18033
|
selectedAttendanceMode,
|
|
@@ -17717,26 +18050,31 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17717
18050
|
...current,
|
|
17718
18051
|
consentAccepted: false
|
|
17719
18052
|
}));
|
|
17720
|
-
const
|
|
17721
|
-
setSelectedSlidingAmountInput(
|
|
17722
|
-
setSelectedAttendanceMode(
|
|
18053
|
+
const defaults = getEventSelectionDefaults(event);
|
|
18054
|
+
setSelectedSlidingAmountInput(defaults.slidingAmountInput);
|
|
18055
|
+
setSelectedAttendanceMode(defaults.attendanceMode);
|
|
17723
18056
|
setSelectedTicketLines([]);
|
|
17724
18057
|
dispatchFlow({
|
|
17725
18058
|
type: "event-changed",
|
|
17726
18059
|
hasPreSelectedContext: true
|
|
17727
18060
|
});
|
|
17728
18061
|
};
|
|
17729
|
-
const handleRetry = () => {
|
|
17730
|
-
|
|
17731
|
-
|
|
17732
|
-
|
|
17733
|
-
|
|
17734
|
-
|
|
17735
|
-
|
|
17736
|
-
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
18062
|
+
const handleRetry = () => recoverRegistrationError(resolveRegistrationRecoveryAction(step, errorAction), {
|
|
18063
|
+
canJoinWaitlist: canRecoverToWaitlist(eligibility),
|
|
18064
|
+
refreshOptions: () => setOptionsRefreshKey((value) => value + 1),
|
|
18065
|
+
clearError: () => setErrorMessage(""),
|
|
18066
|
+
setStep,
|
|
18067
|
+
reset: () => resetRegistrationAfterExpiry({
|
|
18068
|
+
hasPreSelectedContext,
|
|
18069
|
+
preSelectedEvent,
|
|
18070
|
+
dispatchFlow,
|
|
18071
|
+
setSelectedTicketLines,
|
|
18072
|
+
setSelectedSlidingAmountInput,
|
|
18073
|
+
setSelectedAttendanceMode,
|
|
18074
|
+
setErrorMessage,
|
|
18075
|
+
setPendingRegistrationReference
|
|
18076
|
+
})
|
|
18077
|
+
});
|
|
17740
18078
|
const handlePaymentStepStateChange = useCallback((state) => {
|
|
17741
18079
|
setPaymentStepState(state);
|
|
17742
18080
|
}, []);
|
|
@@ -17799,6 +18137,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
17799
18137
|
handleGuestShakeEnd,
|
|
17800
18138
|
registrationResult,
|
|
17801
18139
|
errorMessage,
|
|
18140
|
+
errorAction,
|
|
17802
18141
|
altchaSolution,
|
|
17803
18142
|
setAltchaSolution,
|
|
17804
18143
|
portalAuthState,
|