@flamingo-stack/openframe-frontend-core 0.0.573 → 0.0.574-snapshot.20260827223923
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/{chunk-TIX2SHZX.js → chunk-2EPUD2VR.js} +2 -2
- package/dist/{chunk-2EB5273T.js → chunk-2IK6SB6F.js} +2 -2
- package/dist/{chunk-OUMRHNZW.cjs → chunk-3IUQLB47.cjs} +3 -3
- package/dist/{chunk-OUMRHNZW.cjs.map → chunk-3IUQLB47.cjs.map} +1 -1
- package/dist/{chunk-BWHLWS32.cjs → chunk-3U2P63NQ.cjs} +10 -10
- package/dist/{chunk-BWHLWS32.cjs.map → chunk-3U2P63NQ.cjs.map} +1 -1
- package/dist/{chunk-EC44ZXBH.js → chunk-5QDGP3RI.js} +2 -2
- package/dist/{chunk-YS64Y5MP.cjs → chunk-7G23ANVM.cjs} +49 -49
- package/dist/{chunk-YS64Y5MP.cjs.map → chunk-7G23ANVM.cjs.map} +1 -1
- package/dist/{chunk-R3I2XI33.js → chunk-BGE7CKXC.js} +4 -4
- package/dist/{chunk-6SMQCAPO.cjs → chunk-BGZCZ2JS.cjs} +3 -3
- package/dist/{chunk-6SMQCAPO.cjs.map → chunk-BGZCZ2JS.cjs.map} +1 -1
- package/dist/{chunk-B7S7ETML.cjs → chunk-BKXL7OYT.cjs} +3 -3
- package/dist/{chunk-B7S7ETML.cjs.map → chunk-BKXL7OYT.cjs.map} +1 -1
- package/dist/{chunk-4WCTY326.js → chunk-BTZF3JRS.js} +2 -2
- package/dist/{chunk-J5OC2KYU.js → chunk-DTSRMQIY.js} +5 -5
- package/dist/{chunk-4TGUWWMY.cjs → chunk-GFSJXRX7.cjs} +16 -16
- package/dist/{chunk-4TGUWWMY.cjs.map → chunk-GFSJXRX7.cjs.map} +1 -1
- package/dist/{chunk-P625NSEA.cjs → chunk-IRJQH7RJ.cjs} +17 -17
- package/dist/{chunk-P625NSEA.cjs.map → chunk-IRJQH7RJ.cjs.map} +1 -1
- package/dist/{chunk-DSU7LQMU.js → chunk-ISULYCGY.js} +2 -2
- package/dist/{chunk-SB67TZQU.js → chunk-IWISKP3F.js} +2 -2
- package/dist/{chunk-JLIXPN37.cjs → chunk-K3XONUML.cjs} +4 -4
- package/dist/{chunk-JLIXPN37.cjs.map → chunk-K3XONUML.cjs.map} +1 -1
- package/dist/{chunk-IBZBGRO2.js → chunk-KG7D35RU.js} +5 -5
- package/dist/{chunk-3ENV3IEP.js → chunk-KSKCQ3ZN.js} +2 -2
- package/dist/{chunk-NGXP4EAQ.js → chunk-OE7NV7H3.js} +2 -2
- package/dist/{chunk-66LZDE7U.js → chunk-PBS4F534.js} +3 -2
- package/dist/chunk-PBS4F534.js.map +1 -0
- package/dist/{chunk-AQBWGEL3.cjs → chunk-PUL6X6HY.cjs} +32 -32
- package/dist/{chunk-AQBWGEL3.cjs.map → chunk-PUL6X6HY.cjs.map} +1 -1
- package/dist/{chunk-YK7M7RBF.cjs → chunk-QDOBY3TP.cjs} +3 -2
- package/dist/chunk-QDOBY3TP.cjs.map +1 -0
- package/dist/{chunk-OYWAPTEF.cjs → chunk-QF5B6V4L.cjs} +17 -17
- package/dist/{chunk-OYWAPTEF.cjs.map → chunk-QF5B6V4L.cjs.map} +1 -1
- package/dist/{chunk-NCCWS6YE.cjs → chunk-QTVW5XBL.cjs} +4 -4
- package/dist/{chunk-NCCWS6YE.cjs.map → chunk-QTVW5XBL.cjs.map} +1 -1
- package/dist/{chunk-PDQ7F5AB.cjs → chunk-RXJZXMDZ.cjs} +13 -13
- package/dist/{chunk-PDQ7F5AB.cjs.map → chunk-RXJZXMDZ.cjs.map} +1 -1
- package/dist/{chunk-EIK6KDAE.cjs → chunk-SVUZUFT4.cjs} +34 -34
- package/dist/{chunk-EIK6KDAE.cjs.map → chunk-SVUZUFT4.cjs.map} +1 -1
- package/dist/{chunk-GSSJFXIW.cjs → chunk-UILNZL6J.cjs} +3 -3
- package/dist/{chunk-GSSJFXIW.cjs.map → chunk-UILNZL6J.cjs.map} +1 -1
- package/dist/{chunk-4IAZOAS7.js → chunk-UPEIX7VG.js} +4 -4
- package/dist/{chunk-SY7M6VAJ.js → chunk-WAWMZSCP.js} +3 -3
- package/dist/{chunk-JTDYVW2B.js → chunk-WVKRSC65.js} +2 -2
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +6 -6
- package/dist/components/docs/index.js +5 -5
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +114 -114
- package/dist/components/index.js +12 -12
- package/dist/components/meeting-scheduler/index.cjs +130 -111
- package/dist/components/meeting-scheduler/index.cjs.map +1 -1
- package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
- package/dist/components/meeting-scheduler/index.js +113 -94
- package/dist/components/meeting-scheduler/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +5 -5
- package/dist/components/navigation/index.js +4 -4
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/alert.d.ts +1 -1
- package/dist/components/ui/alert.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/hooks/use-meeting-booking.d.ts +1 -1
- package/dist/hooks/use-meeting-booking.d.ts.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.js +5 -5
- package/dist/schemas/meeting-booking-schema.cjs +9 -0
- package/dist/schemas/meeting-booking-schema.cjs.map +1 -1
- package/dist/schemas/meeting-booking-schema.d.ts +15 -2
- package/dist/schemas/meeting-booking-schema.d.ts.map +1 -1
- package/dist/schemas/meeting-booking-schema.js +9 -1
- package/dist/schemas/meeting-booking-schema.js.map +1 -1
- package/package.json +1 -1
- package/src/components/meeting-scheduler/index.tsx +34 -16
- package/src/components/ui/alert.tsx +1 -0
- package/src/hooks/use-meeting-booking.ts +6 -13
- package/src/schemas/meeting-booking-schema.ts +23 -3
- package/dist/chunk-66LZDE7U.js.map +0 -1
- package/dist/chunk-YK7M7RBF.cjs.map +0 -1
- /package/dist/{chunk-TIX2SHZX.js.map → chunk-2EPUD2VR.js.map} +0 -0
- /package/dist/{chunk-2EB5273T.js.map → chunk-2IK6SB6F.js.map} +0 -0
- /package/dist/{chunk-EC44ZXBH.js.map → chunk-5QDGP3RI.js.map} +0 -0
- /package/dist/{chunk-R3I2XI33.js.map → chunk-BGE7CKXC.js.map} +0 -0
- /package/dist/{chunk-4WCTY326.js.map → chunk-BTZF3JRS.js.map} +0 -0
- /package/dist/{chunk-J5OC2KYU.js.map → chunk-DTSRMQIY.js.map} +0 -0
- /package/dist/{chunk-DSU7LQMU.js.map → chunk-ISULYCGY.js.map} +0 -0
- /package/dist/{chunk-SB67TZQU.js.map → chunk-IWISKP3F.js.map} +0 -0
- /package/dist/{chunk-IBZBGRO2.js.map → chunk-KG7D35RU.js.map} +0 -0
- /package/dist/{chunk-3ENV3IEP.js.map → chunk-KSKCQ3ZN.js.map} +0 -0
- /package/dist/{chunk-NGXP4EAQ.js.map → chunk-OE7NV7H3.js.map} +0 -0
- /package/dist/{chunk-4IAZOAS7.js.map → chunk-UPEIX7VG.js.map} +0 -0
- /package/dist/{chunk-SY7M6VAJ.js.map → chunk-WAWMZSCP.js.map} +0 -0
- /package/dist/{chunk-JTDYVW2B.js.map → chunk-WVKRSC65.js.map} +0 -0
package/dist/components/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
SoftwareInfo,
|
|
16
16
|
SoftwareSourceBadge,
|
|
17
17
|
ToolBadge
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-5QDGP3RI.js";
|
|
19
19
|
import {
|
|
20
20
|
AppHeader,
|
|
21
21
|
AppLayout,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
SlidingSidebar,
|
|
35
35
|
TicketAlertsButton,
|
|
36
36
|
TopNavigation
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-WAWMZSCP.js";
|
|
38
38
|
import {
|
|
39
39
|
DeliveryLists,
|
|
40
40
|
DeliveryTable,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
RoadmapView,
|
|
49
49
|
useLegalDocs,
|
|
50
50
|
useRoadmapVoting
|
|
51
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-BGE7CKXC.js";
|
|
52
52
|
import {
|
|
53
53
|
AnnouncementBarSkeleton,
|
|
54
54
|
ArticleLayoutSkeleton,
|
|
@@ -81,12 +81,12 @@ import {
|
|
|
81
81
|
useDocNavigation,
|
|
82
82
|
useDocumentTree,
|
|
83
83
|
useScrollSpy
|
|
84
|
-
} from "../chunk-
|
|
84
|
+
} from "../chunk-KG7D35RU.js";
|
|
85
85
|
import {
|
|
86
86
|
FileDownloadCard,
|
|
87
87
|
GoogleSheetsViewer,
|
|
88
88
|
PdfViewer
|
|
89
|
-
} from "../chunk-
|
|
89
|
+
} from "../chunk-ISULYCGY.js";
|
|
90
90
|
import {
|
|
91
91
|
PersistentPagination,
|
|
92
92
|
PersistentPaginationWrapper,
|
|
@@ -96,13 +96,13 @@ import {
|
|
|
96
96
|
FaqAccordion,
|
|
97
97
|
FaqDocumentPage,
|
|
98
98
|
FaqSection
|
|
99
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-OE7NV7H3.js";
|
|
100
100
|
import {
|
|
101
101
|
MobileNavigationDropdown,
|
|
102
102
|
MultiLevelNavigation,
|
|
103
103
|
StickySectionNav,
|
|
104
104
|
useSectionNavigation
|
|
105
|
-
} from "../chunk-
|
|
105
|
+
} from "../chunk-KSKCQ3ZN.js";
|
|
106
106
|
import {
|
|
107
107
|
DeliveryRow,
|
|
108
108
|
DevCardRowContent,
|
|
@@ -110,16 +110,16 @@ import {
|
|
|
110
110
|
DevCardRowSkeletonList,
|
|
111
111
|
DevSectionPage,
|
|
112
112
|
DevSectionView
|
|
113
|
-
} from "../chunk-
|
|
113
|
+
} from "../chunk-WVKRSC65.js";
|
|
114
114
|
import {
|
|
115
115
|
EmptyState,
|
|
116
116
|
UnifiedPagination
|
|
117
117
|
} from "../chunk-QQ5ZVCD4.js";
|
|
118
|
-
import "../chunk-
|
|
118
|
+
import "../chunk-IWISKP3F.js";
|
|
119
119
|
import {
|
|
120
120
|
ArticleAuthorByline,
|
|
121
121
|
DetailPageSkeleton
|
|
122
|
-
} from "../chunk-
|
|
122
|
+
} from "../chunk-2EPUD2VR.js";
|
|
123
123
|
import {
|
|
124
124
|
DocSearchBar,
|
|
125
125
|
DocSearchResultRow,
|
|
@@ -127,7 +127,7 @@ import {
|
|
|
127
127
|
mapDocSearchResults,
|
|
128
128
|
resolveSearchResultAction,
|
|
129
129
|
useDocSearch
|
|
130
|
-
} from "../chunk-
|
|
130
|
+
} from "../chunk-BTZF3JRS.js";
|
|
131
131
|
import {
|
|
132
132
|
useSelfFetch
|
|
133
133
|
} from "../chunk-UC5RXT3O.js";
|
|
@@ -576,7 +576,7 @@ import {
|
|
|
576
576
|
useTimeTracker,
|
|
577
577
|
useTrackerClock,
|
|
578
578
|
useWalkthroughVideo
|
|
579
|
-
} from "../chunk-
|
|
579
|
+
} from "../chunk-PBS4F534.js";
|
|
580
580
|
import "../chunk-L2SLFCXP.js";
|
|
581
581
|
import "../chunk-BJXDHKUX.js";
|
|
582
582
|
import {
|
|
@@ -20,7 +20,9 @@ var _chunkVIAZWBZ2cjs = require('../../chunk-VIAZWBZ2.cjs');
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
var _chunkQDOBY3TPcjs = require('../../chunk-QDOBY3TP.cjs');
|
|
24
26
|
require('../../chunk-GQWM3ECA.cjs');
|
|
25
27
|
require('../../chunk-TON3YCCW.cjs');
|
|
26
28
|
|
|
@@ -77,102 +79,17 @@ var _react = require('react');
|
|
|
77
79
|
// src/hooks/use-meeting-booking.ts
|
|
78
80
|
var _reactquery = require('@tanstack/react-query');
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
|
|
83
|
+
// src/schemas/meeting-booking-schema.ts
|
|
84
|
+
var _zod = require('zod');
|
|
85
|
+
var MEETING_BOOKING_ERROR_CODES = [
|
|
81
86
|
"SLOT_TAKEN",
|
|
82
87
|
"VALIDATION",
|
|
88
|
+
"INVALID_EMAIL",
|
|
83
89
|
"LINK_GONE",
|
|
84
90
|
"TEMPORARILY_UNAVAILABLE",
|
|
85
91
|
"MEETING_UNAVAILABLE"
|
|
86
92
|
];
|
|
87
|
-
var AVAILABILITY_STALE_MS = 0;
|
|
88
|
-
function meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) {
|
|
89
|
-
return ["meeting-availability", apiBaseUrl, meetingId, monthOffset];
|
|
90
|
-
}
|
|
91
|
-
function useMeetingBooking(options) {
|
|
92
|
-
const { meetingId, apiBaseUrl = "", initialAvailability } = options;
|
|
93
|
-
const queryClient = _reactquery.useQueryClient.call(void 0, );
|
|
94
|
-
const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _2 => _2.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
|
|
95
|
-
const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
|
|
96
|
-
const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
|
|
97
|
-
setMonthOffsetState(Math.max(0, Math.min(_chunkYK7M7RBFcjs.MAX_MONTH_OFFSET, offset)));
|
|
98
|
-
}, []);
|
|
99
|
-
const prevMeetingIdRef = _react.useRef.call(void 0, meetingId);
|
|
100
|
-
_react.useLayoutEffect.call(void 0, () => {
|
|
101
|
-
if (prevMeetingIdRef.current === meetingId) return;
|
|
102
|
-
prevMeetingIdRef.current = meetingId;
|
|
103
|
-
setMonthOffsetState(0);
|
|
104
|
-
}, [meetingId]);
|
|
105
|
-
const seed = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
|
|
106
|
-
const availabilityQuery = _reactquery.useQuery.call(void 0, {
|
|
107
|
-
queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset),
|
|
108
|
-
queryFn: async ({ signal }) => {
|
|
109
|
-
const params = new URLSearchParams({ meeting: meetingId, monthOffset: String(monthOffset) });
|
|
110
|
-
const res = await _chunkTRC37VRCcjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/availability?${params}`, { signal });
|
|
111
|
-
if (!res.ok) throw new Error(`availability ${res.status}`);
|
|
112
|
-
return await res.json();
|
|
113
|
-
},
|
|
114
|
-
staleTime: AVAILABILITY_STALE_MS,
|
|
115
|
-
initialData: seed,
|
|
116
|
-
// Stamped as infinitely old on purpose: the seed is first-paint
|
|
117
|
-
// scaffolding for a 60-second-volatile resource, not truth, so it paints
|
|
118
|
-
// immediately AND is refetched immediately.
|
|
119
|
-
initialDataUpdatedAt: seed ? 0 : void 0
|
|
120
|
-
});
|
|
121
|
-
const refetchAvailability = _react.useCallback.call(void 0, async () => {
|
|
122
|
-
await queryClient.invalidateQueries({ queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) }).catch(() => void 0);
|
|
123
|
-
}, [queryClient, apiBaseUrl, meetingId, monthOffset]);
|
|
124
|
-
const bookMutation = _reactquery.useMutation.call(void 0, {
|
|
125
|
-
mutationFn: async (payload) => {
|
|
126
|
-
try {
|
|
127
|
-
const res = await _chunkTRC37VRCcjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/book`, {
|
|
128
|
-
method: "POST",
|
|
129
|
-
headers: { "Content-Type": "application/json" },
|
|
130
|
-
body: JSON.stringify(payload)
|
|
131
|
-
});
|
|
132
|
-
const data = await res.json().catch(() => ({}));
|
|
133
|
-
if (res.ok) return { ok: true, confirmation: data };
|
|
134
|
-
const rawCode = typeof data.code === "string" ? data.code : "";
|
|
135
|
-
const code = KNOWN_CODES.includes(rawCode) ? rawCode : "TEMPORARILY_UNAVAILABLE";
|
|
136
|
-
return { ok: false, code, message: typeof data.error === "string" ? data.error : void 0 };
|
|
137
|
-
} catch (e) {
|
|
138
|
-
return { ok: false, code: "TEMPORARILY_UNAVAILABLE" };
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
// A booking is not a read — never retried, at any layer.
|
|
142
|
-
retry: false
|
|
143
|
-
});
|
|
144
|
-
const submittingRef = _react.useRef.call(void 0, null);
|
|
145
|
-
const { mutateAsync } = bookMutation;
|
|
146
|
-
const book = _react.useCallback.call(void 0,
|
|
147
|
-
async (payload) => {
|
|
148
|
-
if (submittingRef.current !== null) return { ok: false, code: "VALIDATION", message: "Already submitting" };
|
|
149
|
-
const submitToken = {};
|
|
150
|
-
submittingRef.current = submitToken;
|
|
151
|
-
try {
|
|
152
|
-
return await mutateAsync(payload);
|
|
153
|
-
} finally {
|
|
154
|
-
if (submittingRef.current === submitToken) submittingRef.current = null;
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
[mutateAsync]
|
|
158
|
-
);
|
|
159
|
-
return {
|
|
160
|
-
availability: _nullishCoalesce(availabilityQuery.data, () => ( null)),
|
|
161
|
-
/** No availability for this month yet — the times column has nothing to show. */
|
|
162
|
-
isLoadingAvailability: availabilityQuery.isPending,
|
|
163
|
-
/** ANY request in flight, including a silent revalidation of cached data. */
|
|
164
|
-
isFetchingAvailability: availabilityQuery.isFetching,
|
|
165
|
-
availabilityError: availabilityQuery.error ? availabilityQuery.error.message : null,
|
|
166
|
-
monthOffset,
|
|
167
|
-
setMonthOffset,
|
|
168
|
-
refetchAvailability,
|
|
169
|
-
book,
|
|
170
|
-
isSubmitting: bookMutation.isPending
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/schemas/meeting-booking-schema.ts
|
|
175
|
-
var _zod = require('zod');
|
|
176
93
|
var SUPPORTED_FORM_FIELD_TYPES = ["text", "textarea", "select", "radio", "checkbox"];
|
|
177
94
|
function isSupportedFormField(field) {
|
|
178
95
|
return SUPPORTED_FORM_FIELD_TYPES.includes(field.type);
|
|
@@ -183,14 +100,14 @@ function isValidIanaTimezone(tz) {
|
|
|
183
100
|
try {
|
|
184
101
|
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
185
102
|
return true;
|
|
186
|
-
} catch (
|
|
103
|
+
} catch (e) {
|
|
187
104
|
return false;
|
|
188
105
|
}
|
|
189
106
|
}
|
|
190
107
|
function isValidBcp47Locale(locale) {
|
|
191
108
|
try {
|
|
192
109
|
return Intl.getCanonicalLocales(locale).length > 0;
|
|
193
|
-
} catch (
|
|
110
|
+
} catch (e2) {
|
|
194
111
|
return false;
|
|
195
112
|
}
|
|
196
113
|
}
|
|
@@ -226,7 +143,7 @@ function makeBookingSchema(formFields, legalConsent) {
|
|
|
226
143
|
}
|
|
227
144
|
answers[field.name] = validator;
|
|
228
145
|
}
|
|
229
|
-
const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess',
|
|
146
|
+
const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _2 => _2.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
|
|
230
147
|
const hasRequiredAnswers = formFields.some((f) => isSupportedFormField(f) && f.required);
|
|
231
148
|
const answersObject = _zod.z.object(answers);
|
|
232
149
|
return _zod.z.object({
|
|
@@ -259,6 +176,94 @@ function makeBookingSchema(formFields, legalConsent) {
|
|
|
259
176
|
});
|
|
260
177
|
}
|
|
261
178
|
|
|
179
|
+
// src/hooks/use-meeting-booking.ts
|
|
180
|
+
var AVAILABILITY_STALE_MS = 0;
|
|
181
|
+
function meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) {
|
|
182
|
+
return ["meeting-availability", apiBaseUrl, meetingId, monthOffset];
|
|
183
|
+
}
|
|
184
|
+
function useMeetingBooking(options) {
|
|
185
|
+
const { meetingId, apiBaseUrl = "", initialAvailability } = options;
|
|
186
|
+
const queryClient = _reactquery.useQueryClient.call(void 0, );
|
|
187
|
+
const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
|
|
188
|
+
const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
|
|
189
|
+
const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
|
|
190
|
+
setMonthOffsetState(Math.max(0, Math.min(_chunkQDOBY3TPcjs.MAX_MONTH_OFFSET, offset)));
|
|
191
|
+
}, []);
|
|
192
|
+
const prevMeetingIdRef = _react.useRef.call(void 0, meetingId);
|
|
193
|
+
_react.useLayoutEffect.call(void 0, () => {
|
|
194
|
+
if (prevMeetingIdRef.current === meetingId) return;
|
|
195
|
+
prevMeetingIdRef.current = meetingId;
|
|
196
|
+
setMonthOffsetState(0);
|
|
197
|
+
}, [meetingId]);
|
|
198
|
+
const seed = _optionalChain([initialAvailability, 'optionalAccess', _4 => _4.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
|
|
199
|
+
const availabilityQuery = _reactquery.useQuery.call(void 0, {
|
|
200
|
+
queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset),
|
|
201
|
+
queryFn: async ({ signal }) => {
|
|
202
|
+
const params = new URLSearchParams({ meeting: meetingId, monthOffset: String(monthOffset) });
|
|
203
|
+
const res = await _chunkTRC37VRCcjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/availability?${params}`, { signal });
|
|
204
|
+
if (!res.ok) throw new Error(`availability ${res.status}`);
|
|
205
|
+
return await res.json();
|
|
206
|
+
},
|
|
207
|
+
staleTime: AVAILABILITY_STALE_MS,
|
|
208
|
+
initialData: seed,
|
|
209
|
+
// Stamped as infinitely old on purpose: the seed is first-paint
|
|
210
|
+
// scaffolding for a 60-second-volatile resource, not truth, so it paints
|
|
211
|
+
// immediately AND is refetched immediately.
|
|
212
|
+
initialDataUpdatedAt: seed ? 0 : void 0
|
|
213
|
+
});
|
|
214
|
+
const refetchAvailability = _react.useCallback.call(void 0, async () => {
|
|
215
|
+
await queryClient.invalidateQueries({ queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) }).catch(() => void 0);
|
|
216
|
+
}, [queryClient, apiBaseUrl, meetingId, monthOffset]);
|
|
217
|
+
const bookMutation = _reactquery.useMutation.call(void 0, {
|
|
218
|
+
mutationFn: async (payload) => {
|
|
219
|
+
try {
|
|
220
|
+
const res = await _chunkTRC37VRCcjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/book`, {
|
|
221
|
+
method: "POST",
|
|
222
|
+
headers: { "Content-Type": "application/json" },
|
|
223
|
+
body: JSON.stringify(payload)
|
|
224
|
+
});
|
|
225
|
+
const data = await res.json().catch(() => ({}));
|
|
226
|
+
if (res.ok) return { ok: true, confirmation: data };
|
|
227
|
+
const rawCode = typeof data.code === "string" ? data.code : "";
|
|
228
|
+
const code = MEETING_BOOKING_ERROR_CODES.includes(rawCode) ? rawCode : "TEMPORARILY_UNAVAILABLE";
|
|
229
|
+
return { ok: false, code, message: typeof data.error === "string" ? data.error : void 0 };
|
|
230
|
+
} catch (e3) {
|
|
231
|
+
return { ok: false, code: "TEMPORARILY_UNAVAILABLE" };
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
// A booking is not a read — never retried, at any layer.
|
|
235
|
+
retry: false
|
|
236
|
+
});
|
|
237
|
+
const submittingRef = _react.useRef.call(void 0, null);
|
|
238
|
+
const { mutateAsync } = bookMutation;
|
|
239
|
+
const book = _react.useCallback.call(void 0,
|
|
240
|
+
async (payload) => {
|
|
241
|
+
if (submittingRef.current !== null) return { ok: false, code: "VALIDATION", message: "Already submitting" };
|
|
242
|
+
const submitToken = {};
|
|
243
|
+
submittingRef.current = submitToken;
|
|
244
|
+
try {
|
|
245
|
+
return await mutateAsync(payload);
|
|
246
|
+
} finally {
|
|
247
|
+
if (submittingRef.current === submitToken) submittingRef.current = null;
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
[mutateAsync]
|
|
251
|
+
);
|
|
252
|
+
return {
|
|
253
|
+
availability: _nullishCoalesce(availabilityQuery.data, () => ( null)),
|
|
254
|
+
/** No availability for this month yet — the times column has nothing to show. */
|
|
255
|
+
isLoadingAvailability: availabilityQuery.isPending,
|
|
256
|
+
/** ANY request in flight, including a silent revalidation of cached data. */
|
|
257
|
+
isFetchingAvailability: availabilityQuery.isFetching,
|
|
258
|
+
availabilityError: availabilityQuery.error ? availabilityQuery.error.message : null,
|
|
259
|
+
monthOffset,
|
|
260
|
+
setMonthOffset,
|
|
261
|
+
refetchAvailability,
|
|
262
|
+
book,
|
|
263
|
+
isSubmitting: bookMutation.isPending
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
262
267
|
// src/components/meeting-scheduler/booking-form.tsx
|
|
263
268
|
var _zod3 = require('@hookform/resolvers/zod');
|
|
264
269
|
|
|
@@ -311,7 +316,7 @@ function BookingForm({
|
|
|
311
316
|
const inputClass = "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-11 md:h-12";
|
|
312
317
|
const FORM_STACK = "flex flex-col gap-[var(--spacing-system-l)]";
|
|
313
318
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
|
|
314
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
319
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.HoneypotField, { ...honeypotInputProps }),
|
|
315
320
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQYQXAXVRcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _9 => _9.email, 'optionalAccess', _10 => _10.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
316
321
|
_chunkQYQXAXVRcjs.Input,
|
|
317
322
|
{
|
|
@@ -359,7 +364,7 @@ function BookingForm({
|
|
|
359
364
|
error: fieldError(field.name),
|
|
360
365
|
children: [
|
|
361
366
|
field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
362
|
-
|
|
367
|
+
_chunkQDOBY3TPcjs.Textarea,
|
|
363
368
|
{
|
|
364
369
|
id: `ms-q-${field.name}`,
|
|
365
370
|
className: "border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary",
|
|
@@ -379,11 +384,11 @@ function BookingForm({
|
|
|
379
384
|
{
|
|
380
385
|
control,
|
|
381
386
|
name: `formFields.${field.name}`,
|
|
382
|
-
render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
383
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
384
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
385
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
386
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
387
|
+
render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkQDOBY3TPcjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
|
|
388
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.SelectValue, { placeholder: "Select\u2026" }) }),
|
|
389
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.SelectItem, { value: opt, children: opt }, opt)) })
|
|
390
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.RadioGroup, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
|
|
391
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
|
|
387
392
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk3QDJLLD2cjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
|
|
388
393
|
] }, opt)) })
|
|
389
394
|
}
|
|
@@ -504,7 +509,7 @@ function ContextPanelSkeleton({
|
|
|
504
509
|
backLabel = "Back"
|
|
505
510
|
}) {
|
|
506
511
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkPRPZBXWZcjs.cn.call(void 0, PANEL_STACK, className), children: [
|
|
507
|
-
onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
512
|
+
onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
|
|
508
513
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
|
|
509
514
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: STRIP_MAIN, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
|
|
510
515
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xs)] lg:flex-none", children: [
|
|
@@ -551,7 +556,7 @@ function SchedulerContextPanel({
|
|
|
551
556
|
return zones.map((tz) => ({ value: tz, label: zoneLabel(tz) }));
|
|
552
557
|
}, [timezone]);
|
|
553
558
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkPRPZBXWZcjs.cn.call(void 0, PANEL_STACK, className), children: [
|
|
554
|
-
onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
559
|
+
onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
|
|
555
560
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
|
|
556
561
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_MAIN, children: [
|
|
557
562
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
|
|
@@ -612,7 +617,7 @@ function SchedulerContextPanel({
|
|
|
612
617
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkPRPZBXWZcjs.cn.call(void 0, STRIP_ASIDE, locked && "max-lg:hidden"), children: [
|
|
613
618
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Timezone" }),
|
|
614
619
|
timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
615
|
-
|
|
620
|
+
_chunkQDOBY3TPcjs.Autocomplete,
|
|
616
621
|
{
|
|
617
622
|
value: timezone,
|
|
618
623
|
onChange: (tz) => {
|
|
@@ -698,18 +703,18 @@ var NOOP = () => void 0;
|
|
|
698
703
|
function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDay, slotsByDay }) {
|
|
699
704
|
const now = /* @__PURE__ */ new Date();
|
|
700
705
|
const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
701
|
-
const endMonth = new Date(now.getFullYear(), now.getMonth() +
|
|
706
|
+
const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkQDOBY3TPcjs.MAX_MONTH_OFFSET + 1, 0);
|
|
702
707
|
const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
|
|
703
708
|
const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _22 => _22.has, 'call', _23 => _23(calendarDayKey(day))]), [slotsByDay]);
|
|
704
709
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-h-0 flex-1 flex-col", "aria-busy": slotsByDay === null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
705
|
-
|
|
710
|
+
_chunkQDOBY3TPcjs.DatePickerCalendar,
|
|
706
711
|
{
|
|
707
712
|
mode: "single",
|
|
708
713
|
bare: true,
|
|
709
714
|
month: visibleMonth,
|
|
710
715
|
onMonthChange: (month) => {
|
|
711
716
|
const offset = (month.getFullYear() - now.getFullYear()) * 12 + (month.getMonth() - now.getMonth());
|
|
712
|
-
onMonthOffsetChange(Math.max(0, Math.min(
|
|
717
|
+
onMonthOffsetChange(Math.max(0, Math.min(_chunkQDOBY3TPcjs.MAX_MONTH_OFFSET, offset)));
|
|
713
718
|
},
|
|
714
719
|
fromDate: startMonth,
|
|
715
720
|
toDate: endMonth,
|
|
@@ -823,7 +828,7 @@ function SlotPicker({
|
|
|
823
828
|
monthLabelFor(monthOffset),
|
|
824
829
|
"."
|
|
825
830
|
] }),
|
|
826
|
-
monthOffset <
|
|
831
|
+
monthOffset < _chunkQDOBY3TPcjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
827
832
|
_chunkS6LZN66Dcjs.Button,
|
|
828
833
|
{
|
|
829
834
|
variant: "outline",
|
|
@@ -1001,6 +1006,13 @@ function MeetingSchedulerDirectory({
|
|
|
1001
1006
|
|
|
1002
1007
|
// src/components/meeting-scheduler/index.tsx
|
|
1003
1008
|
|
|
1009
|
+
var BOOKING_ERROR_COPY = {
|
|
1010
|
+
INVALID_EMAIL: "That email address was rejected by our scheduling system \u2014 please use a real, reachable address (work email works best).",
|
|
1011
|
+
VALIDATION: "Please double-check your details \u2014 especially that the email address is real and reachable \u2014 and try again.",
|
|
1012
|
+
TEMPORARILY_UNAVAILABLE: "Scheduling is briefly unavailable \u2014 please try again in a minute.",
|
|
1013
|
+
MEETING_UNAVAILABLE: "This meeting type has reached its booking limit for today \u2014 try another time or contact us.",
|
|
1014
|
+
LINK_GONE: "This meeting type is no longer available."
|
|
1015
|
+
};
|
|
1004
1016
|
var CONTEXT_PANEL_CLASS = "p-[var(--spacing-system-l)] shrink-0 lg:w-[280px] border-b lg:border-b-0 lg:border-r border-ods-border lg:min-h-0 lg:overflow-y-auto";
|
|
1005
1017
|
var ACTION_PANEL_CLASS = "flex-1 min-w-0 flex flex-col md:min-h-0 lg:p-[var(--spacing-system-l)]";
|
|
1006
1018
|
var PANEL_STEP_CLASS = "p-[var(--spacing-system-l)] md:min-h-0 md:overflow-y-auto lg:p-0";
|
|
@@ -1189,8 +1201,8 @@ function HubSpotMeetingScheduler({
|
|
|
1189
1201
|
"\xB7 ",
|
|
1190
1202
|
_chunkSPAAKHQAcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
|
|
1191
1203
|
] }),
|
|
1192
|
-
bookingError && bookingError !== "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "
|
|
1193
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1204
|
+
bookingError && bookingError !== "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkQDOBY3TPcjs.Alert, { variant: "error", className: "flex flex-col items-start gap-[var(--spacing-system-xs)]", children: [
|
|
1205
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.AlertDescription, { children: _nullishCoalesce(BOOKING_ERROR_COPY[bookingError], () => ( BOOKING_ERROR_COPY.VALIDATION)) }),
|
|
1194
1206
|
escapeHatch
|
|
1195
1207
|
] }),
|
|
1196
1208
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -1208,7 +1220,14 @@ function HubSpotMeetingScheduler({
|
|
|
1208
1220
|
}
|
|
1209
1221
|
)
|
|
1210
1222
|
] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-m)] md:min-h-0 md:flex-1", children: [
|
|
1211
|
-
bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1223
|
+
bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1224
|
+
_chunkQDOBY3TPcjs.Alert,
|
|
1225
|
+
{
|
|
1226
|
+
variant: "warning",
|
|
1227
|
+
className: "mx-[var(--spacing-system-l)] mt-[var(--spacing-system-l)] w-auto lg:m-0 lg:w-full",
|
|
1228
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQDOBY3TPcjs.AlertDescription, { children: "That time was just taken \u2014 pick another slot below. (If you already submitted, check your email for a confirmation before rebooking.)" })
|
|
1229
|
+
}
|
|
1230
|
+
),
|
|
1212
1231
|
timezone && durationMs != null ? (
|
|
1213
1232
|
// The picker owns BOTH the loading and the empty month now —
|
|
1214
1233
|
// it keeps the calendar up either way, so there is no branch
|