@riverbankcms/sdk 0.77.1 → 0.78.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/README.md +69 -0
- package/dist/{PreviewEditorSidebar-DVUG7GK4.mjs → PreviewEditorSidebar-RIKFQ72L.mjs} +4916 -4847
- package/dist/{PreviewEditorUI-P7RN4CDS.mjs → PreviewEditorUI-XO7TUWKK.mjs} +3 -3
- package/dist/SdkPreviewModeRuntime-LAGYMPNF.mjs +8 -0
- package/dist/_dts/ai/src/contracts/proposals.d.ts +154 -154
- package/dist/_dts/api/src/accessAdmin.d.ts +5 -0
- package/dist/_dts/api/src/billing.d.ts +3 -26
- package/dist/_dts/api/src/bookingVerticals.d.ts +4 -0
- package/dist/_dts/api/src/content-editor.d.ts +1 -0
- package/dist/_dts/api/src/demoDashboardMutationSurfaces.d.ts +46 -0
- package/dist/_dts/api/src/endpoints.d.ts +8 -0
- package/dist/_dts/api/src/index.d.ts +14 -2
- package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +87 -0
- package/dist/_dts/api/src/navigation/dashboardDemoNav.d.ts +5 -0
- package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +45 -0
- package/dist/_dts/api/src/navigation/dashboardSiteNav.d.ts +42 -0
- package/dist/_dts/api/src/navigation/dashboardTeamMemberNav.d.ts +24 -0
- package/dist/_dts/api/src/navigation/linkUrlType.d.ts +3 -0
- package/dist/_dts/api/src/navigation.d.ts +12 -0
- package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +55 -26
- package/dist/_dts/api/src/staffAccess.d.ts +79 -0
- package/dist/_dts/api/src/types.d.ts +3 -1
- package/dist/_dts/api/src/workflows/automaticWorkflowTriggers.d.ts +21 -0
- package/dist/_dts/blocks/src/client/site-chrome.d.ts +4 -1
- package/dist/_dts/blocks/src/index.d.ts +1 -0
- package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/blog-listing.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/cart.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/checkout.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/collection.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +2 -2
- package/dist/_dts/blocks/src/system/blocks/faq.d.ts +294 -289
- package/dist/_dts/blocks/src/system/blocks/gifting.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +21 -21
- package/dist/_dts/blocks/src/system/blocks/product-detail.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/product-list.d.ts +288 -288
- package/dist/_dts/blocks/src/system/blocks/shop.d.ts +288 -288
- package/dist/_dts/blocks/src/system/data/index.d.ts +5 -3
- package/dist/_dts/blocks/src/system/data/previewResolvedDataState.d.ts +45 -0
- package/dist/_dts/blocks/src/system/fields/boxStyles.d.ts +2 -1
- package/dist/_dts/blocks/src/system/fragments/library/faqAccordion.d.ts +5 -0
- package/dist/_dts/blocks/src/system/manifest/schema.d.ts +29 -29
- package/dist/_dts/blocks/src/system/node/fragments/headingDecoration.d.ts +10 -0
- package/dist/_dts/blocks/src/system/node/fragments/index.d.ts +1 -0
- package/dist/_dts/blocks/src/system/node/fragments/styledSection.d.ts +9 -0
- package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +3 -2
- package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
- package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +43 -8
- package/dist/_dts/blocks/src/system/runtime/header/shared.d.ts +8 -7
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCompactRow.d.ts +1 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +7 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/header-section.client.d.ts +2 -8
- package/dist/_dts/blocks/src/system/runtime/nodes/header-section.server.d.ts +2 -9
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-cart-discount-ui.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-checkout-form.d.ts +76 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-checkout.state.d.ts +1 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-commerce-store.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-commerce.shared.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/shop-discount-apply.state.d.ts +52 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/shop.state.d.ts +2 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/useDiscountApply.d.ts +21 -0
- package/dist/_dts/blocks/src/system/runtime/shared/components/DiscountCodeDisclosure.d.ts +54 -0
- package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/transforms/registry/ui.d.ts +1 -1
- package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -1
- package/dist/_dts/content-editor/src/contentTypeEditorContentState.d.ts +26 -0
- package/dist/_dts/content-editor/src/definitions/factory.d.ts +75 -0
- package/dist/_dts/content-editor/src/entryWorkflows.d.ts +2 -0
- package/dist/_dts/content-editor/src/footerBlocksEditorState.d.ts +76 -0
- package/dist/_dts/content-editor/src/index.d.ts +5 -0
- package/dist/_dts/content-editor/src/pageWorkflowContent.d.ts +29 -0
- package/dist/_dts/content-model/src/content-types/schema.d.ts +3 -3
- package/dist/_dts/content-model/src/index.d.ts +1 -0
- package/dist/_dts/content-model/src/routeTemplate.d.ts +4 -0
- package/dist/_dts/content-model/src/templates/editorState.d.ts +25 -0
- package/dist/_dts/core/src/csv-cells.d.ts +10 -0
- package/dist/_dts/core/src/csv-date-filter.d.ts +27 -0
- package/dist/_dts/core/src/csv-escape.d.ts +1 -0
- package/dist/_dts/core/src/csv-filename.d.ts +18 -0
- package/dist/_dts/core/src/csv-render.d.ts +4 -0
- package/dist/_dts/core/src/csv-types.d.ts +116 -0
- package/dist/_dts/core/src/currency-format.d.ts +4 -0
- package/dist/_dts/core/src/demo-capability-policy.d.ts +29 -0
- package/dist/_dts/core/src/demo-claim-access.d.ts +14 -0
- package/dist/_dts/core/src/demo-lifecycle-status.d.ts +11 -0
- package/dist/_dts/core/src/demo-runtime.d.ts +47 -0
- package/dist/_dts/core/src/duration.d.ts +14 -0
- package/dist/_dts/core/src/email-format.d.ts +10 -0
- package/dist/_dts/core/src/field-errors.d.ts +1 -0
- package/dist/_dts/core/src/form-submission-preview.d.ts +24 -0
- package/dist/_dts/core/src/index.d.ts +20 -0
- package/dist/_dts/core/src/number-input.d.ts +22 -0
- package/dist/_dts/core/src/public-url-validation.d.ts +12 -0
- package/dist/_dts/core/src/slug.d.ts +39 -0
- package/dist/_dts/core/src/string.d.ts +19 -0
- package/dist/_dts/core/src/uuid.d.ts +6 -0
- package/dist/_dts/db/src/schemas/forms.d.ts +50 -50
- package/dist/_dts/media-core/src/assetsInUseSummary.d.ts +34 -0
- package/dist/_dts/media-core/src/bulkDeletePlanning.d.ts +24 -0
- package/dist/_dts/media-core/src/canonicalCropReview.d.ts +66 -0
- package/dist/_dts/media-core/src/classifyAllPlanning.d.ts +48 -0
- package/dist/_dts/media-core/src/filename.d.ts +1 -0
- package/dist/_dts/media-core/src/index.d.ts +10 -0
- package/dist/_dts/media-core/src/mediaAssetUsageStatus.d.ts +47 -0
- package/dist/_dts/media-core/src/mediaSettingsState.d.ts +3 -0
- package/dist/_dts/media-core/src/portableMediaReferences.d.ts +38 -0
- package/dist/_dts/media-core/src/uploadVerificationContract.d.ts +28 -0
- package/dist/_dts/media-core/src/videoAssetRepair.d.ts +38 -0
- package/dist/_dts/media-editor/src/mediaEditorDebug.d.ts +1 -0
- package/dist/_dts/path-utils/src/index.d.ts +8 -0
- package/dist/_dts/path-utils/src/redirectPaths.d.ts +26 -0
- package/dist/_dts/path-utils/src/safeAppPath.d.ts +26 -0
- package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeButton.d.ts +2 -1
- package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +4 -0
- package/dist/_dts/preview-next/src/client/preview/previewDocumentFrame.d.ts +31 -0
- package/dist/_dts/sdk/src/client/error.d.ts +3 -0
- package/dist/_dts/sdk/src/client/index.d.ts +2 -2
- package/dist/_dts/sdk/src/client/types.d.ts +37 -19
- package/dist/_dts/sdk/src/index.d.ts +2 -2
- package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +16 -16
- package/dist/_dts/sdk/src/next/content-load-failure.d.ts +51 -0
- package/dist/_dts/sdk/src/next/index.d.ts +2 -1
- package/dist/_dts/sdk/src/next/types.d.ts +19 -0
- package/dist/_dts/sdk/src/portal/redirects.d.ts +1 -1
- package/dist/_dts/sdk/src/routing/index.d.ts +3 -2
- package/dist/_dts/sdk/src/routing/resolvePageContent.d.ts +71 -6
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/site-commands/src/commands.d.ts +12 -12
- package/dist/_dts/site-commands/src/index.d.ts +1 -0
- package/dist/_dts/site-commands/src/pagePaths.d.ts +6 -0
- package/dist/_dts/theme-core/src/accordions/siteStyleDefaults.d.ts +26 -0
- package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -0
- package/dist/_dts/theme-core/src/blocks/vars/index.d.ts +1 -0
- package/dist/_dts/theme-core/src/fonts/index.d.ts +1 -0
- package/dist/_dts/theme-core/src/fonts/uploadFormat.d.ts +44 -0
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/index.d.ts +3 -1
- package/dist/_dts/theme-core/src/mock-themes/all.d.ts +36 -24
- package/dist/_dts/theme-core/src/navigation/generateNavLinkCSS.d.ts +6 -1
- package/dist/_dts/theme-core/src/navigation/types.d.ts +12 -0
- package/dist/_dts/theme-core/src/palette/variants/types.d.ts +3 -3
- package/dist/_dts/theme-core/src/runtime/themeCssVarNames.d.ts +7 -0
- package/dist/_dts/theme-core/src/schema.d.ts +64 -18
- package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +214 -34
- package/dist/_dts/theme-core/src/site-styles/appearancePresetTypes.d.ts +5 -2
- package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +214 -34
- package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +24 -0
- package/dist/_dts/theme-core/src/site-styles/designState.d.ts +31 -3
- package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +4 -4
- package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +33 -1
- package/dist/_dts/theme-core/src/site-styles/rawStyleFields.d.ts +4 -2
- package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +9 -1
- package/dist/_dts/theme-core/src/site-styles/types.d.ts +27 -2
- package/dist/_dts/theme-core/src/siteChrome.d.ts +17 -34
- package/dist/_dts/theme-core/src/siteChromeOverlayClearance.d.ts +22 -0
- package/dist/_dts/theme-core/src/siteChromePlacement.d.ts +22 -0
- package/dist/_dts/theme-core/src/siteChromePlanning.d.ts +32 -0
- package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +2 -2
- package/dist/{chunk-2SPENC5M.mjs → chunk-F7RTCZYN.mjs} +229 -50
- package/dist/{chunk-IENWFSLO.mjs → chunk-NIDXI46P.mjs} +1 -1
- package/dist/{chunk-KWJPDZH2.mjs → chunk-OECWLDHN.mjs} +2770 -620
- package/dist/{chunk-VX7B5VAC.mjs → chunk-SVMMM2NA.mjs} +8 -0
- package/dist/{chunk-6SMUFTXD.mjs → chunk-SXOLGNMX.mjs} +1 -1
- package/dist/{chunk-ZYEJLCTN.mjs → chunk-TXDES5P2.mjs} +2 -2
- package/dist/cli/index.mjs +1677 -440
- package/dist/client/{accordion-RZMQSYLR.mjs → accordion-EVDEOUPR.mjs} +2 -2
- package/dist/client/{bookingForm-NF4ASVNV.mjs → bookingForm-DIHBLC64.mjs} +27 -30
- package/dist/client/bookings.mjs +3707 -259
- package/dist/client/{carousel-LDX47ZIK.mjs → carousel-FEBQHIWI.mjs} +3 -4
- package/dist/client/{cart-RGXDS5F4.mjs → cart-7CKSXAE4.mjs} +8 -8
- package/dist/client/{checkout-P7WWSNNY.mjs → checkout-WKYCANLV.mjs} +8 -8
- package/dist/client/{chunk-JNC7CGHX.mjs → chunk-2SAVKN2M.mjs} +2 -2
- package/dist/client/{chunk-TQ5MSPDX.mjs → chunk-36WJCERQ.mjs} +1 -1
- package/dist/client/{chunk-R56FQ3RR.mjs → chunk-65F47D7Y.mjs} +280 -71
- package/dist/client/{chunk-L3DNHIJX.mjs → chunk-GUK2FPXQ.mjs} +23 -45
- package/dist/client/{chunk-PMAIXMAB.mjs → chunk-IVNCUVAV.mjs} +26 -21
- package/dist/client/{chunk-II7O4XN3.mjs → chunk-OFMSCGNY.mjs} +2 -2
- package/dist/client/chunk-PD6NBCEY.mjs +66 -0
- package/dist/client/{chunk-GMVTOKYG.mjs → chunk-RV6FX7UH.mjs} +510 -64
- package/dist/client/{chunk-E2TDNXCL.mjs → chunk-RZDWX7QW.mjs} +2 -1
- package/dist/client/{chunk-M3L3KYYR.mjs → chunk-UDNSI5PY.mjs} +12 -0
- package/dist/client/{chunk-JEZECJ3W.mjs → chunk-VPPMNXCF.mjs} +129 -3
- package/dist/client/{chunk-UFSWADAO.mjs → chunk-YDSEG6GZ.mjs} +5 -66
- package/dist/client/client.mjs +7070 -4561
- package/dist/client/{courseRegistration-7F65K5ZR.mjs → courseRegistration-5QF2PHKM.mjs} +14 -11
- package/dist/client/{eventCalendar-GLSC5KTL.mjs → eventCalendar-4ZOSETDU.mjs} +9 -9
- package/dist/client/{eventCombined-ZHK4WKUR.mjs → eventCombined-WQGU7JUX.mjs} +9 -9
- package/dist/client/{eventDetails-E3PJYBIN.mjs → eventDetails-AYWVUJ5Y.mjs} +9 -9
- package/dist/client/{eventListing-EMS3WC3E.mjs → eventListing-NT7C6UT5.mjs} +9 -9
- package/dist/client/{eventRegistration-NZOTVNPI.mjs → eventRegistration-OH24F4ZJ.mjs} +9 -9
- package/dist/client/{form-ETFZFATW.mjs → form-7L42SRBB.mjs} +6 -6
- package/dist/client/{headerSection-4LBP7ULT.mjs → headerSection-OZRZNZ52.mjs} +3 -3
- package/dist/client/hooks.mjs +1040 -278
- package/dist/client/{locationMap-5M655YSJ.mjs → locationMap-ZBXRPQ7C.mjs} +2 -2
- package/dist/client/{newsletterForm-QOUYW44O.mjs → newsletterForm-SNAGFF2I.mjs} +3 -3
- package/dist/client/{productDetail-O4DOCWQG.mjs → productDetail-I46BOFGV.mjs} +8 -8
- package/dist/client/{productList-A5RO5WIS.mjs → productList-BOYHTYI6.mjs} +8 -8
- package/dist/client/rendering/client.mjs +7090 -2645
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +6089 -3792
- package/dist/client/{shop-L4MZH4I2.mjs → shop-XTXPZTKR.mjs} +8 -8
- package/dist/preview-next/before-render.mjs +8 -0
- package/dist/preview-next/client/runtime.mjs +5 -5
- package/dist/preview-next/editor-chrome.css +10 -0
- package/dist/preview-next/middleware.mjs +8 -0
- package/dist/{sdk-runtime-6UT2S7KZ.mjs → sdk-runtime-ZJLKC6DR.mjs} +6 -6
- package/dist/server/components.mjs +2635 -1262
- package/dist/server/config-validation.mjs +1271 -509
- package/dist/server/config.mjs +1271 -509
- package/dist/server/data.mjs +1040 -278
- package/dist/server/index.mjs +488 -246
- package/dist/server/next.mjs +4087 -2147
- package/dist/server/page-converter.mjs +571 -115
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +2636 -1263
- package/dist/server/rendering.mjs +2654 -1268
- package/dist/server/routing.mjs +1729 -489
- package/dist/server/server.mjs +1532 -530
- package/dist/server/theme-bridge.mjs +3151 -131
- package/dist/server/theme.mjs +10 -1
- package/dist/styles/index.css +488 -48
- package/package.json +2 -1
- package/dist/SdkPreviewModeRuntime-KLPX47SE.mjs +0 -8
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/DiscountCodeSection.d.ts +0 -7
- package/dist/_dts/preview-next/src/client/widgets/PreviewMediaField.d.ts +0 -4
- package/dist/client/chunk-OJPZEZU2.mjs +0 -31
- package/dist/client/chunk-RTZ3JKKX.mjs +0 -178
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { addPassToCommerceCart, useCommerceCart } from './chunk-
|
|
3
|
-
import { CarouselNodeClient } from './chunk-
|
|
2
|
+
import { addPassToCommerceCart, useCommerceCart } from './chunk-RZDWX7QW.mjs';
|
|
3
|
+
import { CarouselNodeClient } from './chunk-OFMSCGNY.mjs';
|
|
4
4
|
import { isRecord } from './chunk-I2MMZO53.mjs';
|
|
5
|
-
import {
|
|
5
|
+
import { useDiscountCodeUi } from './chunk-PD6NBCEY.mjs';
|
|
6
|
+
import { createBodyThemePortalRoot, consumeSearchParams, scrollToBlock, TerminalPanel, StateIcon, CheckIcon, CrossIcon, ActionRow, DiscountCodeDisclosure, consumeSearchParam, buildCheckoutReturnUrls } from './chunk-VPPMNXCF.mjs';
|
|
6
7
|
import { ModalShell, resolveDedicatedCheckoutPath } from './chunk-3PEDD5KJ.mjs';
|
|
7
|
-
import { useBlockApi, FeedbackMessage, BlockApiProvider } from './chunk-
|
|
8
|
+
import { useBlockApi, FeedbackMessage, BlockApiProvider } from './chunk-UDNSI5PY.mjs';
|
|
8
9
|
import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
|
|
9
|
-
import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay,
|
|
10
|
-
import { getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-
|
|
10
|
+
import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, deriveCommerceCheckoutState, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay, assertNever11, reportWorkflowError, clearWorkflowFeedback } from './chunk-65F47D7Y.mjs';
|
|
11
|
+
import { assertNever, ok, err, getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-IVNCUVAV.mjs';
|
|
11
12
|
import * as React3 from 'react';
|
|
12
13
|
import React3__default, { useState, useRef, useCallback, useEffect } from 'react';
|
|
13
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -488,7 +489,8 @@ function ShopAddFeedback(props) {
|
|
|
488
489
|
var initialShopCheckoutState = {
|
|
489
490
|
form: {
|
|
490
491
|
name: "",
|
|
491
|
-
email: ""
|
|
492
|
+
email: "",
|
|
493
|
+
discountCode: ""
|
|
492
494
|
},
|
|
493
495
|
submission: "idle",
|
|
494
496
|
feedback: { tag: "idle" },
|
|
@@ -498,24 +500,21 @@ function shopCheckoutReducer(state, action) {
|
|
|
498
500
|
switch (action.type) {
|
|
499
501
|
case "setField":
|
|
500
502
|
return {
|
|
501
|
-
...state,
|
|
503
|
+
...clearWorkflowFeedback(state),
|
|
502
504
|
form: {
|
|
503
505
|
...state.form,
|
|
504
506
|
[action.field]: action.value
|
|
505
|
-
}
|
|
506
|
-
feedback: { tag: "idle" }
|
|
507
|
+
}
|
|
507
508
|
};
|
|
508
509
|
case "submitStarted":
|
|
509
510
|
return {
|
|
510
|
-
...state,
|
|
511
|
-
submission: "submitting"
|
|
512
|
-
feedback: { tag: "idle" }
|
|
511
|
+
...clearWorkflowFeedback(state),
|
|
512
|
+
submission: "submitting"
|
|
513
513
|
};
|
|
514
514
|
case "submitFailed":
|
|
515
515
|
return {
|
|
516
|
-
...state,
|
|
517
|
-
submission: "idle"
|
|
518
|
-
feedback: { tag: "error", message: action.message }
|
|
516
|
+
...reportWorkflowError(state, action.message),
|
|
517
|
+
submission: "idle"
|
|
519
518
|
};
|
|
520
519
|
case "submitCompleted":
|
|
521
520
|
return {
|
|
@@ -528,9 +527,338 @@ function shopCheckoutReducer(state, action) {
|
|
|
528
527
|
notice: action.notice
|
|
529
528
|
};
|
|
530
529
|
default:
|
|
531
|
-
return
|
|
530
|
+
return assertNever11(action);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// ../blocks/src/system/runtime/nodes/shop-checkout-form.ts
|
|
535
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
536
|
+
function normalizeManualDiscountCode(raw) {
|
|
537
|
+
const trimmed = raw.trim();
|
|
538
|
+
return trimmed ? trimmed : null;
|
|
539
|
+
}
|
|
540
|
+
function normalizeCheckoutEmail(raw) {
|
|
541
|
+
const email = raw.trim().toLowerCase();
|
|
542
|
+
if (!email) {
|
|
543
|
+
return err({
|
|
544
|
+
type: "missing_contact",
|
|
545
|
+
message: "Please enter your email"
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
if (!EMAIL_PATTERN.test(email)) {
|
|
549
|
+
return err({
|
|
550
|
+
type: "invalid_email",
|
|
551
|
+
message: "Please enter a valid email address"
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
return ok(email);
|
|
555
|
+
}
|
|
556
|
+
function normalizeCheckoutContactForm(form) {
|
|
557
|
+
const emailValue = form.email.trim().toLowerCase();
|
|
558
|
+
const name = form.name.trim();
|
|
559
|
+
if (!emailValue || !name) {
|
|
560
|
+
return err({
|
|
561
|
+
type: "missing_contact",
|
|
562
|
+
message: "Please enter your email and name"
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
const email = normalizeCheckoutEmail(emailValue);
|
|
566
|
+
if (!email.ok) return email;
|
|
567
|
+
return ok({ email: email.value, name });
|
|
568
|
+
}
|
|
569
|
+
function planDirectShopCheckoutRequest(input) {
|
|
570
|
+
const contact = normalizeCheckoutContactForm(input.form);
|
|
571
|
+
if (!contact.ok) return contact;
|
|
572
|
+
const discountCode = normalizeManualDiscountCode(input.form.discountCode);
|
|
573
|
+
return ok({
|
|
574
|
+
productType: input.productType,
|
|
575
|
+
productId: input.productId,
|
|
576
|
+
customerEmail: contact.value.email,
|
|
577
|
+
customerName: contact.value.name,
|
|
578
|
+
...discountCode ? { discountCode } : {},
|
|
579
|
+
successUrl: input.successUrl,
|
|
580
|
+
cancelUrl: input.cancelUrl,
|
|
581
|
+
...input.confirmDuplicate ? { confirmDuplicate: true } : {}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
function buildUnifiedCheckoutItems(checkout) {
|
|
585
|
+
return checkout.items.map(
|
|
586
|
+
(item) => item.kind === "product" ? {
|
|
587
|
+
type: "product",
|
|
588
|
+
productId: item.productId,
|
|
589
|
+
...item.variantId ? { variantId: item.variantId } : {},
|
|
590
|
+
quantity: item.quantity
|
|
591
|
+
} : {
|
|
592
|
+
type: "pass",
|
|
593
|
+
passId: item.passId
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
function planUnifiedCheckoutRequest(input) {
|
|
598
|
+
if (input.checkout.kind === "empty") {
|
|
599
|
+
return err({
|
|
600
|
+
type: "empty_cart",
|
|
601
|
+
message: "Your cart is empty"
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
if (input.checkout.kind === "blocked") {
|
|
605
|
+
return err({
|
|
606
|
+
type: "blocked_cart",
|
|
607
|
+
reason: input.checkout.reason,
|
|
608
|
+
message: "Your cart contains items with different currencies"
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
const contact = normalizeCheckoutContactForm(input.form);
|
|
612
|
+
if (!contact.ok) return contact;
|
|
613
|
+
const discountCode = normalizeManualDiscountCode(input.form.discountCode);
|
|
614
|
+
return ok({
|
|
615
|
+
mode: "one_time",
|
|
616
|
+
items: buildUnifiedCheckoutItems(input.checkout),
|
|
617
|
+
customer: contact.value,
|
|
618
|
+
...discountCode ? { discountCode } : {},
|
|
619
|
+
successUrl: input.successUrl,
|
|
620
|
+
cancelUrl: input.cancelUrl
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
function planCartDiscountAvailabilityRequests(checkout) {
|
|
624
|
+
if (checkout.kind === "empty") {
|
|
625
|
+
return err({
|
|
626
|
+
type: "empty_cart",
|
|
627
|
+
message: "Your cart is empty"
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
if (checkout.kind === "blocked") {
|
|
631
|
+
return err({
|
|
632
|
+
type: "blocked_cart",
|
|
633
|
+
reason: checkout.reason,
|
|
634
|
+
message: "Your cart contains items with different currencies"
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
return ok(checkout.items.map((item) => {
|
|
638
|
+
const subtotalCents = Math.max(0, item.unitPriceCents * item.quantity);
|
|
639
|
+
if (item.kind === "product") {
|
|
640
|
+
return {
|
|
641
|
+
context: {
|
|
642
|
+
type: "product",
|
|
643
|
+
productId: item.productId,
|
|
644
|
+
productCategoryId: item.productCategoryId
|
|
645
|
+
},
|
|
646
|
+
subtotalCents,
|
|
647
|
+
currency: item.currency
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
context: {
|
|
652
|
+
type: "pass",
|
|
653
|
+
passId: item.passId
|
|
654
|
+
},
|
|
655
|
+
subtotalCents,
|
|
656
|
+
currency: item.currency
|
|
657
|
+
};
|
|
658
|
+
}));
|
|
659
|
+
}
|
|
660
|
+
function aggregateCartDiscountUiState(availability) {
|
|
661
|
+
if (!availability.some((item) => item.hasDiscounts)) {
|
|
662
|
+
return { type: "unavailable" };
|
|
663
|
+
}
|
|
664
|
+
if (availability.some((item) => item.manualCodeEntryAllowed)) {
|
|
665
|
+
return { type: "manual-allowed" };
|
|
666
|
+
}
|
|
667
|
+
const autoAppliedDiscount = availability.find(
|
|
668
|
+
(item) => item.autoAppliedDiscount
|
|
669
|
+
)?.autoAppliedDiscount ?? null;
|
|
670
|
+
return {
|
|
671
|
+
type: "auto-only",
|
|
672
|
+
autoAppliedDiscount
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function checkoutFormForDiscountUiState(form, discountUiState) {
|
|
676
|
+
if (discountUiState.type === "manual-allowed") return form;
|
|
677
|
+
return {
|
|
678
|
+
...form,
|
|
679
|
+
discountCode: ""
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
var CART_DISCOUNT_UNAVAILABLE = { type: "unavailable" };
|
|
683
|
+
function useCartDiscountUiState(api, plan) {
|
|
684
|
+
const [discountUiState, setDiscountUiState] = useState(
|
|
685
|
+
CART_DISCOUNT_UNAVAILABLE
|
|
686
|
+
);
|
|
687
|
+
useEffect(() => {
|
|
688
|
+
let cancelled = false;
|
|
689
|
+
async function loadCartDiscountAvailability() {
|
|
690
|
+
if (!plan.ok || plan.value.length === 0) {
|
|
691
|
+
setDiscountUiState(CART_DISCOUNT_UNAVAILABLE);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
setDiscountUiState({ type: "loading" });
|
|
695
|
+
try {
|
|
696
|
+
const availability = await Promise.all(
|
|
697
|
+
plan.value.map((request) => api.getDiscountsAvailable(request))
|
|
698
|
+
);
|
|
699
|
+
if (cancelled) return;
|
|
700
|
+
setDiscountUiState(aggregateCartDiscountUiState(availability));
|
|
701
|
+
} catch {
|
|
702
|
+
if (!cancelled) {
|
|
703
|
+
setDiscountUiState({ type: "error-unavailable" });
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
loadCartDiscountAvailability();
|
|
708
|
+
return () => {
|
|
709
|
+
cancelled = true;
|
|
710
|
+
};
|
|
711
|
+
}, [api, plan]);
|
|
712
|
+
return discountUiState;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// ../blocks/src/system/runtime/nodes/shop-discount-apply.state.ts
|
|
716
|
+
var initialDiscountApplyState = {
|
|
717
|
+
isOpen: false,
|
|
718
|
+
draftCode: "",
|
|
719
|
+
status: { type: "idle" }
|
|
720
|
+
};
|
|
721
|
+
function discountApplyReducer(state, action) {
|
|
722
|
+
switch (action.type) {
|
|
723
|
+
case "open":
|
|
724
|
+
return {
|
|
725
|
+
...state,
|
|
726
|
+
isOpen: true
|
|
727
|
+
};
|
|
728
|
+
case "draftChanged":
|
|
729
|
+
return {
|
|
730
|
+
...state,
|
|
731
|
+
draftCode: action.draftCode,
|
|
732
|
+
status: { type: "idle" }
|
|
733
|
+
};
|
|
734
|
+
case "remove":
|
|
735
|
+
return initialDiscountApplyState;
|
|
736
|
+
case "applyStarted":
|
|
737
|
+
return {
|
|
738
|
+
...state,
|
|
739
|
+
status: { type: "applying" }
|
|
740
|
+
};
|
|
741
|
+
case "applySucceeded":
|
|
742
|
+
return {
|
|
743
|
+
...state,
|
|
744
|
+
isOpen: true,
|
|
745
|
+
draftCode: action.discount.code,
|
|
746
|
+
status: {
|
|
747
|
+
type: "applied",
|
|
748
|
+
discount: action.discount
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
case "applyRejected":
|
|
752
|
+
return {
|
|
753
|
+
...state,
|
|
754
|
+
isOpen: true,
|
|
755
|
+
status: {
|
|
756
|
+
type: "rejected",
|
|
757
|
+
reason: action.reason,
|
|
758
|
+
message: action.message
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
case "resetApplied":
|
|
762
|
+
if (state.status.type !== "applied") return state;
|
|
763
|
+
return {
|
|
764
|
+
...state,
|
|
765
|
+
status: { type: "idle" }
|
|
766
|
+
};
|
|
767
|
+
default:
|
|
768
|
+
return assertNever11(action);
|
|
532
769
|
}
|
|
533
770
|
}
|
|
771
|
+
function getAppliedDiscountCode(state) {
|
|
772
|
+
if (state.status.type !== "applied") return null;
|
|
773
|
+
return normalizeManualDiscountCode(state.status.discount.code);
|
|
774
|
+
}
|
|
775
|
+
function isDiscountApplyInFlight(state) {
|
|
776
|
+
return state.status.type === "applying";
|
|
777
|
+
}
|
|
778
|
+
function getDiscountApplyFeedback(status, formatPrice) {
|
|
779
|
+
switch (status.type) {
|
|
780
|
+
case "idle":
|
|
781
|
+
case "applying":
|
|
782
|
+
return null;
|
|
783
|
+
case "applied": {
|
|
784
|
+
const savings = formatPrice(
|
|
785
|
+
status.discount.discountCents,
|
|
786
|
+
status.discount.currency
|
|
787
|
+
);
|
|
788
|
+
return {
|
|
789
|
+
tone: "success",
|
|
790
|
+
message: `${status.discount.publicLabel} applied. You save ${savings}.`
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
case "rejected":
|
|
794
|
+
return {
|
|
795
|
+
tone: "error",
|
|
796
|
+
message: status.message
|
|
797
|
+
};
|
|
798
|
+
default:
|
|
799
|
+
return assertNever11(status);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
var DISCOUNT_APPLY_MESSAGES = {
|
|
803
|
+
emptyCode: "Enter a discount code first.",
|
|
804
|
+
emailRequired: "Enter your email before applying a code.",
|
|
805
|
+
unavailable: "That code doesn't work for this checkout.",
|
|
806
|
+
unknown: "We couldn't check that code. Try again."
|
|
807
|
+
};
|
|
808
|
+
function useDiscountApply(options) {
|
|
809
|
+
return useCallback(async () => {
|
|
810
|
+
const discountCode = normalizeManualDiscountCode(options.state.draftCode);
|
|
811
|
+
if (!discountCode) {
|
|
812
|
+
options.dispatch({
|
|
813
|
+
type: "applyRejected",
|
|
814
|
+
reason: "empty_code",
|
|
815
|
+
message: DISCOUNT_APPLY_MESSAGES.emptyCode
|
|
816
|
+
});
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const email = normalizeCheckoutEmail(options.getCustomerEmail());
|
|
820
|
+
if (!email.ok) {
|
|
821
|
+
options.dispatch({
|
|
822
|
+
type: "applyRejected",
|
|
823
|
+
reason: "email_required",
|
|
824
|
+
message: DISCOUNT_APPLY_MESSAGES.emailRequired
|
|
825
|
+
});
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
const linesPlan = options.getLines();
|
|
829
|
+
if (!linesPlan.ok || linesPlan.lines.length === 0) {
|
|
830
|
+
options.dispatch({
|
|
831
|
+
type: "applyRejected",
|
|
832
|
+
reason: "unavailable",
|
|
833
|
+
message: DISCOUNT_APPLY_MESSAGES.unavailable
|
|
834
|
+
});
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
options.dispatch({ type: "applyStarted" });
|
|
838
|
+
try {
|
|
839
|
+
const result = await options.api.applyDiscountCode({
|
|
840
|
+
discountCode,
|
|
841
|
+
customerEmail: email.value,
|
|
842
|
+
lines: linesPlan.lines
|
|
843
|
+
});
|
|
844
|
+
if (result.type === "applied") {
|
|
845
|
+
options.dispatch({ type: "applySucceeded", discount: result });
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
options.dispatch({
|
|
849
|
+
type: "applyRejected",
|
|
850
|
+
reason: result.reason,
|
|
851
|
+
message: result.message
|
|
852
|
+
});
|
|
853
|
+
} catch {
|
|
854
|
+
options.dispatch({
|
|
855
|
+
type: "applyRejected",
|
|
856
|
+
reason: "unknown",
|
|
857
|
+
message: DISCOUNT_APPLY_MESSAGES.unknown
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
}, [options]);
|
|
861
|
+
}
|
|
534
862
|
var CHECKOUT_ANCHOR_ID = "shop-checkout";
|
|
535
863
|
function ProductListController(props) {
|
|
536
864
|
const api = useBlockApi();
|
|
@@ -764,6 +1092,10 @@ function CheckoutController(props) {
|
|
|
764
1092
|
shopCheckoutReducer,
|
|
765
1093
|
initialShopCheckoutState
|
|
766
1094
|
);
|
|
1095
|
+
const [discountApply, dispatchDiscountApply] = React3.useReducer(
|
|
1096
|
+
discountApplyReducer,
|
|
1097
|
+
initialDiscountApplyState
|
|
1098
|
+
);
|
|
767
1099
|
React3.useEffect(() => {
|
|
768
1100
|
const checkout = consumeSearchParam("checkout");
|
|
769
1101
|
if (checkout === "success") {
|
|
@@ -777,33 +1109,57 @@ function CheckoutController(props) {
|
|
|
777
1109
|
() => getShopDisplayForItems(props.render, cart.items),
|
|
778
1110
|
[cart.items, props.render]
|
|
779
1111
|
);
|
|
1112
|
+
const checkoutState = React3.useMemo(
|
|
1113
|
+
() => deriveCommerceCheckoutState({ items: cart.items }),
|
|
1114
|
+
[cart.items]
|
|
1115
|
+
);
|
|
1116
|
+
const discountAvailabilityPlan = React3.useMemo(
|
|
1117
|
+
() => planCartDiscountAvailabilityRequests(checkoutState),
|
|
1118
|
+
[checkoutState]
|
|
1119
|
+
);
|
|
1120
|
+
const discountUiState = useCartDiscountUiState(api, discountAvailabilityPlan);
|
|
1121
|
+
const discountApplyFeedback = getDiscountApplyFeedback(
|
|
1122
|
+
discountApply.status,
|
|
1123
|
+
formatCommercePrice
|
|
1124
|
+
);
|
|
1125
|
+
React3.useEffect(() => {
|
|
1126
|
+
if (discountUiState.type === "manual-allowed") return;
|
|
1127
|
+
dispatchDiscountApply({ type: "remove" });
|
|
1128
|
+
}, [discountUiState.type]);
|
|
1129
|
+
const checkoutIdentity = React3.useMemo(() => {
|
|
1130
|
+
if (checkoutState.kind !== "ready") return checkoutState.kind;
|
|
1131
|
+
return checkoutState.items.map((item) => `${item.key}:${item.quantity}:${item.unitPriceCents}`).join("|");
|
|
1132
|
+
}, [checkoutState]);
|
|
1133
|
+
React3.useEffect(() => {
|
|
1134
|
+
dispatchDiscountApply({ type: "resetApplied" });
|
|
1135
|
+
}, [checkoutIdentity, state.form.email]);
|
|
1136
|
+
const applyDiscountCode = useDiscountApply({
|
|
1137
|
+
api,
|
|
1138
|
+
state: discountApply,
|
|
1139
|
+
dispatch: dispatchDiscountApply,
|
|
1140
|
+
getCustomerEmail: () => state.form.email,
|
|
1141
|
+
getLines: () => discountAvailabilityPlan.ok ? { ok: true, lines: discountAvailabilityPlan.value } : { ok: false }
|
|
1142
|
+
});
|
|
780
1143
|
const handleSubmit = async (event) => {
|
|
781
1144
|
event.preventDefault();
|
|
782
1145
|
if (display.state !== "ready" || state.submission === "submitting") return;
|
|
783
1146
|
dispatch({ type: "submitStarted" });
|
|
784
1147
|
try {
|
|
785
1148
|
const { successUrl, cancelUrl } = buildCheckoutReturnUrls("checkout", CHECKOUT_ANCHOR_ID);
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
} : {
|
|
793
|
-
type: "pass",
|
|
794
|
-
passId: item.passId
|
|
795
|
-
}
|
|
796
|
-
);
|
|
797
|
-
const result = await api.createUnifiedCheckout({
|
|
798
|
-
mode: "one_time",
|
|
799
|
-
items: checkoutItems,
|
|
800
|
-
customer: {
|
|
801
|
-
email: state.form.email.trim().toLowerCase(),
|
|
802
|
-
name: state.form.name.trim()
|
|
803
|
-
},
|
|
1149
|
+
const command = planUnifiedCheckoutRequest({
|
|
1150
|
+
checkout: checkoutState,
|
|
1151
|
+
form: checkoutFormForDiscountUiState({
|
|
1152
|
+
...state.form,
|
|
1153
|
+
discountCode: discountUiState.type === "manual-allowed" ? getAppliedDiscountCode(discountApply) ?? "" : ""
|
|
1154
|
+
}, discountUiState),
|
|
804
1155
|
successUrl,
|
|
805
1156
|
cancelUrl
|
|
806
1157
|
});
|
|
1158
|
+
if (!command.ok) {
|
|
1159
|
+
dispatch({ type: "submitFailed", message: command.error.message });
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
const result = await api.createUnifiedCheckout(command.value);
|
|
807
1163
|
if (result.type === "redirect") {
|
|
808
1164
|
window.location.href = result.checkoutUrl;
|
|
809
1165
|
return;
|
|
@@ -859,6 +1215,25 @@ function CheckoutController(props) {
|
|
|
859
1215
|
}
|
|
860
1216
|
)
|
|
861
1217
|
] }),
|
|
1218
|
+
discountUiState.type === "manual-allowed" ? /* @__PURE__ */ jsx(
|
|
1219
|
+
DiscountCodeDisclosure,
|
|
1220
|
+
{
|
|
1221
|
+
surface: "theme-form",
|
|
1222
|
+
isOpen: discountApply.isOpen,
|
|
1223
|
+
code: discountApply.draftCode,
|
|
1224
|
+
onOpen: () => dispatchDiscountApply({ type: "open" }),
|
|
1225
|
+
onChange: (draftCode) => dispatchDiscountApply({ type: "draftChanged", draftCode }),
|
|
1226
|
+
onRemove: () => dispatchDiscountApply({ type: "remove" }),
|
|
1227
|
+
onApply: applyDiscountCode,
|
|
1228
|
+
id: "shop-checkout-discount-code",
|
|
1229
|
+
hint: "Apply your code before checkout.",
|
|
1230
|
+
feedback: discountApplyFeedback,
|
|
1231
|
+
isApplying: isDiscountApplyInFlight(discountApply),
|
|
1232
|
+
disabled: state.submission === "submitting"
|
|
1233
|
+
}
|
|
1234
|
+
) : null,
|
|
1235
|
+
discountUiState.type === "loading" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "rb-caption status-muted", role: "status", children: "Checking available discounts." }) : null,
|
|
1236
|
+
discountUiState.type === "auto-only" ? /* @__PURE__ */ jsx(FeedbackMessage, { tone: "info", className: "rb-caption status-muted", role: "status", children: discountUiState.autoAppliedDiscount ? `${discountUiState.autoAppliedDiscount.publicLabel} will be applied at checkout.` : "Eligible discounts will be applied at checkout." }) : null,
|
|
862
1237
|
state.feedback.tag === "error" ? /* @__PURE__ */ jsx(
|
|
863
1238
|
FeedbackMessage,
|
|
864
1239
|
{
|
|
@@ -897,7 +1272,8 @@ function ProductListClient(props) {
|
|
|
897
1272
|
// ../blocks/src/system/runtime/nodes/shop.state.ts
|
|
898
1273
|
var EMPTY_FORM = {
|
|
899
1274
|
email: "",
|
|
900
|
-
name: ""
|
|
1275
|
+
name: "",
|
|
1276
|
+
discountCode: ""
|
|
901
1277
|
};
|
|
902
1278
|
var CLOSED_CHECKOUT = { tag: "closed" };
|
|
903
1279
|
var initialShopPassesMembershipsState = {
|
|
@@ -993,7 +1369,7 @@ function shopPassesMembershipsReducer(state, action) {
|
|
|
993
1369
|
returnNotice: null
|
|
994
1370
|
};
|
|
995
1371
|
default:
|
|
996
|
-
return
|
|
1372
|
+
return assertNever11(action);
|
|
997
1373
|
}
|
|
998
1374
|
}
|
|
999
1375
|
function getOpenCheckout(state) {
|
|
@@ -1008,12 +1384,29 @@ function getCheckoutModalTitle(checkout) {
|
|
|
1008
1384
|
if (checkout.item.productType === "membership") return "Subscribe to Membership";
|
|
1009
1385
|
return checkout.item.product.productUseCase === "appointment_package" ? "Purchase Package" : "Purchase Pass";
|
|
1010
1386
|
}
|
|
1387
|
+
function getCheckoutDiscountApplyLine(checkout) {
|
|
1388
|
+
return {
|
|
1389
|
+
context: checkout.item.productType === "pass" ? {
|
|
1390
|
+
type: "pass",
|
|
1391
|
+
passId: checkout.item.product.id
|
|
1392
|
+
} : {
|
|
1393
|
+
type: "membership",
|
|
1394
|
+
membershipId: checkout.item.product.id
|
|
1395
|
+
},
|
|
1396
|
+
subtotalCents: Math.max(0, checkout.item.product.price),
|
|
1397
|
+
currency: checkout.item.product.currency
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1011
1400
|
function PassesMembershipsController({ render }) {
|
|
1012
1401
|
const api = useBlockApi();
|
|
1013
1402
|
const [state, dispatch] = React3__default.useReducer(
|
|
1014
1403
|
shopPassesMembershipsReducer,
|
|
1015
1404
|
initialShopPassesMembershipsState
|
|
1016
1405
|
);
|
|
1406
|
+
const [discountApply, dispatchDiscountApply] = React3__default.useReducer(
|
|
1407
|
+
discountApplyReducer,
|
|
1408
|
+
initialDiscountApplyState
|
|
1409
|
+
);
|
|
1017
1410
|
const passAddFeedback = useTransientShopAddFeedback();
|
|
1018
1411
|
const [modalPortalRoot, setModalPortalRoot] = useState(null);
|
|
1019
1412
|
const shopRootRef = useRef(null);
|
|
@@ -1023,6 +1416,19 @@ function PassesMembershipsController({ render }) {
|
|
|
1023
1416
|
const display = render.display;
|
|
1024
1417
|
const hydration = render.hydration;
|
|
1025
1418
|
const checkoutTitle = getCheckoutModalTitle(checkout);
|
|
1419
|
+
const discountContext = React3__default.useMemo(() => {
|
|
1420
|
+
if (!checkout) return null;
|
|
1421
|
+
return checkout.item.productType === "pass" ? { type: "pass", passId: checkout.item.product.id } : { type: "membership", membershipId: checkout.item.product.id };
|
|
1422
|
+
}, [checkout]);
|
|
1423
|
+
const discountUi = useDiscountCodeUi({
|
|
1424
|
+
api,
|
|
1425
|
+
discountContext,
|
|
1426
|
+
subtotalCents: checkout?.item.product.price
|
|
1427
|
+
});
|
|
1428
|
+
const discountApplyFeedback = getDiscountApplyFeedback(
|
|
1429
|
+
discountApply.status,
|
|
1430
|
+
formatCommercePrice
|
|
1431
|
+
);
|
|
1026
1432
|
const handleBuyPass = useCallback((pass) => {
|
|
1027
1433
|
if (hydration.passPurchaseMode === "add_to_cart") {
|
|
1028
1434
|
addPassToCommerceCart(api.config.siteId, {
|
|
@@ -1053,6 +1459,13 @@ function PassesMembershipsController({ render }) {
|
|
|
1053
1459
|
focusedCheckoutKeyRef.current = checkoutKey;
|
|
1054
1460
|
}
|
|
1055
1461
|
}, [checkout]);
|
|
1462
|
+
useEffect(() => {
|
|
1463
|
+
dispatchDiscountApply({ type: "resetApplied" });
|
|
1464
|
+
}, [checkout?.form.email, checkout?.item.product.id, checkout?.item.productType]);
|
|
1465
|
+
useEffect(() => {
|
|
1466
|
+
if (checkout && discountUi.manualCodeEntryAllowed) return;
|
|
1467
|
+
dispatchDiscountApply({ type: "remove" });
|
|
1468
|
+
}, [checkout, discountUi.manualCodeEntryAllowed]);
|
|
1056
1469
|
useEffect(() => {
|
|
1057
1470
|
const sourceEl = shopRootRef.current;
|
|
1058
1471
|
if (!sourceEl) return;
|
|
@@ -1079,16 +1492,6 @@ function PassesMembershipsController({ render }) {
|
|
|
1079
1492
|
}, []);
|
|
1080
1493
|
const submitCheckout = useCallback(async (confirmDuplicate = false) => {
|
|
1081
1494
|
if (!checkout) return;
|
|
1082
|
-
const email = checkout.form.email.trim().toLowerCase();
|
|
1083
|
-
const name = checkout.form.name.trim();
|
|
1084
|
-
if (!email || !name) {
|
|
1085
|
-
dispatch({ type: "submitFailed", error: "Please enter your email and name" });
|
|
1086
|
-
return;
|
|
1087
|
-
}
|
|
1088
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
1089
|
-
dispatch({ type: "submitFailed", error: "Please enter a valid email address" });
|
|
1090
|
-
return;
|
|
1091
|
-
}
|
|
1092
1495
|
dispatch({ type: "submitStarted" });
|
|
1093
1496
|
try {
|
|
1094
1497
|
const currentUrl = window.location.href;
|
|
@@ -1097,38 +1500,53 @@ function PassesMembershipsController({ render }) {
|
|
|
1097
1500
|
successUrl.searchParams.set("product", checkout.item.product.id);
|
|
1098
1501
|
const cancelUrl = new URL(currentUrl);
|
|
1099
1502
|
cancelUrl.searchParams.set("checkout", "cancelled");
|
|
1100
|
-
const
|
|
1503
|
+
const form = {
|
|
1504
|
+
...checkout.form,
|
|
1505
|
+
discountCode: discountUi.manualCodeEntryAllowed ? getAppliedDiscountCode(discountApply) ?? "" : ""
|
|
1506
|
+
};
|
|
1507
|
+
const command = planDirectShopCheckoutRequest({
|
|
1101
1508
|
productType: checkout.item.productType,
|
|
1102
1509
|
productId: checkout.item.product.id,
|
|
1103
|
-
|
|
1104
|
-
customerName: name,
|
|
1510
|
+
form,
|
|
1105
1511
|
successUrl: successUrl.toString(),
|
|
1106
1512
|
cancelUrl: cancelUrl.toString(),
|
|
1107
1513
|
confirmDuplicate
|
|
1108
1514
|
});
|
|
1109
|
-
if (
|
|
1110
|
-
dispatch({
|
|
1111
|
-
type: "submitDuplicateWarning",
|
|
1112
|
-
warning: result
|
|
1113
|
-
});
|
|
1515
|
+
if (!command.ok) {
|
|
1516
|
+
dispatch({ type: "submitFailed", error: command.error.message });
|
|
1114
1517
|
return;
|
|
1115
1518
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1519
|
+
const result = await api.createShopCheckout(command.value);
|
|
1520
|
+
switch (result.type) {
|
|
1521
|
+
case "duplicate_membership_warning":
|
|
1522
|
+
dispatch({
|
|
1523
|
+
type: "submitDuplicateWarning",
|
|
1524
|
+
warning: result
|
|
1525
|
+
});
|
|
1526
|
+
return;
|
|
1527
|
+
case "bypassed":
|
|
1528
|
+
window.location.href = successUrl.toString();
|
|
1529
|
+
return;
|
|
1530
|
+
case "redirect":
|
|
1531
|
+
window.location.href = result.checkoutUrl;
|
|
1532
|
+
return;
|
|
1533
|
+
default:
|
|
1534
|
+
return assertNever(result);
|
|
1119
1535
|
}
|
|
1120
|
-
if ("checkoutUrl" in result && result.checkoutUrl) {
|
|
1121
|
-
window.location.href = result.checkoutUrl;
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
throw new Error("No checkout URL returned");
|
|
1125
1536
|
} catch (submitError) {
|
|
1126
1537
|
dispatch({
|
|
1127
1538
|
type: "submitFailed",
|
|
1128
1539
|
error: submitError instanceof Error ? submitError.message : "An error occurred"
|
|
1129
1540
|
});
|
|
1130
1541
|
}
|
|
1131
|
-
}, [api, checkout]);
|
|
1542
|
+
}, [api, checkout, discountApply, discountUi.manualCodeEntryAllowed]);
|
|
1543
|
+
const applyDiscountCode = useDiscountApply({
|
|
1544
|
+
api,
|
|
1545
|
+
state: discountApply,
|
|
1546
|
+
dispatch: dispatchDiscountApply,
|
|
1547
|
+
getCustomerEmail: () => checkout?.form.email ?? "",
|
|
1548
|
+
getLines: () => checkout ? { ok: true, lines: [getCheckoutDiscountApplyLine(checkout)] } : { ok: false }
|
|
1549
|
+
});
|
|
1132
1550
|
const handleFormSubmit = useCallback((event) => {
|
|
1133
1551
|
event.preventDefault();
|
|
1134
1552
|
submitCheckout(false);
|
|
@@ -1318,6 +1736,34 @@ function PassesMembershipsController({ render }) {
|
|
|
1318
1736
|
}
|
|
1319
1737
|
)
|
|
1320
1738
|
] }),
|
|
1739
|
+
discountUi.manualCodeEntryAllowed ? /* @__PURE__ */ jsx(
|
|
1740
|
+
DiscountCodeDisclosure,
|
|
1741
|
+
{
|
|
1742
|
+
surface: "theme-form",
|
|
1743
|
+
isOpen: discountApply.isOpen,
|
|
1744
|
+
code: discountApply.draftCode,
|
|
1745
|
+
onOpen: () => dispatchDiscountApply({ type: "open" }),
|
|
1746
|
+
onChange: (draftCode) => dispatchDiscountApply({ type: "draftChanged", draftCode }),
|
|
1747
|
+
onRemove: () => {
|
|
1748
|
+
dispatchDiscountApply({ type: "remove" });
|
|
1749
|
+
},
|
|
1750
|
+
onApply: applyDiscountCode,
|
|
1751
|
+
id: "shop-discount-code",
|
|
1752
|
+
hint: "Apply your code before checkout.",
|
|
1753
|
+
feedback: discountApplyFeedback,
|
|
1754
|
+
isApplying: isDiscountApplyInFlight(discountApply),
|
|
1755
|
+
disabled: checkout.submitting
|
|
1756
|
+
}
|
|
1757
|
+
) : null,
|
|
1758
|
+
!discountUi.discountsAvailableLoading && discountUi.discountsAvailable && !discountUi.manualCodeEntryAllowed ? /* @__PURE__ */ jsx(
|
|
1759
|
+
FeedbackMessage,
|
|
1760
|
+
{
|
|
1761
|
+
tone: "info",
|
|
1762
|
+
className: "shop__modal-discount",
|
|
1763
|
+
role: "status",
|
|
1764
|
+
children: "Eligible discounts will be applied at checkout."
|
|
1765
|
+
}
|
|
1766
|
+
) : null,
|
|
1321
1767
|
checkout.formError ? /* @__PURE__ */ jsx(
|
|
1322
1768
|
FeedbackMessage,
|
|
1323
1769
|
{
|