@riverbankcms/sdk 0.90.1 → 0.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{PreviewEditorSidebar-FNFRVSIM.mjs → PreviewEditorSidebar-3TT47WCF.mjs} +3 -3
- package/dist/{PreviewEditorUI-3WXJFQXG.mjs → PreviewEditorUI-ORCLLUNZ.mjs} +3 -3
- package/dist/SdkPreviewModeRuntime-GMCDQPZZ.mjs +8 -0
- package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +17 -0
- package/dist/_dts/core/src/string.d.ts +12 -0
- package/dist/_dts/sdk/src/cli/sync/validation.d.ts +2 -2
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/{chunk-SYYJZPKU.mjs → chunk-AFPMCLS7.mjs} +2 -2
- package/dist/{chunk-H6TT5ZXI.mjs → chunk-GDT2QGIL.mjs} +1 -1
- package/dist/{chunk-CR2VX432.mjs → chunk-RQUZYSES.mjs} +48 -36
- package/dist/{chunk-FA6LVZ7C.mjs → chunk-S3YHJWEU.mjs} +7 -7
- package/dist/{chunk-UG7I7S7W.mjs → chunk-U5YM4AWE.mjs} +1 -1
- package/dist/{chunk-BOQXMCSP.mjs → chunk-ZA2S7H34.mjs} +3 -3
- package/dist/cli/index.mjs +204 -335
- package/dist/cli/init-docs/content/workflow-add-block.md +48 -0
- package/dist/cli/init-docs/content/workflow-custom-block.md +10 -0
- package/dist/client/{accordion-4K7VGZ3I.mjs → accordion-AFX37652.mjs} +2 -2
- package/dist/client/{bookingForm-3QXA3CIS.mjs → bookingForm-32V5QCOW.mjs} +6 -6
- package/dist/client/bookings.mjs +16 -15
- package/dist/client/{carousel-BEJKNGQ7.mjs → carousel-TJGQJ7ER.mjs} +3 -3
- package/dist/client/{cart-44BBM6XG.mjs → cart-JUU2JEW4.mjs} +6 -6
- package/dist/client/{checkout-THMHEYKF.mjs → checkout-RD6BTFX4.mjs} +6 -6
- package/dist/client/{chunk-JV7ZNAOU.mjs → chunk-6QZIBNGV.mjs} +8 -8
- package/dist/client/{chunk-DQIRKNZE.mjs → chunk-6RN62XBV.mjs} +1 -1
- package/dist/client/{chunk-ZIAF2DA4.mjs → chunk-C4LP6BPG.mjs} +1 -1
- package/dist/client/{chunk-SLY6UDAS.mjs → chunk-CKXEUWWA.mjs} +2 -2
- package/dist/client/{chunk-5AJIMWKS.mjs → chunk-E6VIWZUG.mjs} +3 -3
- package/dist/client/{chunk-PEDNDLPB.mjs → chunk-FMZZHAIR.mjs} +2 -2
- package/dist/client/{chunk-KNTLBQ3N.mjs → chunk-ISAUXU5R.mjs} +1 -1
- package/dist/client/{chunk-HIHOQGIP.mjs → chunk-LJCX6V7Q.mjs} +9 -9
- package/dist/client/{chunk-B4H6QMPY.mjs → chunk-MLBNVN4H.mjs} +7 -5
- package/dist/client/{chunk-EJBHK74Y.mjs → chunk-PMNAV6LO.mjs} +1 -1
- package/dist/client/{chunk-4COPESPO.mjs → chunk-RMOFBBNA.mjs} +5 -5
- package/dist/client/{chunk-3H5CLFKT.mjs → chunk-RWYFG625.mjs} +9 -8
- package/dist/client/client.mjs +34 -31
- package/dist/client/{courseRegistration-URX7RCCK.mjs → courseRegistration-X63QAIVV.mjs} +6 -6
- package/dist/client/{eventCalendar-GTENOQCE.mjs → eventCalendar-5T24GCZL.mjs} +9 -9
- package/dist/client/{eventCombined-EZVB72MF.mjs → eventCombined-AZVTF22X.mjs} +9 -9
- package/dist/client/{eventDetails-CH4BJR5Z.mjs → eventDetails-7GPFNLGF.mjs} +9 -9
- package/dist/client/{eventListing-4BVOI5HS.mjs → eventListing-QEUMTMUM.mjs} +9 -9
- package/dist/client/{eventRegistration-37LPIKIE.mjs → eventRegistration-P2EDKCQZ.mjs} +9 -9
- package/dist/client/{form-FX3Y54YK.mjs → form-NUJ7H4IN.mjs} +3 -3
- package/dist/client/{headerSection-UOZZGVYL.mjs → headerSection-JB7LECPL.mjs} +3 -3
- package/dist/client/hooks.mjs +7 -7
- package/dist/client/{locationMap-VSIPKV35.mjs → locationMap-UEYWUCSW.mjs} +3 -3
- package/dist/client/{newsletterForm-6FRJKNAF.mjs → newsletterForm-S2YZQ2X7.mjs} +3 -3
- package/dist/client/{productDetail-6AHMLXCO.mjs → productDetail-H5MADGG7.mjs} +6 -6
- package/dist/client/{productList-M2CYIZVH.mjs → productList-DK7YON7H.mjs} +6 -6
- package/dist/client/rendering/client.mjs +31 -28
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +33 -30
- package/dist/client/{shop-AUOT6GEX.mjs → shop-6PA7RDRJ.mjs} +6 -6
- package/dist/client/spam-protection.mjs +10 -10
- package/dist/preview-next/client/runtime.mjs +5 -5
- package/dist/{sdk-runtime-6GPJNLU6.mjs → sdk-runtime-JP5347OB.mjs} +6 -6
- package/dist/server/components.mjs +13 -11
- package/dist/server/config-validation.mjs +7 -7
- package/dist/server/config.mjs +7 -7
- package/dist/server/data.mjs +7 -7
- package/dist/server/index.mjs +1 -1
- package/dist/server/navigation.mjs +2 -2
- package/dist/server/next.mjs +14 -12
- package/dist/server/page-converter.mjs +5 -5
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +13 -11
- package/dist/server/rendering.mjs +13 -11
- package/dist/server/routing.mjs +14 -14
- package/dist/server/server.mjs +8 -8
- package/package.json +1 -1
- package/dist/SdkPreviewModeRuntime-2UCIMKUB.mjs +0 -8
|
@@ -49,6 +49,16 @@ riverbankcms block list home
|
|
|
49
49
|
riverbankcms block upsert <page-id> <block-id> --kind <block-kind> --data '<json>'
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
### Authoring Block JSON
|
|
53
|
+
|
|
54
|
+
Use `block-types.md` and `block-types-site.md` as the source of truth for fields.
|
|
55
|
+
|
|
56
|
+
- Fields marked `required` must be present with a valid value.
|
|
57
|
+
- Fields not marked `required` may be omitted. You do not need to include every optional key or set unused optional values to `null`.
|
|
58
|
+
- Defaults shown in the block reference are applied by the editor/rendering contract. Include an optional field only when you want to override that default.
|
|
59
|
+
- For nested objects and repeaters, required child fields apply once you include the parent value. For example, an omitted `images` repeater is valid, but `images: [{}]` is not because the item is present and its required `image` field is missing.
|
|
60
|
+
- `null` is only valid for field types that explicitly accept clearing to no value. When in doubt, omit optional fields instead of sending `null`.
|
|
61
|
+
|
|
52
62
|
**Examples:**
|
|
53
63
|
|
|
54
64
|
Add a hero block:
|
|
@@ -59,6 +69,44 @@ riverbankcms block upsert home main-hero \
|
|
|
59
69
|
--data '{"heading": "Welcome", "subheading": "to our website"}'
|
|
60
70
|
```
|
|
61
71
|
|
|
72
|
+
Add a minimal media and text block:
|
|
73
|
+
|
|
74
|
+
`block.media-text` has many display and carousel fields, but most are optional controls with defaults. A minimal content-only block only needs rich text:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"text": {
|
|
79
|
+
"type": "doc",
|
|
80
|
+
"content": [
|
|
81
|
+
{
|
|
82
|
+
"type": "paragraph",
|
|
83
|
+
"content": [{ "type": "text", "text": "Welcome to our space." }]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Add media only when you have a complete media item:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"text": {
|
|
95
|
+
"type": "doc",
|
|
96
|
+
"content": [{ "type": "paragraph", "content": [] }]
|
|
97
|
+
},
|
|
98
|
+
"images": [
|
|
99
|
+
{
|
|
100
|
+
"image": {
|
|
101
|
+
"type": "image",
|
|
102
|
+
"src": "/images/studio.jpg",
|
|
103
|
+
"alt": "A bright studio room"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
62
110
|
Add a body text block:
|
|
63
111
|
|
|
64
112
|
```bash
|
|
@@ -105,6 +105,16 @@ Common field types for custom blocks:
|
|
|
105
105
|
| `repeater` | List of nested fields | `schema`, `minItems`, `maxItems` |
|
|
106
106
|
| `group` | Grouped fields | `schema` |
|
|
107
107
|
|
|
108
|
+
### Step 2.5: Model Required Fields Carefully
|
|
109
|
+
|
|
110
|
+
The same content authoring rules apply to custom blocks and system blocks:
|
|
111
|
+
|
|
112
|
+
- Leave `required` unset or `false` for fields that can be omitted from pushed JSON.
|
|
113
|
+
- Use `defaultValue` for optional controls that should have a stable editor/rendering default.
|
|
114
|
+
- Set `required: true` only when every pushed block must provide that field.
|
|
115
|
+
- For repeaters and groups, required child fields apply when the parent item/object is present. If a repeater item has `{ id: 'title', required: true }`, then every item in that repeater must include `title`.
|
|
116
|
+
- In React overrides, type optional fields as optional and handle missing values with defaults or conditional rendering.
|
|
117
|
+
|
|
108
118
|
### Step 3: Create React Override Component
|
|
109
119
|
|
|
110
120
|
Create a component to render your block:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineIslandPropsDecoder } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
|
|
2
|
+
import './chunk-RWYFG625.mjs';
|
|
3
3
|
|
|
4
4
|
// src/rendering/islands/enhancers/accordion.ts
|
|
5
5
|
var decode = defineIslandPropsDecoder("accordion");
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-
|
|
3
|
-
import { SpinnerNode } from './chunk-
|
|
2
|
+
import { buildBookingPaymentSelectionViewModel, usePolling } from './chunk-E6VIWZUG.mjs';
|
|
3
|
+
import { SpinnerNode } from './chunk-ISAUXU5R.mjs';
|
|
4
4
|
import { buildRouteIslandApiConfig } from './chunk-L4J5Y62O.mjs';
|
|
5
|
-
import { scrollToBlock, useDiscountCodeUi, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-
|
|
5
|
+
import { scrollToBlock, useDiscountCodeUi, buildCheckoutReturnUrls, DiscountCodeDisclosure } from './chunk-CKXEUWWA.mjs';
|
|
6
6
|
import { FieldValidationMessage, getFieldValidationControlProps } from './chunk-3DCJ45Z2.mjs';
|
|
7
7
|
import './chunk-WBQG7VJA.mjs';
|
|
8
|
-
import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-
|
|
8
|
+
import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-LJCX6V7Q.mjs';
|
|
9
9
|
import { BlockApiProvider, useBlockApi, FeedbackMessage } from './chunk-WHZQDPBZ.mjs';
|
|
10
10
|
import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
|
|
11
|
-
import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-
|
|
12
|
-
import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatBookingInstant } from './chunk-
|
|
11
|
+
import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith, err } from './chunk-MLBNVN4H.mjs';
|
|
12
|
+
import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, unsafeAsPassId, formatBookingInstant } from './chunk-RWYFG625.mjs';
|
|
13
13
|
import React2, { useRef, useState, useMemo, useReducer, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
14
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
|
package/dist/client/bookings.mjs
CHANGED
|
@@ -5414,10 +5414,11 @@ function omitZeroAmountFutureRows(rows) {
|
|
|
5414
5414
|
if (rows.length <= 1) {
|
|
5415
5415
|
return rows;
|
|
5416
5416
|
}
|
|
5417
|
-
const
|
|
5418
|
-
if (
|
|
5417
|
+
const firstRow = rows[0];
|
|
5418
|
+
if (firstRow === void 0) {
|
|
5419
5419
|
return [];
|
|
5420
5420
|
}
|
|
5421
|
+
const futureRows = rows.slice(1);
|
|
5421
5422
|
return [
|
|
5422
5423
|
firstRow,
|
|
5423
5424
|
...futureRows.filter((row) => row.amountCents > 0)
|
|
@@ -5460,11 +5461,11 @@ function isValidTimeZone(timeZone) {
|
|
|
5460
5461
|
}
|
|
5461
5462
|
function getSafeTimeZone(timeZone) {
|
|
5462
5463
|
const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
|
|
5463
|
-
return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
|
|
5464
|
+
return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
|
|
5464
5465
|
}
|
|
5465
5466
|
function parseStrictBookingTimeZone(timeZone) {
|
|
5466
5467
|
const normalized = timeZone.trim();
|
|
5467
|
-
if (
|
|
5468
|
+
if (normalized.length === 0 || !isValidTimeZone(normalized)) {
|
|
5468
5469
|
return null;
|
|
5469
5470
|
}
|
|
5470
5471
|
return normalized;
|
|
@@ -5551,7 +5552,7 @@ function parseScheduledBookingDateTime(input) {
|
|
|
5551
5552
|
try {
|
|
5552
5553
|
const startsAt = toUtcIsoDateTimeString(input.startsAt);
|
|
5553
5554
|
const timeZone = parseStrictBookingTimeZone(input.timeZone);
|
|
5554
|
-
if (
|
|
5555
|
+
if (timeZone === null) {
|
|
5555
5556
|
return {
|
|
5556
5557
|
ok: false,
|
|
5557
5558
|
field: "timeZone",
|
|
@@ -5598,7 +5599,7 @@ function getBookingLocalDateKey(input) {
|
|
|
5598
5599
|
}
|
|
5599
5600
|
function parseBookingLocalDate(value) {
|
|
5600
5601
|
const match = LOCAL_DATE_PATTERN.exec(value.trim());
|
|
5601
|
-
if (
|
|
5602
|
+
if (match === null || match.groups === void 0) {
|
|
5602
5603
|
throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
|
|
5603
5604
|
}
|
|
5604
5605
|
const year = Number(match.groups.year);
|
|
@@ -12452,22 +12453,22 @@ function AltchaWidget({
|
|
|
12452
12453
|
if (typeof window === "undefined") return;
|
|
12453
12454
|
let widget = null;
|
|
12454
12455
|
Promise.resolve().then(() => (init_altcha(), altcha_exports)).then(() => {
|
|
12455
|
-
if (
|
|
12456
|
+
if (containerRef.current === null) return;
|
|
12456
12457
|
widget = document.createElement("altcha-widget");
|
|
12457
12458
|
widget.setAttribute("challengeurl", challengeUrl);
|
|
12458
|
-
if (auto) {
|
|
12459
|
+
if (auto === true) {
|
|
12459
12460
|
widget.setAttribute("auto", "onload");
|
|
12460
12461
|
}
|
|
12461
|
-
if (hidelogo) {
|
|
12462
|
+
if (hidelogo === true) {
|
|
12462
12463
|
widget.setAttribute("hidelogo", "true");
|
|
12463
12464
|
}
|
|
12464
12465
|
widget.setAttribute("hidefooter", "true");
|
|
12465
|
-
if (className) {
|
|
12466
|
+
if (className !== void 0 && className.length > 0) {
|
|
12466
12467
|
widget.className = className;
|
|
12467
12468
|
}
|
|
12468
12469
|
widget.addEventListener("statechange", ((event) => {
|
|
12469
12470
|
const { state, payload } = event.detail;
|
|
12470
|
-
if (state === "verified" && payload) {
|
|
12471
|
+
if (state === "verified" && payload !== void 0 && payload.length > 0) {
|
|
12471
12472
|
onSolutionChange?.(payload);
|
|
12472
12473
|
} else if (state === "error" || state === "expired") {
|
|
12473
12474
|
onSolutionChange?.(null);
|
|
@@ -12478,7 +12479,7 @@ function AltchaWidget({
|
|
|
12478
12479
|
console.error("Failed to load ALTCHA widget:", err3);
|
|
12479
12480
|
});
|
|
12480
12481
|
return () => {
|
|
12481
|
-
if (widget && containerRef.current) {
|
|
12482
|
+
if (widget !== null && containerRef.current !== null) {
|
|
12482
12483
|
containerRef.current.removeChild(widget);
|
|
12483
12484
|
}
|
|
12484
12485
|
};
|
|
@@ -12533,15 +12534,15 @@ var encoder = new TextEncoder();
|
|
|
12533
12534
|
// ../altcha/src/index.ts
|
|
12534
12535
|
function getCmsApiUrl() {
|
|
12535
12536
|
const env = process.env.RIVERBANK_ENV;
|
|
12536
|
-
if (env) {
|
|
12537
|
+
if (env !== void 0 && env.length > 0) {
|
|
12537
12538
|
const envKey = `RIVERBANK_${env.toUpperCase()}_DASHBOARD_URL`;
|
|
12538
12539
|
const dashboardUrl2 = process.env[envKey];
|
|
12539
|
-
if (dashboardUrl2) {
|
|
12540
|
+
if (dashboardUrl2 !== void 0 && dashboardUrl2.length > 0) {
|
|
12540
12541
|
return `${dashboardUrl2.replace(/\/$/, "")}/api`;
|
|
12541
12542
|
}
|
|
12542
12543
|
}
|
|
12543
12544
|
const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
|
|
12544
|
-
if (dashboardUrl) {
|
|
12545
|
+
if (dashboardUrl !== void 0 && dashboardUrl.length > 0) {
|
|
12545
12546
|
return `${dashboardUrl.replace(/\/$/, "")}/api`;
|
|
12546
12547
|
}
|
|
12547
12548
|
throw new Error("Dashboard URL not configured. Set NEXT_PUBLIC_DASHBOARD_URL");
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { normalizeCarouselProps, CarouselNodeClient } from './chunk-
|
|
1
|
+
import { normalizeCarouselProps, CarouselNodeClient } from './chunk-PMNAV6LO.mjs';
|
|
2
2
|
import './chunk-6N7YRNYU.mjs';
|
|
3
3
|
import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
|
|
4
|
-
import { defineIslandPropsDecoder } from './chunk-
|
|
5
|
-
import './chunk-
|
|
4
|
+
import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
|
|
5
|
+
import './chunk-RWYFG625.mjs';
|
|
6
6
|
import { jsx } from 'react/jsx-runtime';
|
|
7
7
|
|
|
8
8
|
var decode = defineIslandPropsDecoder("carousel");
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { mountShopBlockIsland, CartClient } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { mountShopBlockIsland, CartClient } from './chunk-RMOFBBNA.mjs';
|
|
2
|
+
import './chunk-6RN62XBV.mjs';
|
|
3
|
+
import './chunk-PMNAV6LO.mjs';
|
|
4
4
|
import './chunk-6N7YRNYU.mjs';
|
|
5
5
|
import './chunk-L4J5Y62O.mjs';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-CKXEUWWA.mjs';
|
|
7
7
|
import './chunk-3DCJ45Z2.mjs';
|
|
8
8
|
import './chunk-WBQG7VJA.mjs';
|
|
9
9
|
import './chunk-WHZQDPBZ.mjs';
|
|
10
10
|
import './chunk-N7PBWBWQ.mjs';
|
|
11
|
-
import { defineIslandPropsDecoder } from './chunk-
|
|
12
|
-
import './chunk-
|
|
11
|
+
import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
|
|
12
|
+
import './chunk-RWYFG625.mjs';
|
|
13
13
|
|
|
14
14
|
// src/rendering/islands/enhancers/cart.tsx
|
|
15
15
|
var decode = defineIslandPropsDecoder("cart");
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { mountShopBlockIsland, CheckoutClient } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { mountShopBlockIsland, CheckoutClient } from './chunk-RMOFBBNA.mjs';
|
|
2
|
+
import './chunk-6RN62XBV.mjs';
|
|
3
|
+
import './chunk-PMNAV6LO.mjs';
|
|
4
4
|
import './chunk-6N7YRNYU.mjs';
|
|
5
5
|
import './chunk-L4J5Y62O.mjs';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-CKXEUWWA.mjs';
|
|
7
7
|
import './chunk-3DCJ45Z2.mjs';
|
|
8
8
|
import './chunk-WBQG7VJA.mjs';
|
|
9
9
|
import './chunk-WHZQDPBZ.mjs';
|
|
10
10
|
import './chunk-N7PBWBWQ.mjs';
|
|
11
|
-
import { defineIslandPropsDecoder } from './chunk-
|
|
12
|
-
import './chunk-
|
|
11
|
+
import { defineIslandPropsDecoder } from './chunk-MLBNVN4H.mjs';
|
|
12
|
+
import './chunk-RWYFG625.mjs';
|
|
13
13
|
|
|
14
14
|
// src/rendering/islands/enhancers/checkout.tsx
|
|
15
15
|
var decode = defineIslandPropsDecoder("checkout");
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { LeafletStaticMap } from './chunk-
|
|
3
|
-
import { resolveCoursePricingState, useWaitlistClaim, MagicLinkForm, formatCoursePriceAmount, formatCoursePriceDisplay } from './chunk-
|
|
2
|
+
import { LeafletStaticMap } from './chunk-C4LP6BPG.mjs';
|
|
3
|
+
import { resolveCoursePricingState, useWaitlistClaim, MagicLinkForm, formatCoursePriceAmount, formatCoursePriceDisplay } from './chunk-FMZZHAIR.mjs';
|
|
4
4
|
import { CreditCard, Ticket, Star, Sparkles } from './chunk-6N7YRNYU.mjs';
|
|
5
|
-
import { usePolling, buildBookingPaymentSelectionViewModel } from './chunk-
|
|
6
|
-
import { SpinnerNode } from './chunk-
|
|
7
|
-
import { createBodyThemePortalRoot, TabBarFragment, useDiscountCodeUi, logoutPortal, consumeSearchParam, StepIndicator, DiscountCodeDisclosure, TerminalPanel, StateIcon, formatPrice, CrossIcon, ClockIcon, LoggedInAsUser, CheckIcon } from './chunk-
|
|
5
|
+
import { usePolling, buildBookingPaymentSelectionViewModel } from './chunk-E6VIWZUG.mjs';
|
|
6
|
+
import { SpinnerNode } from './chunk-ISAUXU5R.mjs';
|
|
7
|
+
import { createBodyThemePortalRoot, TabBarFragment, useDiscountCodeUi, logoutPortal, consumeSearchParam, StepIndicator, DiscountCodeDisclosure, TerminalPanel, StateIcon, formatPrice, CrossIcon, ClockIcon, LoggedInAsUser, CheckIcon } from './chunk-CKXEUWWA.mjs';
|
|
8
8
|
import { getFieldValidationControlProps, FieldValidationMessage } from './chunk-3DCJ45Z2.mjs';
|
|
9
9
|
import { ModalShell } from './chunk-WBQG7VJA.mjs';
|
|
10
|
-
import { isSpamProtectionEnabled, AltchaWidget, getChallengeUrl } from './chunk-
|
|
10
|
+
import { isSpamProtectionEnabled, AltchaWidget, getChallengeUrl } from './chunk-LJCX6V7Q.mjs';
|
|
11
11
|
import { useBlockApi, FeedbackMessage } from './chunk-WHZQDPBZ.mjs';
|
|
12
|
-
import { buildEventRuntimeFilters, buildEventCalendarListingRender, groupEventsByDate, getOrderedDayNames, formatDateKey, getEventRuntimeFiltersKey, themeButtonClassName, normalizeCsvIds, normalizeOptionalId, normalizeEventBlockKind, normalizeCsvString, EventCompactRow, EmptyState, getContainerClass, getCardOrientation, isToday, MAX_EVENTS_PER_DAY, formatTime, WIZARD_STEPS, getWizardStepsForContext, getStepNumber, formatEventPriceDisplay, resolveRuntimeEventPricing, formatEventPrice, formatEventDateParts, resolveEventLinkProps, DateTimeTile, assertNever, EventCard, buildCalendarViewport, shiftCalendarAnchorDate, addMonths, getThreeMonthRange, buildTimetableModel, formatDate, MONTH_NAMES, getEventAvailability, formatEventTeacherLine, toRegistrationEvents, isEventContentType, findPreSelectedEvent, resolveRegistrationTarget, findEventByOccurrenceId, resolveEventRequiresPayment, resolveDiscountContext } from './chunk-
|
|
13
|
-
import { publicEventPricingType, getBookingLocalDateKey, toScheduledBookingDateTime, toBookingTimeZone, publicEventPricingCurrency, formatBookingDateTime, publicEventPricingMode, publicEventScalarPrice, publicEventTicketTypes, formatCurrencyAmount, formatBookingDate, formatBookingTime } from './chunk-
|
|
12
|
+
import { buildEventRuntimeFilters, buildEventCalendarListingRender, groupEventsByDate, getOrderedDayNames, formatDateKey, getEventRuntimeFiltersKey, themeButtonClassName, normalizeCsvIds, normalizeOptionalId, normalizeEventBlockKind, normalizeCsvString, EventCompactRow, EmptyState, getContainerClass, getCardOrientation, isToday, MAX_EVENTS_PER_DAY, formatTime, WIZARD_STEPS, getWizardStepsForContext, getStepNumber, formatEventPriceDisplay, resolveRuntimeEventPricing, formatEventPrice, formatEventDateParts, resolveEventLinkProps, DateTimeTile, assertNever, EventCard, buildCalendarViewport, shiftCalendarAnchorDate, addMonths, getThreeMonthRange, buildTimetableModel, formatDate, MONTH_NAMES, getEventAvailability, formatEventTeacherLine, toRegistrationEvents, isEventContentType, findPreSelectedEvent, resolveRegistrationTarget, findEventByOccurrenceId, resolveEventRequiresPayment, resolveDiscountContext } from './chunk-MLBNVN4H.mjs';
|
|
13
|
+
import { publicEventPricingType, getBookingLocalDateKey, toScheduledBookingDateTime, toBookingTimeZone, publicEventPricingCurrency, formatBookingDateTime, publicEventPricingMode, publicEventScalarPrice, publicEventTicketTypes, formatCurrencyAmount, formatBookingDate, formatBookingTime } from './chunk-RWYFG625.mjs';
|
|
14
14
|
import React9, { createContext, useId, useMemo, useReducer, useState, useRef, useEffect, useCallback, useContext } from 'react';
|
|
15
15
|
import { createPortal } from 'react-dom';
|
|
16
16
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EMPTY_COMMERCE_CART_STATE, parseStoredCommerceCartState, reduceCommerceCart, buildPassCartItem } from './chunk-
|
|
1
|
+
import { EMPTY_COMMERCE_CART_STATE, parseStoredCommerceCartState, reduceCommerceCart, buildPassCartItem } from './chunk-MLBNVN4H.mjs';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
4
|
var EMPTY_STATE = EMPTY_COMMERCE_CART_STATE;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { FeedbackMessage, discountAvailabilityHasDiscounts, getAutoAppliedDiscountPreview, discountAvailabilityAllowsManualEntry } from './chunk-WHZQDPBZ.mjs';
|
|
3
|
-
import { themeButtonClassName } from './chunk-
|
|
4
|
-
import { formatCurrencyAmount, clsx_default } from './chunk-
|
|
3
|
+
import { themeButtonClassName } from './chunk-MLBNVN4H.mjs';
|
|
4
|
+
import { formatCurrencyAmount, clsx_default } from './chunk-RWYFG625.mjs';
|
|
5
5
|
import { useReducer, useEffect, useId, useRef } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { formatPrice } from './chunk-
|
|
3
|
-
import { assertNever } from './chunk-
|
|
4
|
-
import { resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows } from './chunk-
|
|
2
|
+
import { formatPrice } from './chunk-CKXEUWWA.mjs';
|
|
3
|
+
import { assertNever } from './chunk-MLBNVN4H.mjs';
|
|
4
|
+
import { resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows } from './chunk-RWYFG625.mjs';
|
|
5
5
|
import { useReducer, useRef, useCallback, useEffect } from 'react';
|
|
6
6
|
|
|
7
7
|
// ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useBlockApi } from './chunk-WHZQDPBZ.mjs';
|
|
3
|
-
import { themeButtonClassName, assertNever } from './chunk-
|
|
4
|
-
import { resolvePlanningDateInput, formatBookingPriceDisplay } from './chunk-
|
|
3
|
+
import { themeButtonClassName, assertNever } from './chunk-MLBNVN4H.mjs';
|
|
4
|
+
import { resolvePlanningDateInput, formatBookingPriceDisplay } from './chunk-RWYFG625.mjs';
|
|
5
5
|
import { useState, useReducer, useSyncExternalStore, useEffect } from 'react';
|
|
6
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
7
|
|
|
@@ -14,22 +14,22 @@ function AltchaWidget({
|
|
|
14
14
|
if (typeof window === "undefined") return;
|
|
15
15
|
let widget = null;
|
|
16
16
|
import('./altcha-LIGLPZS5.mjs').then(() => {
|
|
17
|
-
if (
|
|
17
|
+
if (containerRef.current === null) return;
|
|
18
18
|
widget = document.createElement("altcha-widget");
|
|
19
19
|
widget.setAttribute("challengeurl", challengeUrl);
|
|
20
|
-
if (auto) {
|
|
20
|
+
if (auto === true) {
|
|
21
21
|
widget.setAttribute("auto", "onload");
|
|
22
22
|
}
|
|
23
|
-
if (hidelogo) {
|
|
23
|
+
if (hidelogo === true) {
|
|
24
24
|
widget.setAttribute("hidelogo", "true");
|
|
25
25
|
}
|
|
26
26
|
widget.setAttribute("hidefooter", "true");
|
|
27
|
-
if (className) {
|
|
27
|
+
if (className !== void 0 && className.length > 0) {
|
|
28
28
|
widget.className = className;
|
|
29
29
|
}
|
|
30
30
|
widget.addEventListener("statechange", ((event) => {
|
|
31
31
|
const { state, payload } = event.detail;
|
|
32
|
-
if (state === "verified" && payload) {
|
|
32
|
+
if (state === "verified" && payload !== void 0 && payload.length > 0) {
|
|
33
33
|
onSolutionChange?.(payload);
|
|
34
34
|
} else if (state === "error" || state === "expired") {
|
|
35
35
|
onSolutionChange?.(null);
|
|
@@ -40,7 +40,7 @@ function AltchaWidget({
|
|
|
40
40
|
console.error("Failed to load ALTCHA widget:", err);
|
|
41
41
|
});
|
|
42
42
|
return () => {
|
|
43
|
-
if (widget && containerRef.current) {
|
|
43
|
+
if (widget !== null && containerRef.current !== null) {
|
|
44
44
|
containerRef.current.removeChild(widget);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
@@ -59,15 +59,15 @@ new TextEncoder();
|
|
|
59
59
|
// ../altcha/src/index.ts
|
|
60
60
|
function getCmsApiUrl() {
|
|
61
61
|
const env = process.env.RIVERBANK_ENV;
|
|
62
|
-
if (env) {
|
|
62
|
+
if (env !== void 0 && env.length > 0) {
|
|
63
63
|
const envKey = `RIVERBANK_${env.toUpperCase()}_DASHBOARD_URL`;
|
|
64
64
|
const dashboardUrl2 = process.env[envKey];
|
|
65
|
-
if (dashboardUrl2) {
|
|
65
|
+
if (dashboardUrl2 !== void 0 && dashboardUrl2.length > 0) {
|
|
66
66
|
return `${dashboardUrl2.replace(/\/$/, "")}/api`;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
|
|
70
|
-
if (dashboardUrl) {
|
|
70
|
+
if (dashboardUrl !== void 0 && dashboardUrl.length > 0) {
|
|
71
71
|
return `${dashboardUrl.replace(/\/$/, "")}/api`;
|
|
72
72
|
}
|
|
73
73
|
throw new Error("Dashboard URL not configured. Set NEXT_PUBLIC_DASHBOARD_URL");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseAspectRatioValue, parseColorTokenParts, toBookingTimeZone, formatBookingDate, toScheduledBookingDateTime, formatBookingTime, toScheduledBookingDateRange, formatBookingDateParts, formatEventPricing, ImagePresets, getBookingLocalDateKey, publicEventPricingType, formatCurrencyAmount, getCurrentResolveImageUrlContext, renderVideo, renderAudio, resolveMediaNodeResponsiveImage, MediaPlaceholder, computeMediaTransformStyle, rgbColorValue } from './chunk-
|
|
1
|
+
import { parseAspectRatioValue, parseColorTokenParts, toBookingTimeZone, formatBookingDate, toScheduledBookingDateTime, formatBookingTime, toScheduledBookingDateRange, formatBookingDateParts, formatEventPricing, ImagePresets, getBookingLocalDateKey, publicEventPricingType, formatCurrencyAmount, getCurrentResolveImageUrlContext, renderVideo, renderAudio, resolveMediaNodeResponsiveImage, MediaPlaceholder, computeMediaTransformStyle, rgbColorValue } from './chunk-RWYFG625.mjs';
|
|
2
2
|
import z2, { z } from 'zod';
|
|
3
3
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -5309,7 +5309,7 @@ function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
|
|
|
5309
5309
|
if (view === "week") {
|
|
5310
5310
|
const weekStart = days[0];
|
|
5311
5311
|
const weekEnd = days[6];
|
|
5312
|
-
if (
|
|
5312
|
+
if (weekStart === void 0 || weekEnd === void 0) {
|
|
5313
5313
|
return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
|
|
5314
5314
|
}
|
|
5315
5315
|
const startMonth = monthNames[weekStart.getMonth()] ?? "";
|
|
@@ -5415,7 +5415,9 @@ function getLocalDateKey(isoTimestamp, timeZone) {
|
|
|
5415
5415
|
const year = parts.find((part) => part.type === "year")?.value;
|
|
5416
5416
|
const month = parts.find((part) => part.type === "month")?.value;
|
|
5417
5417
|
const day = parts.find((part) => part.type === "day")?.value;
|
|
5418
|
-
if (
|
|
5418
|
+
if (year === void 0 || year.length === 0) return null;
|
|
5419
|
+
if (month === void 0 || month.length === 0) return null;
|
|
5420
|
+
if (day === void 0 || day.length === 0) return null;
|
|
5419
5421
|
return `${year}-${month}-${day}`;
|
|
5420
5422
|
}
|
|
5421
5423
|
var validTimeZoneCache = /* @__PURE__ */ new Map();
|
|
@@ -5672,7 +5674,7 @@ function enumerateDateKeys(startDateKey, endDateKey) {
|
|
|
5672
5674
|
}
|
|
5673
5675
|
function parseDateKey(dateKey) {
|
|
5674
5676
|
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateKey);
|
|
5675
|
-
if (
|
|
5677
|
+
if (match === null) {
|
|
5676
5678
|
throw new Error(`Invalid timetable date key: ${dateKey}`);
|
|
5677
5679
|
}
|
|
5678
5680
|
const [, year, month, day] = match;
|
|
@@ -5692,7 +5694,7 @@ function groupItemsByDate(items, accessors) {
|
|
|
5692
5694
|
const dateKey = getLocalDateKey(startsAt, timeZone);
|
|
5693
5695
|
if (dateKey == null) continue;
|
|
5694
5696
|
const existing = grouped.get(dateKey);
|
|
5695
|
-
if (existing) {
|
|
5697
|
+
if (existing !== void 0) {
|
|
5696
5698
|
existing.push(item);
|
|
5697
5699
|
} else {
|
|
5698
5700
|
grouped.set(dateKey, [item]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { ChevronLeft, ChevronRight } from './chunk-6N7YRNYU.mjs';
|
|
3
|
-
import { clsx_default } from './chunk-
|
|
3
|
+
import { clsx_default } from './chunk-RWYFG625.mjs';
|
|
4
4
|
import React, { useRef, useState, useCallback, useEffect } from 'react';
|
|
5
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { addPassToCommerceCart, useCommerceCart } from './chunk-
|
|
3
|
-
import { CarouselNodeClient } from './chunk-
|
|
2
|
+
import { addPassToCommerceCart, useCommerceCart } from './chunk-6RN62XBV.mjs';
|
|
3
|
+
import { CarouselNodeClient } from './chunk-PMNAV6LO.mjs';
|
|
4
4
|
import { buildRouteIslandApiConfig } from './chunk-L4J5Y62O.mjs';
|
|
5
|
-
import { useDiscountCodeUi, createBodyThemePortalRoot, consumeSearchParams, scrollToBlock, TerminalPanel, StateIcon, CheckIcon, CrossIcon, ActionRow, DiscountCodeDisclosure, consumeSearchParam, buildCheckoutReturnUrls } from './chunk-
|
|
5
|
+
import { useDiscountCodeUi, createBodyThemePortalRoot, consumeSearchParams, scrollToBlock, TerminalPanel, StateIcon, CheckIcon, CrossIcon, ActionRow, DiscountCodeDisclosure, consumeSearchParam, buildCheckoutReturnUrls } from './chunk-CKXEUWWA.mjs';
|
|
6
6
|
import { ModalShell, resolveDedicatedCheckoutPath } from './chunk-WBQG7VJA.mjs';
|
|
7
7
|
import { useBlockApi, FeedbackMessage, BlockApiProvider, discountAvailabilityHasDiscounts, discountAvailabilityAllowsManualEntry, getAutoAppliedDiscountPreview } from './chunk-WHZQDPBZ.mjs';
|
|
8
8
|
import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
|
|
9
|
-
import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, deriveCommerceCheckoutState, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay, assertNever as assertNever$1, reportWorkflowError, clearWorkflowFeedback, unwrapRichTextRoot, createRichTextDocFromMarkdown, isRecord } from './chunk-
|
|
10
|
-
import { assertNever, ok, err, getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-
|
|
9
|
+
import { themeButtonClassName, formatCommercePrice, formatInterval, getShopDisplayForItems, deriveCommerceCheckoutState, buildProductDetailDisplay, productItemKey, buildProductCartItem, buildProductCardDisplay, assertNever as assertNever$1, reportWorkflowError, clearWorkflowFeedback, unwrapRichTextRoot, createRichTextDocFromMarkdown, isRecord } from './chunk-MLBNVN4H.mjs';
|
|
10
|
+
import { assertNever, ok, err, getCurrentResolveImageUrlContext, resolveImageUrlWithContext, ImagePresets } from './chunk-RWYFG625.mjs';
|
|
11
11
|
import * as React3 from 'react';
|
|
12
12
|
import React3__default, { useState, useRef, useCallback, useEffect } from 'react';
|
|
13
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -264,10 +264,11 @@ function omitZeroAmountFutureRows(rows) {
|
|
|
264
264
|
if (rows.length <= 1) {
|
|
265
265
|
return rows;
|
|
266
266
|
}
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
267
|
+
const firstRow = rows[0];
|
|
268
|
+
if (firstRow === void 0) {
|
|
269
269
|
return [];
|
|
270
270
|
}
|
|
271
|
+
const futureRows = rows.slice(1);
|
|
271
272
|
return [
|
|
272
273
|
firstRow,
|
|
273
274
|
...futureRows.filter((row) => row.amountCents > 0)
|
|
@@ -310,11 +311,11 @@ function isValidTimeZone(timeZone) {
|
|
|
310
311
|
}
|
|
311
312
|
function getSafeTimeZone(timeZone) {
|
|
312
313
|
const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
|
|
313
|
-
return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
|
|
314
|
+
return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
|
|
314
315
|
}
|
|
315
316
|
function parseStrictBookingTimeZone(timeZone) {
|
|
316
317
|
const normalized = timeZone.trim();
|
|
317
|
-
if (
|
|
318
|
+
if (normalized.length === 0 || !isValidTimeZone(normalized)) {
|
|
318
319
|
return null;
|
|
319
320
|
}
|
|
320
321
|
return normalized;
|
|
@@ -401,7 +402,7 @@ function parseScheduledBookingDateTime(input) {
|
|
|
401
402
|
try {
|
|
402
403
|
const startsAt = toUtcIsoDateTimeString(input.startsAt);
|
|
403
404
|
const timeZone = parseStrictBookingTimeZone(input.timeZone);
|
|
404
|
-
if (
|
|
405
|
+
if (timeZone === null) {
|
|
405
406
|
return {
|
|
406
407
|
ok: false,
|
|
407
408
|
field: "timeZone",
|
|
@@ -540,7 +541,7 @@ function getBookingLocalDateKey(input) {
|
|
|
540
541
|
}
|
|
541
542
|
function parseBookingLocalDate(value) {
|
|
542
543
|
const match = LOCAL_DATE_PATTERN.exec(value.trim());
|
|
543
|
-
if (
|
|
544
|
+
if (match === null || match.groups === void 0) {
|
|
544
545
|
throw new Error(`Invalid booking date format: "${value}" (expected YYYY-MM-DD)`);
|
|
545
546
|
}
|
|
546
547
|
const year = Number(match.groups.year);
|
|
@@ -574,10 +575,10 @@ function normalizeLocationAddressText(value) {
|
|
|
574
575
|
return null;
|
|
575
576
|
}
|
|
576
577
|
const trimmed = value.trim();
|
|
577
|
-
return trimmed ? trimmed : null;
|
|
578
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
578
579
|
}
|
|
579
580
|
function hasLocationCoordinates(value) {
|
|
580
|
-
return typeof value
|
|
581
|
+
return value != null && typeof value.lat === "number" && typeof value.lng === "number";
|
|
581
582
|
}
|
|
582
583
|
function toLocationCoordinates(value) {
|
|
583
584
|
if (!hasLocationCoordinates(value)) {
|