@wix/headless-restaurants-olo 0.0.33 → 0.0.35

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.
Files changed (59) hide show
  1. package/cjs/dist/react/FulfillmentDetails.d.ts +139 -15
  2. package/cjs/dist/react/FulfillmentDetails.js +128 -24
  3. package/cjs/dist/react/ItemDetails.d.ts +4 -4
  4. package/cjs/dist/react/ItemDetails.js +5 -6
  5. package/cjs/dist/react/Settings.d.ts +8 -0
  6. package/cjs/dist/react/Settings.js +18 -25
  7. package/cjs/dist/react/core/FulfillmentDetails.d.ts +73 -7
  8. package/cjs/dist/react/core/FulfillmentDetails.js +133 -86
  9. package/cjs/dist/react/core/ItemDetails.d.ts +1 -1
  10. package/cjs/dist/react/core/ItemDetails.js +5 -16
  11. package/cjs/dist/react/core/Settings.d.ts +19 -4
  12. package/cjs/dist/react/core/Settings.js +29 -20
  13. package/cjs/dist/services/fulfillment-details-service.d.ts +127 -0
  14. package/cjs/dist/services/fulfillment-details-service.js +351 -0
  15. package/cjs/dist/services/fulfillments-service.js +67 -43
  16. package/cjs/dist/services/index.d.ts +2 -0
  17. package/cjs/dist/services/index.js +1 -0
  18. package/cjs/dist/services/item-details-service.d.ts +1 -1
  19. package/cjs/dist/services/item-details-service.js +10 -16
  20. package/cjs/dist/services/olo-settings-service.d.ts +0 -1
  21. package/cjs/dist/services/olo-settings-service.js +1 -3
  22. package/cjs/dist/services/utils.d.ts +4 -0
  23. package/cjs/dist/services/utils.js +12 -0
  24. package/cjs/dist/types/fulfillments-types.d.ts +18 -1
  25. package/cjs/dist/types/fulfillments-types.js +9 -0
  26. package/cjs/dist/utils/date-utils.d.ts +164 -0
  27. package/cjs/dist/utils/date-utils.js +297 -0
  28. package/cjs/dist/utils/fulfillments-utils.d.ts +3 -2
  29. package/cjs/dist/utils/fulfillments-utils.js +13 -57
  30. package/dist/react/FulfillmentDetails.d.ts +139 -15
  31. package/dist/react/FulfillmentDetails.js +128 -24
  32. package/dist/react/ItemDetails.d.ts +4 -4
  33. package/dist/react/ItemDetails.js +5 -6
  34. package/dist/react/Settings.d.ts +8 -0
  35. package/dist/react/Settings.js +18 -25
  36. package/dist/react/core/FulfillmentDetails.d.ts +73 -7
  37. package/dist/react/core/FulfillmentDetails.js +133 -86
  38. package/dist/react/core/ItemDetails.d.ts +1 -1
  39. package/dist/react/core/ItemDetails.js +5 -16
  40. package/dist/react/core/Settings.d.ts +19 -4
  41. package/dist/react/core/Settings.js +29 -20
  42. package/dist/services/fulfillment-details-service.d.ts +127 -0
  43. package/dist/services/fulfillment-details-service.js +351 -0
  44. package/dist/services/fulfillments-service.js +67 -43
  45. package/dist/services/index.d.ts +2 -0
  46. package/dist/services/index.js +1 -0
  47. package/dist/services/item-details-service.d.ts +1 -1
  48. package/dist/services/item-details-service.js +10 -16
  49. package/dist/services/olo-settings-service.d.ts +0 -1
  50. package/dist/services/olo-settings-service.js +1 -3
  51. package/dist/services/utils.d.ts +4 -0
  52. package/dist/services/utils.js +12 -0
  53. package/dist/types/fulfillments-types.d.ts +18 -1
  54. package/dist/types/fulfillments-types.js +9 -0
  55. package/dist/utils/date-utils.d.ts +164 -0
  56. package/dist/utils/date-utils.js +297 -0
  57. package/dist/utils/fulfillments-utils.d.ts +3 -2
  58. package/dist/utils/fulfillments-utils.js +13 -57
  59. package/package.json +3 -2
@@ -1,7 +1,11 @@
1
1
  import * as operationsSDK from '@wix/auto_sdk_restaurants_operations';
2
2
  import { DispatchType, } from '../types/fulfillments-types.js';
3
- import { EntitiesDayOfWeek as DayOfWeek, } from '@wix/auto_sdk_restaurants_fulfillment-methods';
4
3
  import { FulfillmentTimeType, } from '@wix/auto_sdk_restaurants_operations';
4
+ import { DAY_OF_WEEK, isInTimeRange, getDayOfWeekNumber, getLocale, convertDateToTimezone, } from './date-utils.js';
5
+ // Re-export date utilities for convenience
6
+ export { convertTimeOfDayToDateTime, convertDateToTimezone, formatDateInTimezone, formatTime, formatTimeRange, getDatePartsInTimezone, buildDateFromParts, isInTimeRange, DAY_OF_WEEK, DayOfWeek, getDayOfWeekNumber,
7
+ // Locale & timezone utilities
8
+ getLocale, getTimezone, } from './date-utils.js';
5
9
  /**
6
10
  * Format a string with placeholders like {0}, {1}, etc.
7
11
  * Similar to C#'s String.Format
@@ -150,6 +154,8 @@ export const processFulfillmentTimeSlotByOperationList = (operationTimeSlot) =>
150
154
  durationRangeOptions: selectedFulfillmentInfo?.durationRange,
151
155
  ...selectedFulfillmentInfo,
152
156
  };
157
+ // const startTime = convertTimeOfDayToDateTime(startTime!, timezone);
158
+ // const endTime = convertTimeOfDayToDateTime(endTime!, timezone);
153
159
  return {
154
160
  id: createTimeSlotId(startTime, endTime),
155
161
  startTime: startTime,
@@ -163,71 +169,22 @@ export const processFulfillmentTimeSlotByOperationList = (operationTimeSlot) =>
163
169
  }),
164
170
  ];
165
171
  };
166
- const DAY_OF_WEEK = {
167
- [DayOfWeek.MON]: 1,
168
- [DayOfWeek.TUE]: 2,
169
- [DayOfWeek.WED]: 3,
170
- [DayOfWeek.THU]: 4,
171
- [DayOfWeek.FRI]: 5,
172
- [DayOfWeek.SAT]: 6,
173
- [DayOfWeek.SUN]: 7,
174
- };
175
- const convertTimeOfDayToDateTime = (time, timezone) => {
176
- const now = new Date();
177
- if (timezone) {
178
- // Get today's date components in the specified timezone
179
- const options = {
180
- timeZone: timezone,
181
- year: 'numeric',
182
- month: '2-digit',
183
- day: '2-digit',
184
- };
185
- const parts = new Intl.DateTimeFormat('en-US', options).formatToParts(now);
186
- const year = parts.find((p) => p.type === 'year')?.value;
187
- const month = parts.find((p) => p.type === 'month')?.value;
188
- const day = parts.find((p) => p.type === 'day')?.value;
189
- // Create an ISO string with the date in the timezone and the specified time
190
- const hours = String(time.hours ?? 0).padStart(2, '0');
191
- const minutes = String(time.minutes ?? 0).padStart(2, '0');
192
- const isoString = `${year}-${month}-${day}T${hours}:${minutes}:00.000`;
193
- // Convert to Date - this will be interpreted as local time
194
- const localDate = new Date(isoString);
195
- // Get what this time would be formatted as in the target timezone
196
- const formattedInTz = new Date(localDate.toLocaleString('en-US', { timeZone: timezone }));
197
- // Calculate the difference and adjust
198
- const offset = localDate.getTime() - formattedInTz.getTime();
199
- return new Date(localDate.getTime() + offset);
200
- }
201
- // If no timezone specified, use local time
202
- const date = new Date();
203
- date.setHours(time.hours ?? 0, time.minutes ?? 0, 0, 0);
204
- return date;
205
- };
206
- const isInTimeRange = (time, range, timeZone) => {
207
- const startTime = range.startTime
208
- ? convertTimeOfDayToDateTime(range.startTime, timeZone)
209
- : time;
210
- const endTime = range.endTime
211
- ? convertTimeOfDayToDateTime(range.endTime, timeZone)
212
- : time;
213
- return (time.getTime() >= startTime.getTime() && time.getTime() <= endTime.getTime());
214
- };
215
172
  const isFulfillmentAvailable = (fulfillment, operation) => {
216
173
  const { availability: { timeZone, availableTimes } = {} } = fulfillment;
217
174
  const { asapOptions: { maxInMinutes, rangeInMinutes } = {} } = operation;
218
175
  const deliveryTime = fulfillment.deliveryOptions?.deliveryTimeInMinutes ?? 0;
219
- const zone = timeZone;
220
- const timeNow = new Date();
176
+ const timezone = timeZone;
177
+ const locale = getLocale();
178
+ const timeNow = convertDateToTimezone(new Date(), timezone, locale);
221
179
  timeNow.setMinutes(timeNow.getMinutes() +
222
180
  (maxInMinutes ?? rangeInMinutes?.min ?? 0) +
223
181
  deliveryTime);
224
- // getDay() returns 0 (Sunday) to 6 (Saturday), but we need 1 (Monday) to 7 (Sunday)
225
- const currentDayOfWeek = timeNow.getDay() === 0 ? 7 : timeNow.getDay();
182
+ const currentDayOfWeek = getDayOfWeekNumber(timeNow);
226
183
  return !!availableTimes?.some((availableTime) => {
227
184
  const { dayOfWeek, timeRanges } = availableTime;
228
185
  const dayOfWeekNumber = DAY_OF_WEEK[dayOfWeek];
229
186
  const isAvailable = dayOfWeekNumber === currentDayOfWeek &&
230
- !!timeRanges?.some((range) => isInTimeRange(timeNow, range, zone));
187
+ !!timeRanges?.some((range) => isInTimeRange(timeNow, range, timezone));
231
188
  return isAvailable;
232
189
  });
233
190
  };
@@ -291,10 +248,9 @@ export const createTimeRange = (arr) => {
291
248
  return { durationRangeOptions: { minDuration, maxDuration } };
292
249
  }
293
250
  };
294
- export const processFulfillments = async (fulfillments, timeSlots, operation) => {
251
+ export const processFulfillments = (fulfillments, timeSlots, operation) => {
295
252
  const shouldConsiderAvailability = timeSlots.length > 0;
296
253
  try {
297
- console.log('fulfillments :>>', fulfillments);
298
254
  const pickupFulfillment = fulfillments.find((fulfillment) => fulfillment.type === 'PICKUP' && fulfillment.enabled);
299
255
  let deliveryFulfillments = fulfillments.filter((fulfillment) => fulfillment.type === 'DELIVERY' && fulfillment.enabled);
300
256
  const isPickupConfigured = !!pickupFulfillment;
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { CoreFulfillmentDetails } from './core/index.js';
3
- import { DispatchType } from '../types/fulfillments-types.js';
2
+ import { DispatchType, FulfillmentTypeEnum } from '../types/fulfillments-types.js';
4
3
  import { AsChildChildren } from '@wix/headless-utils/react';
5
4
  interface TimeSlotContextValue {
6
5
  timeSlots: Array<{
@@ -67,6 +66,12 @@ export declare const AddressName: React.ForwardRefExoticComponent<AddressNamePro
67
66
  interface FulfillmentDateProps extends Omit<React.ComponentPropsWithoutRef<'input'>, 'children' | 'type' | 'value' | 'onChange' | 'min' | 'max'> {
68
67
  /** Whether to render as a child component */
69
68
  asChild?: boolean;
69
+ /** Optional label text or element for the date picker */
70
+ label?: React.ReactNode;
71
+ /** Optional class name for the label element */
72
+ labelClassName?: string;
73
+ /** Optional class name for the wrapper div (only rendered when label is provided) */
74
+ wrapperClassName?: string;
70
75
  /** Optional children render prop that receives the date picker props */
71
76
  children?: AsChildChildren<{
72
77
  selectedDate: Date | null;
@@ -87,15 +92,23 @@ interface FulfillmentDateProps extends Omit<React.ComponentPropsWithoutRef<'inpu
87
92
  * // With custom class name
88
93
  * <FulfillmentDetails.FulfillmentDate className="my-date-input" />
89
94
  *
95
+ * // With label
96
+ * <FulfillmentDetails.FulfillmentDate
97
+ * label="Date"
98
+ * labelClassName="block mb-1 text-sm"
99
+ * wrapperClassName="flex-1"
100
+ * className="my-date-input"
101
+ * />
102
+ *
90
103
  * // Using asChild pattern
91
104
  * <FulfillmentDetails.FulfillmentDate asChild>
92
105
  * {({ selectedDate, onDateChange, minDate, maxDate }) => (
93
106
  * <input
94
107
  * type="date"
95
- * value={selectedDate?.toISOString().split('T')[0]}
108
+ * value={selectedDate ? toISODateString(selectedDate) : ''}
96
109
  * onChange={(e) => onDateChange(new Date(e.target.value))}
97
- * min={minDate.toISOString().split('T')[0]}
98
- * max={maxDate.toISOString().split('T')[0]}
110
+ * min={toISODateString(minDate)}
111
+ * max={toISODateString(maxDate)}
99
112
  * />
100
113
  * )}
101
114
  * </FulfillmentDetails.FulfillmentDate>
@@ -191,22 +204,50 @@ interface TimeSlotOptionRepeaterProps {
191
204
  * ```
192
205
  */
193
206
  export declare const TimeSlotOptionRepeater: React.FC<TimeSlotOptionRepeaterProps>;
194
- export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
195
- interface FulfillmentTypeProps {
207
+ interface FulfillmentTypeProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
208
+ /** Whether to render as a child component */
209
+ asChild?: boolean;
210
+ /** Label text for the ASAP option */
211
+ asapLabel?: string;
212
+ /** Label text for the schedule for later (preorder) option */
213
+ scheduleLabel?: string;
214
+ /** Aria label for the radio group */
215
+ groupAriaLabel?: string;
216
+ /** Template text for ASAP time display (e.g., "Ready in {0} min"). Use {0} for asapTime placeholder */
217
+ asapTimeText?: string;
218
+ /** Optional class name for the radio input elements */
219
+ inputClassName?: string;
196
220
  /** Children render prop that receives the fulfillment type selection props */
197
- children: (props: {
198
- selectedType: CoreFulfillmentDetails.FulfillmentTypeEnum;
199
- onTypeChange: (type: CoreFulfillmentDetails.FulfillmentTypeEnum) => void;
221
+ children?: AsChildChildren<{
222
+ selectedType: FulfillmentTypeEnum;
223
+ onTypeChange: (type: FulfillmentTypeEnum) => void;
200
224
  hasAsapOption: boolean;
201
225
  hasPreorderOption: boolean;
202
- }) => React.ReactNode;
226
+ asapTime: number | undefined;
227
+ asapTimeRange: {
228
+ minDuration?: number;
229
+ maxDuration?: number;
230
+ } | undefined;
231
+ }> | React.ReactNode;
203
232
  }
204
233
  /**
205
- * Headless component for fulfillment type selection (ASAP or Pre-order)
234
+ * Headless component for fulfillment type selection (ASAP or Schedule for later)
235
+ * Provides radio button functionality with default rendering
206
236
  *
207
237
  * @example
208
238
  * ```tsx
209
- * <FulfillmentDetails.FulfillmentType>
239
+ * // Default usage - renders radio buttons
240
+ * <FulfillmentDetails.FulfillmentType />
241
+ *
242
+ * // With custom labels
243
+ * <FulfillmentDetails.FulfillmentType
244
+ * asapLabel="Now"
245
+ * scheduleLabel="Later"
246
+ * groupAriaLabel="When do you want your order?"
247
+ * />
248
+ *
249
+ * // Using asChild pattern
250
+ * <FulfillmentDetails.FulfillmentType asChild>
210
251
  * {({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption }) => (
211
252
  * <div>
212
253
  * {hasAsapOption && (
@@ -222,7 +263,7 @@ interface FulfillmentTypeProps {
222
263
  * onClick={() => onTypeChange(FulfillmentTypeEnum.PREORDER)}
223
264
  * data-selected={selectedType === FulfillmentTypeEnum.PREORDER}
224
265
  * >
225
- * Pre-order
266
+ * Schedule for later
226
267
  * </button>
227
268
  * )}
228
269
  * </div>
@@ -230,4 +271,87 @@ interface FulfillmentTypeProps {
230
271
  * </FulfillmentDetails.FulfillmentType>
231
272
  * ```
232
273
  */
233
- export declare const FulfillmentType: React.FC<FulfillmentTypeProps>;
274
+ export declare const FulfillmentType: React.ForwardRefExoticComponent<FulfillmentTypeProps & React.RefAttributes<HTMLDivElement>>;
275
+ /**
276
+ * Address fields that can be updated
277
+ */
278
+ export interface DeliveryAddressFields {
279
+ /** Street address line 1 */
280
+ addressLine?: string;
281
+ /** Street address line 2 (apartment, suite, etc.) */
282
+ addressLine2?: string;
283
+ /** City */
284
+ city?: string;
285
+ /** State/Province/Subdivision */
286
+ subdivision?: string;
287
+ /** Postal/ZIP code */
288
+ postalCode?: string;
289
+ /** Country */
290
+ country?: string;
291
+ /** Formatted full address string */
292
+ formattedAddress?: string;
293
+ }
294
+ interface DeliveryAddressProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
295
+ /** Whether to render as a child component */
296
+ asChild?: boolean;
297
+ /** Label text for the address input */
298
+ label?: React.ReactNode;
299
+ /** Optional class name for the label element */
300
+ labelClassName?: string;
301
+ /** Optional class name for the wrapper div (only rendered when label is provided) */
302
+ wrapperClassName?: string;
303
+ /** Placeholder text for the address input */
304
+ placeholder?: string;
305
+ /** Optional class name for the input element */
306
+ inputClassName?: string;
307
+ /** Children render prop that receives the address data */
308
+ children?: AsChildChildren<{
309
+ address: DeliveryAddressFields | null;
310
+ hasAddress: boolean;
311
+ isDelivery: boolean;
312
+ dispatchType: DispatchType | null;
313
+ onAddressChange: (address: DeliveryAddressFields) => void;
314
+ onAddressClear: () => void;
315
+ }> | React.ReactNode;
316
+ }
317
+ /**
318
+ * Headless component for editing the delivery address
319
+ * Only renders when dispatch type is DELIVERY
320
+ *
321
+ * @example
322
+ * ```tsx
323
+ * // Default usage - renders input for address line
324
+ * <FulfillmentDetails.DeliveryAddress
325
+ * label="Delivery Address"
326
+ * placeholder="Enter your address"
327
+ * />
328
+ *
329
+ * // Using asChild pattern for custom rendering
330
+ * <FulfillmentDetails.DeliveryAddress asChild>
331
+ * {({ address, hasAddress, isDelivery, onAddressChange, onAddressClear }) => (
332
+ * isDelivery && (
333
+ * <div>
334
+ * <input
335
+ * value={address?.addressLine || ''}
336
+ * onChange={(e) => onAddressChange({ ...address, addressLine: e.target.value })}
337
+ * placeholder="Street Address"
338
+ * />
339
+ * <input
340
+ * value={address?.city || ''}
341
+ * onChange={(e) => onAddressChange({ ...address, city: e.target.value })}
342
+ * placeholder="City"
343
+ * />
344
+ * <input
345
+ * value={address?.postalCode || ''}
346
+ * onChange={(e) => onAddressChange({ ...address, postalCode: e.target.value })}
347
+ * placeholder="ZIP Code"
348
+ * />
349
+ * {hasAddress && <button onClick={onAddressClear}>Clear</button>}
350
+ * </div>
351
+ * )
352
+ * )}
353
+ * </FulfillmentDetails.DeliveryAddress>
354
+ * ```
355
+ */
356
+ export declare const DeliveryAddress: React.ForwardRefExoticComponent<DeliveryAddressProps & React.RefAttributes<HTMLDivElement>>;
357
+ export {};
@@ -1,7 +1,10 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { CoreFulfillmentDetails } from './core/index.js';
4
+ import { FulfillmentTypeEnum, } from '../types/fulfillments-types.js';
4
5
  import { AsChildSlot } from '@wix/headless-utils/react';
6
+ import { stringFormat } from '../utils/fulfillments-utils.js';
7
+ import { toISODateString } from '../utils/date-utils.js';
5
8
  const TimeSlotContext = React.createContext(null);
6
9
  function useTimeSlotContext() {
7
10
  const context = React.useContext(TimeSlotContext);
@@ -22,6 +25,8 @@ var TestIds;
22
25
  TestIds["timeSlotOptions"] = "fulfillment-time-slot-options";
23
26
  TestIds["timeSlotOption"] = "fulfillment-time-slot-option";
24
27
  TestIds["fulfillmentType"] = "fulfillment-type";
28
+ TestIds["deliveryAddress"] = "fulfillment-delivery-address";
29
+ TestIds["deliveryAddressInput"] = "fulfillment-delivery-address-input";
25
30
  })(TestIds || (TestIds = {}));
26
31
  /**
27
32
  * Root headless component for Fulfillment Details
@@ -61,7 +66,7 @@ Root.displayName = 'FulfillmentDetails.Root';
61
66
  */
62
67
  export const AddressName = React.forwardRef(({ children, asChild, className, ...rest }, ref) => {
63
68
  return (_jsx(CoreFulfillmentDetails.AddressName, { children: ({ addressName, fullAddress, hasAddress, dispatchType }) => {
64
- const displayText = addressName || fullAddress || 'No address selected';
69
+ const displayText = addressName || fullAddress;
65
70
  return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, customElementProps: {
66
71
  addressName,
67
72
  fullAddress,
@@ -83,29 +88,38 @@ AddressName.displayName = 'FulfillmentDetails.AddressName';
83
88
  * // With custom class name
84
89
  * <FulfillmentDetails.FulfillmentDate className="my-date-input" />
85
90
  *
91
+ * // With label
92
+ * <FulfillmentDetails.FulfillmentDate
93
+ * label="Date"
94
+ * labelClassName="block mb-1 text-sm"
95
+ * wrapperClassName="flex-1"
96
+ * className="my-date-input"
97
+ * />
98
+ *
86
99
  * // Using asChild pattern
87
100
  * <FulfillmentDetails.FulfillmentDate asChild>
88
101
  * {({ selectedDate, onDateChange, minDate, maxDate }) => (
89
102
  * <input
90
103
  * type="date"
91
- * value={selectedDate?.toISOString().split('T')[0]}
104
+ * value={selectedDate ? toISODateString(selectedDate) : ''}
92
105
  * onChange={(e) => onDateChange(new Date(e.target.value))}
93
- * min={minDate.toISOString().split('T')[0]}
94
- * max={maxDate.toISOString().split('T')[0]}
106
+ * min={toISODateString(minDate)}
107
+ * max={toISODateString(maxDate)}
95
108
  * />
96
109
  * )}
97
110
  * </FulfillmentDetails.FulfillmentDate>
98
111
  * ```
99
112
  */
100
- export const FulfillmentDate = React.forwardRef(({ children, asChild, className, ...rest }, ref) => {
113
+ export const FulfillmentDate = React.forwardRef(({ children, asChild, className, label, labelClassName, wrapperClassName, ...rest }, ref) => {
101
114
  return (_jsx(CoreFulfillmentDetails.FulfillmentDate, { children: ({ selectedDate, onDateChange, minDate, maxDate }) => {
102
- const defaultContent = (_jsx("input", { type: "date", value: selectedDate?.toISOString().split('T')[0] || '', onChange: (e) => onDateChange(new Date(e.target.value)), min: minDate.toISOString().split('T')[0], max: maxDate.toISOString().split('T')[0] }));
103
- return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, customElementProps: {
115
+ const inputElement = (_jsx("input", { ref: ref, type: "date", className: className, value: selectedDate ? toISODateString(selectedDate) : '', onChange: (e) => onDateChange(new Date(e.target.value)), min: toISODateString(minDate), max: toISODateString(maxDate), "data-testid": TestIds.fulfillmentDate, ...rest }));
116
+ const defaultContent = label ? (_jsxs("div", { className: wrapperClassName, children: [_jsx("label", { className: labelClassName, children: label }), inputElement] })) : (inputElement);
117
+ return (_jsx(AsChildSlot, { asChild: asChild, customElement: children, customElementProps: {
104
118
  selectedDate,
105
119
  onDateChange,
106
120
  minDate,
107
121
  maxDate,
108
- }, content: defaultContent, "data-testid": TestIds.fulfillmentDate, ...rest, children: defaultContent }));
122
+ }, content: defaultContent, children: defaultContent }));
109
123
  } }));
110
124
  });
111
125
  FulfillmentDate.displayName = 'FulfillmentDetails.FulfillmentDate';
@@ -211,16 +225,24 @@ export const TimeSlotOptionRepeater = ({ children, }) => {
211
225
  };
212
226
  TimeSlotOptionRepeater.displayName =
213
227
  'FulfillmentDetails.TimeSlotOptionRepeater';
214
- // ========================================
215
- // FULFILLMENT TYPE COMPONENT
216
- // ========================================
217
- export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
218
228
  /**
219
- * Headless component for fulfillment type selection (ASAP or Pre-order)
229
+ * Headless component for fulfillment type selection (ASAP or Schedule for later)
230
+ * Provides radio button functionality with default rendering
220
231
  *
221
232
  * @example
222
233
  * ```tsx
223
- * <FulfillmentDetails.FulfillmentType>
234
+ * // Default usage - renders radio buttons
235
+ * <FulfillmentDetails.FulfillmentType />
236
+ *
237
+ * // With custom labels
238
+ * <FulfillmentDetails.FulfillmentType
239
+ * asapLabel="Now"
240
+ * scheduleLabel="Later"
241
+ * groupAriaLabel="When do you want your order?"
242
+ * />
243
+ *
244
+ * // Using asChild pattern
245
+ * <FulfillmentDetails.FulfillmentType asChild>
224
246
  * {({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption }) => (
225
247
  * <div>
226
248
  * {hasAsapOption && (
@@ -236,7 +258,7 @@ export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
236
258
  * onClick={() => onTypeChange(FulfillmentTypeEnum.PREORDER)}
237
259
  * data-selected={selectedType === FulfillmentTypeEnum.PREORDER}
238
260
  * >
239
- * Pre-order
261
+ * Schedule for later
240
262
  * </button>
241
263
  * )}
242
264
  * </div>
@@ -244,12 +266,94 @@ export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
244
266
  * </FulfillmentDetails.FulfillmentType>
245
267
  * ```
246
268
  */
247
- export const FulfillmentType = ({ children, }) => {
248
- return (_jsx(CoreFulfillmentDetails.FulfillmentType, { children: ({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption }) => children({
249
- selectedType,
250
- onTypeChange,
251
- hasAsapOption,
252
- hasPreorderOption,
253
- }) }));
254
- };
269
+ export const FulfillmentType = React.forwardRef(({ children, asChild, className, asapLabel, scheduleLabel, groupAriaLabel, asapTimeText, inputClassName, ...rest }, ref) => {
270
+ return (_jsx(CoreFulfillmentDetails.FulfillmentType, { children: ({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption, hasAsapAndFutureOption, asapTime, asapTimeRange, }) => {
271
+ const radioGroupName = React.useId();
272
+ const isOnlyAsap = hasAsapOption && !hasAsapAndFutureOption;
273
+ // Format ASAP label with time if asapTimeText template is provided
274
+ const formattedAsapLabel = asapTimeText
275
+ ? stringFormat(asapTimeText, asapTime)
276
+ : asapTime;
277
+ const onlyAsapContent = isOnlyAsap && formattedAsapLabel;
278
+ const renderRadioOption = (value, label) => (_jsxs("label", { children: [_jsx("input", { type: "radio", name: radioGroupName, value: value, checked: selectedType === value, onChange: () => onTypeChange(value), className: inputClassName }), label] }));
279
+ const defaultContent = hasAsapAndFutureOption && (_jsxs("div", { role: "radiogroup", "aria-label": groupAriaLabel, children: [hasAsapOption &&
280
+ renderRadioOption(FulfillmentTypeEnum.ASAP, asapLabel), hasAsapAndFutureOption &&
281
+ renderRadioOption(FulfillmentTypeEnum.ASAP_AND_FUTURE, scheduleLabel)] }));
282
+ // Use onlyAsapContent when only ASAP is available, otherwise use defaultContent
283
+ const contentToRender = isOnlyAsap ? onlyAsapContent : defaultContent;
284
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, customElementProps: {
285
+ selectedType,
286
+ onTypeChange,
287
+ hasAsapOption,
288
+ hasAsapAndFutureOption,
289
+ hasPreorderOption,
290
+ asapTime,
291
+ asapTimeRange,
292
+ }, content: contentToRender, "data-testid": TestIds.fulfillmentType, ...rest, children: contentToRender }));
293
+ } }));
294
+ });
255
295
  FulfillmentType.displayName = 'FulfillmentDetails.FulfillmentType';
296
+ /**
297
+ * Headless component for editing the delivery address
298
+ * Only renders when dispatch type is DELIVERY
299
+ *
300
+ * @example
301
+ * ```tsx
302
+ * // Default usage - renders input for address line
303
+ * <FulfillmentDetails.DeliveryAddress
304
+ * label="Delivery Address"
305
+ * placeholder="Enter your address"
306
+ * />
307
+ *
308
+ * // Using asChild pattern for custom rendering
309
+ * <FulfillmentDetails.DeliveryAddress asChild>
310
+ * {({ address, hasAddress, isDelivery, onAddressChange, onAddressClear }) => (
311
+ * isDelivery && (
312
+ * <div>
313
+ * <input
314
+ * value={address?.addressLine || ''}
315
+ * onChange={(e) => onAddressChange({ ...address, addressLine: e.target.value })}
316
+ * placeholder="Street Address"
317
+ * />
318
+ * <input
319
+ * value={address?.city || ''}
320
+ * onChange={(e) => onAddressChange({ ...address, city: e.target.value })}
321
+ * placeholder="City"
322
+ * />
323
+ * <input
324
+ * value={address?.postalCode || ''}
325
+ * onChange={(e) => onAddressChange({ ...address, postalCode: e.target.value })}
326
+ * placeholder="ZIP Code"
327
+ * />
328
+ * {hasAddress && <button onClick={onAddressClear}>Clear</button>}
329
+ * </div>
330
+ * )
331
+ * )}
332
+ * </FulfillmentDetails.DeliveryAddress>
333
+ * ```
334
+ */
335
+ export const DeliveryAddress = React.forwardRef(({ children, asChild, className, label, labelClassName, wrapperClassName, placeholder = 'Enter delivery address', inputClassName, ...rest }, ref) => {
336
+ return (_jsx(CoreFulfillmentDetails.DeliveryAddress, { children: ({ address, hasAddress, isDelivery, dispatchType, onAddressChange, onAddressClear, }) => {
337
+ // Don't render anything if not delivery
338
+ if (!isDelivery) {
339
+ return null;
340
+ }
341
+ const handleAddressLineChange = (e) => {
342
+ onAddressChange({
343
+ ...address,
344
+ addressLine: e.target.value,
345
+ });
346
+ };
347
+ const inputElement = (_jsx("input", { type: "text", className: inputClassName, value: address?.addressLine || '', onChange: handleAddressLineChange, placeholder: placeholder, "data-testid": TestIds.deliveryAddressInput }));
348
+ const defaultContent = label ? (_jsxs("div", { className: wrapperClassName, children: [_jsx("label", { className: labelClassName, children: label }), inputElement] })) : (inputElement);
349
+ return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, customElementProps: {
350
+ address,
351
+ hasAddress,
352
+ isDelivery,
353
+ dispatchType,
354
+ onAddressChange,
355
+ onAddressClear,
356
+ }, content: defaultContent, "data-testid": TestIds.deliveryAddress, ...rest, children: defaultContent }));
357
+ } }));
358
+ });
359
+ DeliveryAddress.displayName = 'FulfillmentDetails.DeliveryAddress';
@@ -131,7 +131,7 @@ export interface AddToCartButtonProps {
131
131
  addToCartLabelMap: Record<AddToCartButtonState, string>;
132
132
  /** Children render prop that receives button state and line item data */
133
133
  children?: AsChildChildren<{
134
- lineItem: LineItem;
134
+ onHandleAddToCart: (onClick: (lineItem: LineItem) => void) => void;
135
135
  buttonState: AddToCartButtonState;
136
136
  addToCartButtonDisabled?: boolean;
137
137
  /** Content to display when loading */
@@ -139,7 +139,6 @@ export interface AddToCartButtonProps {
139
139
  /** Text label for the button */
140
140
  label: React.ReactNode;
141
141
  formattedPrice: string;
142
- modifierGroupHasError: boolean;
143
142
  }>;
144
143
  }
145
144
  /**
@@ -166,9 +165,10 @@ export interface AddToCartButtonProps {
166
165
  * addToCartLabelMap={labelMap}
167
166
  * asChild
168
167
  * >
169
- * {({ buttonState, formattedPrice, modifierGroupHasError, addToCartButtonDisabled }) => (
168
+ * {({ buttonState, formattedPrice, addToCartButtonDisabled,onHandleAddToCart }) => (
170
169
  * <button
171
- * disabled={addToCartButtonDisabled || modifierGroupHasError}
170
+ * onClick={() => onHandleAddToCart(onClickFunction)}
171
+ * disabled={addToCartButtonDisabled}
172
172
  * className="bg-primary text-primary-foreground"
173
173
  * >
174
174
  * <span>{labelMap[buttonState]}</span>
@@ -118,9 +118,10 @@ Variants.displayName = 'ItemDetails.Variants';
118
118
  * addToCartLabelMap={labelMap}
119
119
  * asChild
120
120
  * >
121
- * {({ buttonState, formattedPrice, modifierGroupHasError, addToCartButtonDisabled }) => (
121
+ * {({ buttonState, formattedPrice, addToCartButtonDisabled,onHandleAddToCart }) => (
122
122
  * <button
123
- * disabled={addToCartButtonDisabled || modifierGroupHasError}
123
+ * onClick={() => onHandleAddToCart(onClickFunction)}
124
+ * disabled={addToCartButtonDisabled}
124
125
  * className="bg-primary text-primary-foreground"
125
126
  * >
126
127
  * <span>{labelMap[buttonState]}</span>
@@ -131,17 +132,15 @@ Variants.displayName = 'ItemDetails.Variants';
131
132
  * ```
132
133
  */
133
134
  export const AddToCartButton = React.forwardRef(({ asChild, children, className, addToCartLabelMap, ...props }, ref) => {
134
- return (_jsx(CoreItemDetails.LineItemComponent, { addToCartLabelMap: addToCartLabelMap, children: ({ lineItem, buttonState, addToCartButtonDisabled, loadingState, labelText, formattedPrice, modifierGroupHasError, }) => {
135
+ return (_jsx(CoreItemDetails.LineItemComponent, { addToCartLabelMap: addToCartLabelMap, children: ({ onHandleAddToCart, buttonState, addToCartButtonDisabled, loadingState, labelText, formattedPrice, lineItem, }) => {
135
136
  const label = (_jsxs(_Fragment, { children: [_jsx("span", { children: labelText }), " ", _jsx("span", { children: " | " }), _jsx("span", { children: formattedPrice })] }));
136
137
  return (_jsx(AsChildSlot, { asChild: asChild, className: className, customElement: children, customElementProps: {
137
138
  buttonState,
138
139
  addToCartButtonDisabled,
139
140
  loadingState,
140
- lineItem,
141
- lineItems: [lineItem],
141
+ onHandleAddToCart,
142
142
  label,
143
143
  formattedPrice,
144
- modifierGroupHasError,
145
144
  }, ref: ref, ...props, children: _jsx(Commerce.Actions.AddToCart, { asChild: false, label: label, className: className, lineItems: [lineItem], ...props }) }));
146
145
  } }));
147
146
  });
@@ -37,6 +37,8 @@ interface CurrentTimeSlotProps {
37
37
  className?: string;
38
38
  /** Whether to render as a child component */
39
39
  asChild?: boolean;
40
+ /** prefixElement to display before the time slot text */
41
+ prefixElement?: React.ReactNode;
40
42
  deliveryTypeText: string;
41
43
  pickupTypeText: string;
42
44
  asapTimeText: string;
@@ -172,6 +174,8 @@ interface CurrentLocationProps {
172
174
  export declare const CurrentLocation: React.FC<CurrentLocationProps>;
173
175
  interface MinOrderAmountProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
174
176
  asChild?: boolean;
177
+ /** Label text to display before the minimum order amount (e.g., "Min Order:") */
178
+ label?: string;
175
179
  /** Children render prop that receives the minimum order amount data */
176
180
  children?: AsChildChildren<{
177
181
  minOrderAmount: number | undefined;
@@ -242,6 +246,8 @@ interface SelectedAddressProps extends Omit<React.ComponentPropsWithoutRef<'div'
242
246
  export declare const SelectedAddress: React.FC<SelectedAddressProps>;
243
247
  interface DeliveryFeeProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
244
248
  asChild?: boolean;
249
+ /** Label text to display before the delivery fee (e.g., "Delivery Fee:") */
250
+ label?: string;
245
251
  /** Children render prop that receives the delivery fee data */
246
252
  children?: AsChildChildren<{
247
253
  deliveryFee: string | undefined;
@@ -267,6 +273,8 @@ interface DeliveryFeeProps extends Omit<React.ComponentPropsWithoutRef<'div'>, '
267
273
  export declare const DeliveryFee: React.FC<DeliveryFeeProps>;
268
274
  interface FreeDeliveryThresholdProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
269
275
  asChild?: boolean;
276
+ /** Label text to display before the free delivery threshold (e.g., "Free delivery above:") */
277
+ label?: string;
270
278
  /** Children render prop that receives the free delivery threshold data */
271
279
  children?: AsChildChildren<{
272
280
  freeDeliveryThreshold: string | undefined;