@flamingo-stack/openframe-frontend-core 0.0.574-snapshot.20260827223923 → 0.0.574

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.
@@ -79,104 +79,13 @@ var _react = require('react');
79
79
  // src/hooks/use-meeting-booking.ts
80
80
  var _reactquery = require('@tanstack/react-query');
81
81
 
82
-
83
- // src/schemas/meeting-booking-schema.ts
84
- var _zod = require('zod');
85
- var MEETING_BOOKING_ERROR_CODES = [
82
+ var KNOWN_CODES = [
86
83
  "SLOT_TAKEN",
87
84
  "VALIDATION",
88
- "INVALID_EMAIL",
89
85
  "LINK_GONE",
90
86
  "TEMPORARILY_UNAVAILABLE",
91
87
  "MEETING_UNAVAILABLE"
92
88
  ];
93
- var SUPPORTED_FORM_FIELD_TYPES = ["text", "textarea", "select", "radio", "checkbox"];
94
- function isSupportedFormField(field) {
95
- return SUPPORTED_FORM_FIELD_TYPES.includes(field.type);
96
- }
97
- var IANA_TZ_RE = /^(?:UTC|[A-Za-z_]+(?:\/[A-Za-z0-9_+-]+)+)$/;
98
- function isValidIanaTimezone(tz) {
99
- if (!IANA_TZ_RE.test(tz)) return false;
100
- try {
101
- new Intl.DateTimeFormat("en-US", { timeZone: tz });
102
- return true;
103
- } catch (e) {
104
- return false;
105
- }
106
- }
107
- function isValidBcp47Locale(locale) {
108
- try {
109
- return Intl.getCanonicalLocales(locale).length > 0;
110
- } catch (e2) {
111
- return false;
112
- }
113
- }
114
- function makeBookingSchema(formFields, legalConsent) {
115
- const answers = {};
116
- for (const field of formFields) {
117
- if (!isSupportedFormField(field)) continue;
118
- let validator;
119
- switch (field.type) {
120
- case "checkbox":
121
- validator = _zod.z.boolean();
122
- break;
123
- case "select":
124
- case "radio":
125
- validator = _zod.z.string().refine((v) => !v || (_nullishCoalesce(field.options, () => ( []))).includes(v), {
126
- message: `Please choose a valid option for ${field.label}`
127
- });
128
- break;
129
- case "textarea":
130
- validator = _zod.z.string().max(5e3, { message: `${field.label} is too long` });
131
- break;
132
- case "text":
133
- default:
134
- validator = _zod.z.string().max(1e3, { message: `${field.label} is too long` });
135
- break;
136
- }
137
- if (field.required) {
138
- validator = field.type === "checkbox" ? _zod.z.literal(true, { message: `${field.label} is required` }) : validator.min(1, { message: `${field.label} is required` });
139
- } else if (field.type !== "checkbox") {
140
- validator = validator.optional().or(_zod.z.literal(""));
141
- } else {
142
- validator = _zod.z.boolean().optional();
143
- }
144
- answers[field.name] = validator;
145
- }
146
- const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _2 => _2.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
147
- const hasRequiredAnswers = formFields.some((f) => isSupportedFormField(f) && f.required);
148
- const answersObject = _zod.z.object(answers);
149
- return _zod.z.object({
150
- meetingId: _zod.z.string().min(1),
151
- startTimeMs: _zod.z.number().int().positive(),
152
- durationMs: _zod.z.number().int().positive(),
153
- firstName: _zod.z.string().min(1, { message: "First name is required" }).max(255),
154
- lastName: _zod.z.string().min(1, { message: "Last name is required" }).max(255),
155
- email: _zod.z.string().email({ message: "Please enter a valid email address" }).max(255),
156
- timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }),
157
- locale: _zod.z.string().refine(isValidBcp47Locale, { message: "Invalid locale" }).optional(),
158
- // Plain `.optional()` (no `.default()`) so zod's input and output types
159
- // match — react-hook-form's zodResolver needs them identical, and the
160
- // server handles `undefined` explicitly anyway. REQUIRED when the link
161
- // declares required questions (see `hasRequiredAnswers` above).
162
- formFields: hasRequiredAnswers ? answersObject : answersObject.optional(),
163
- legalConsentResponses: _zod.z.array(_zod.z.object({ communicationTypeId: _zod.z.string(), consented: _zod.z.boolean() })).optional()
164
- }).superRefine((data, ctx) => {
165
- const responses = _nullishCoalesce(data.legalConsentResponses, () => ( []));
166
- const ok = requiredConsentIds.every(
167
- (id) => responses.some((r) => r.communicationTypeId === id && r.consented === true)
168
- );
169
- if (!ok) {
170
- ctx.addIssue({
171
- code: _zod.z.ZodIssueCode.custom,
172
- path: ["legalConsentResponses"],
173
- message: "Required consent checkboxes must be accepted"
174
- });
175
- }
176
- });
177
- }
178
-
179
- // src/hooks/use-meeting-booking.ts
180
89
  var AVAILABILITY_STALE_MS = 0;
181
90
  function meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) {
182
91
  return ["meeting-availability", apiBaseUrl, meetingId, monthOffset];
@@ -184,7 +93,7 @@ function meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) {
184
93
  function useMeetingBooking(options) {
185
94
  const { meetingId, apiBaseUrl = "", initialAvailability } = options;
186
95
  const queryClient = _reactquery.useQueryClient.call(void 0, );
187
- const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
96
+ const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _2 => _2.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
188
97
  const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
189
98
  const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
190
99
  setMonthOffsetState(Math.max(0, Math.min(_chunkQDOBY3TPcjs.MAX_MONTH_OFFSET, offset)));
@@ -195,7 +104,7 @@ function useMeetingBooking(options) {
195
104
  prevMeetingIdRef.current = meetingId;
196
105
  setMonthOffsetState(0);
197
106
  }, [meetingId]);
198
- const seed = _optionalChain([initialAvailability, 'optionalAccess', _4 => _4.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
107
+ const seed = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
199
108
  const availabilityQuery = _reactquery.useQuery.call(void 0, {
200
109
  queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset),
201
110
  queryFn: async ({ signal }) => {
@@ -225,9 +134,9 @@ function useMeetingBooking(options) {
225
134
  const data = await res.json().catch(() => ({}));
226
135
  if (res.ok) return { ok: true, confirmation: data };
227
136
  const rawCode = typeof data.code === "string" ? data.code : "";
228
- const code = MEETING_BOOKING_ERROR_CODES.includes(rawCode) ? rawCode : "TEMPORARILY_UNAVAILABLE";
137
+ const code = KNOWN_CODES.includes(rawCode) ? rawCode : "TEMPORARILY_UNAVAILABLE";
229
138
  return { ok: false, code, message: typeof data.error === "string" ? data.error : void 0 };
230
- } catch (e3) {
139
+ } catch (e) {
231
140
  return { ok: false, code: "TEMPORARILY_UNAVAILABLE" };
232
141
  }
233
142
  },
@@ -264,6 +173,94 @@ function useMeetingBooking(options) {
264
173
  };
265
174
  }
266
175
 
176
+ // src/schemas/meeting-booking-schema.ts
177
+ var _zod = require('zod');
178
+ var SUPPORTED_FORM_FIELD_TYPES = ["text", "textarea", "select", "radio", "checkbox"];
179
+ function isSupportedFormField(field) {
180
+ return SUPPORTED_FORM_FIELD_TYPES.includes(field.type);
181
+ }
182
+ var IANA_TZ_RE = /^(?:UTC|[A-Za-z_]+(?:\/[A-Za-z0-9_+-]+)+)$/;
183
+ function isValidIanaTimezone(tz) {
184
+ if (!IANA_TZ_RE.test(tz)) return false;
185
+ try {
186
+ new Intl.DateTimeFormat("en-US", { timeZone: tz });
187
+ return true;
188
+ } catch (e2) {
189
+ return false;
190
+ }
191
+ }
192
+ function isValidBcp47Locale(locale) {
193
+ try {
194
+ return Intl.getCanonicalLocales(locale).length > 0;
195
+ } catch (e3) {
196
+ return false;
197
+ }
198
+ }
199
+ function makeBookingSchema(formFields, legalConsent) {
200
+ const answers = {};
201
+ for (const field of formFields) {
202
+ if (!isSupportedFormField(field)) continue;
203
+ let validator;
204
+ switch (field.type) {
205
+ case "checkbox":
206
+ validator = _zod.z.boolean();
207
+ break;
208
+ case "select":
209
+ case "radio":
210
+ validator = _zod.z.string().refine((v) => !v || (_nullishCoalesce(field.options, () => ( []))).includes(v), {
211
+ message: `Please choose a valid option for ${field.label}`
212
+ });
213
+ break;
214
+ case "textarea":
215
+ validator = _zod.z.string().max(5e3, { message: `${field.label} is too long` });
216
+ break;
217
+ case "text":
218
+ default:
219
+ validator = _zod.z.string().max(1e3, { message: `${field.label} is too long` });
220
+ break;
221
+ }
222
+ if (field.required) {
223
+ validator = field.type === "checkbox" ? _zod.z.literal(true, { message: `${field.label} is required` }) : validator.min(1, { message: `${field.label} is required` });
224
+ } else if (field.type !== "checkbox") {
225
+ validator = validator.optional().or(_zod.z.literal(""));
226
+ } else {
227
+ validator = _zod.z.boolean().optional();
228
+ }
229
+ answers[field.name] = validator;
230
+ }
231
+ const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _4 => _4.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
232
+ const hasRequiredAnswers = formFields.some((f) => isSupportedFormField(f) && f.required);
233
+ const answersObject = _zod.z.object(answers);
234
+ return _zod.z.object({
235
+ meetingId: _zod.z.string().min(1),
236
+ startTimeMs: _zod.z.number().int().positive(),
237
+ durationMs: _zod.z.number().int().positive(),
238
+ firstName: _zod.z.string().min(1, { message: "First name is required" }).max(255),
239
+ lastName: _zod.z.string().min(1, { message: "Last name is required" }).max(255),
240
+ email: _zod.z.string().email({ message: "Please enter a valid email address" }).max(255),
241
+ timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }),
242
+ locale: _zod.z.string().refine(isValidBcp47Locale, { message: "Invalid locale" }).optional(),
243
+ // Plain `.optional()` (no `.default()`) so zod's input and output types
244
+ // match — react-hook-form's zodResolver needs them identical, and the
245
+ // server handles `undefined` explicitly anyway. REQUIRED when the link
246
+ // declares required questions (see `hasRequiredAnswers` above).
247
+ formFields: hasRequiredAnswers ? answersObject : answersObject.optional(),
248
+ legalConsentResponses: _zod.z.array(_zod.z.object({ communicationTypeId: _zod.z.string(), consented: _zod.z.boolean() })).optional()
249
+ }).superRefine((data, ctx) => {
250
+ const responses = _nullishCoalesce(data.legalConsentResponses, () => ( []));
251
+ const ok = requiredConsentIds.every(
252
+ (id) => responses.some((r) => r.communicationTypeId === id && r.consented === true)
253
+ );
254
+ if (!ok) {
255
+ ctx.addIssue({
256
+ code: _zod.z.ZodIssueCode.custom,
257
+ path: ["legalConsentResponses"],
258
+ message: "Required consent checkboxes must be accepted"
259
+ });
260
+ }
261
+ });
262
+ }
263
+
267
264
  // src/components/meeting-scheduler/booking-form.tsx
268
265
  var _zod3 = require('@hookform/resolvers/zod');
269
266