@wix/headless-restaurants-olo 0.0.30 → 0.0.32
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/cjs/dist/react/ClickableItem.d.ts +18 -3
- package/cjs/dist/react/ClickableItem.js +16 -9
- package/cjs/dist/react/FulfillmentDetails.d.ts +233 -0
- package/cjs/dist/react/FulfillmentDetails.js +255 -0
- package/cjs/dist/react/ItemDetails.d.ts +233 -36
- package/cjs/dist/react/ItemDetails.js +208 -0
- package/cjs/dist/react/ModifierGroup.js +0 -3
- package/cjs/dist/react/OLO.d.ts +5 -160
- package/cjs/dist/react/OLO.js +6 -122
- package/cjs/dist/react/OLOMenus.d.ts +8 -2
- package/cjs/dist/react/OLOMenus.js +3 -4
- package/cjs/dist/react/Settings.d.ts +176 -48
- package/cjs/dist/react/Settings.js +276 -26
- package/cjs/dist/react/core/ClickableItem.d.ts +12 -5
- package/cjs/dist/react/core/ClickableItem.js +13 -14
- package/cjs/dist/react/core/FulfillmentDetails.d.ts +78 -0
- package/cjs/dist/react/core/FulfillmentDetails.js +177 -0
- package/cjs/dist/react/core/ItemDetails.js +2 -4
- package/cjs/dist/react/core/OLO.d.ts +6 -74
- package/cjs/dist/react/core/OLO.js +5 -44
- package/cjs/dist/react/core/OLOMenus.d.ts +1 -1
- package/cjs/dist/react/core/OLOMenus.js +2 -3
- package/cjs/dist/react/core/Settings.d.ts +138 -22
- package/cjs/dist/react/core/Settings.js +157 -34
- package/cjs/dist/react/core/index.d.ts +1 -0
- package/cjs/dist/react/core/index.js +1 -0
- package/cjs/dist/react/index.d.ts +2 -0
- package/cjs/dist/react/index.js +1 -0
- package/cjs/dist/services/fulfillments-service.js +80 -22
- package/cjs/dist/types/fulfillments-types.d.ts +49 -2
- package/cjs/dist/types/operation.d.ts +1 -1
- package/cjs/dist/utils/fulfillments-utils.d.ts +34 -1
- package/cjs/dist/utils/fulfillments-utils.js +209 -1
- package/dist/react/ClickableItem.d.ts +18 -3
- package/dist/react/ClickableItem.js +16 -9
- package/dist/react/FulfillmentDetails.d.ts +233 -0
- package/dist/react/FulfillmentDetails.js +255 -0
- package/dist/react/ItemDetails.d.ts +233 -36
- package/dist/react/ItemDetails.js +208 -0
- package/dist/react/ModifierGroup.js +0 -3
- package/dist/react/OLO.d.ts +5 -160
- package/dist/react/OLO.js +6 -122
- package/dist/react/OLOMenus.d.ts +8 -2
- package/dist/react/OLOMenus.js +3 -4
- package/dist/react/Settings.d.ts +176 -48
- package/dist/react/Settings.js +276 -26
- package/dist/react/core/ClickableItem.d.ts +12 -5
- package/dist/react/core/ClickableItem.js +13 -14
- package/dist/react/core/FulfillmentDetails.d.ts +78 -0
- package/dist/react/core/FulfillmentDetails.js +177 -0
- package/dist/react/core/ItemDetails.js +2 -4
- package/dist/react/core/OLO.d.ts +6 -74
- package/dist/react/core/OLO.js +5 -44
- package/dist/react/core/OLOMenus.d.ts +1 -1
- package/dist/react/core/OLOMenus.js +2 -3
- package/dist/react/core/Settings.d.ts +138 -22
- package/dist/react/core/Settings.js +157 -34
- package/dist/react/core/index.d.ts +1 -0
- package/dist/react/core/index.js +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +1 -0
- package/dist/services/fulfillments-service.js +80 -22
- package/dist/types/fulfillments-types.d.ts +49 -2
- package/dist/types/operation.d.ts +1 -1
- package/dist/utils/fulfillments-utils.d.ts +34 -1
- package/dist/utils/fulfillments-utils.js +209 -1
- package/package.json +2 -2
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { type SelectedItemData } from './core/ClickableItem.js';
|
|
3
|
+
/**
|
|
4
|
+
* ClickableItem component
|
|
5
|
+
*
|
|
6
|
+
* A wrapper that makes an item clickable and passes the selected item data up via callback.
|
|
7
|
+
* Uses direct props pattern - no global state.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <ClickableItem onItemSelected={(item) => setSelectedItem(item)}>
|
|
12
|
+
* <div>Click me</div>
|
|
13
|
+
* </ClickableItem>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function ClickableItem({ onItemSelected, children, className, }: {
|
|
17
|
+
onItemSelected: (item: SelectedItemData) => void;
|
|
4
18
|
children: React.ReactNode;
|
|
19
|
+
className?: string;
|
|
5
20
|
}): import("react/jsx-runtime").JSX.Element;
|
|
6
21
|
export declare const Actions: {
|
|
7
22
|
Select: typeof ClickableItem;
|
|
8
23
|
};
|
|
9
|
-
export {};
|
|
24
|
+
export type { SelectedItemData } from './core/ClickableItem.js';
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { CoreClickableItem } from './core/ClickableItem.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
import { CoreClickableItem, } from './core/ClickableItem.js';
|
|
3
|
+
/**
|
|
4
|
+
* ClickableItem component
|
|
5
|
+
*
|
|
6
|
+
* A wrapper that makes an item clickable and passes the selected item data up via callback.
|
|
7
|
+
* Uses direct props pattern - no global state.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <ClickableItem onItemSelected={(item) => setSelectedItem(item)}>
|
|
12
|
+
* <div>Click me</div>
|
|
13
|
+
* </ClickableItem>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
function ClickableItem({ onItemSelected, children, className, }) {
|
|
17
|
+
return (_jsx(CoreClickableItem, { children: ({ itemData }) => (_jsx("div", { onClick: () => onItemSelected(itemData), className: className, children: children })) }));
|
|
11
18
|
}
|
|
12
19
|
export const Actions = {
|
|
13
20
|
Select: ClickableItem,
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CoreFulfillmentDetails } from './core/index.js';
|
|
3
|
+
import { DispatchType } from '../types/fulfillments-types.js';
|
|
4
|
+
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
5
|
+
interface TimeSlotContextValue {
|
|
6
|
+
timeSlots: Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
startTime: Date;
|
|
10
|
+
endTime: Date;
|
|
11
|
+
dispatchType: DispatchType;
|
|
12
|
+
isAsap: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
selectedTimeSlotId: string | null;
|
|
15
|
+
onTimeSlotChange: (timeSlotId: string) => void;
|
|
16
|
+
hasTimeSlots: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface RootProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
19
|
+
/** Child components that will have access to fulfillment details context */
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Root headless component for Fulfillment Details
|
|
24
|
+
* Provides context for fulfillment detail components
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <FulfillmentDetails.Root>
|
|
29
|
+
* <FulfillmentDetails.AddressName />
|
|
30
|
+
* <FulfillmentDetails.FulfillmentType />
|
|
31
|
+
* <FulfillmentDetails.FulfillmentDate />
|
|
32
|
+
* <FulfillmentDetails.AvailableTimeSlots>
|
|
33
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater />
|
|
34
|
+
* </FulfillmentDetails.AvailableTimeSlots>
|
|
35
|
+
* </FulfillmentDetails.Root>
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare const Root: React.ForwardRefExoticComponent<RootProps & React.RefAttributes<HTMLDivElement>>;
|
|
39
|
+
interface AddressNameProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
40
|
+
/** Whether to render as a child component */
|
|
41
|
+
asChild?: boolean;
|
|
42
|
+
/** Children render prop that receives the address data */
|
|
43
|
+
children?: AsChildChildren<{
|
|
44
|
+
addressName: string | null;
|
|
45
|
+
fullAddress: string | null;
|
|
46
|
+
hasAddress: boolean;
|
|
47
|
+
dispatchType: DispatchType | null;
|
|
48
|
+
}> | React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Headless component for displaying the fulfillment address name
|
|
52
|
+
* Shows pickup location name or delivery address
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* <FulfillmentDetails.AddressName>
|
|
57
|
+
* {({ addressName, dispatchType }) => (
|
|
58
|
+
* <div>
|
|
59
|
+
* {dispatchType === 'PICKUP' ? 'Pickup at: ' : 'Deliver to: '}
|
|
60
|
+
* {addressName}
|
|
61
|
+
* </div>
|
|
62
|
+
* )}
|
|
63
|
+
* </FulfillmentDetails.AddressName>
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare const AddressName: React.ForwardRefExoticComponent<AddressNameProps & React.RefAttributes<HTMLDivElement>>;
|
|
67
|
+
interface FulfillmentDateProps extends Omit<React.ComponentPropsWithoutRef<'input'>, 'children' | 'type' | 'value' | 'onChange' | 'min' | 'max'> {
|
|
68
|
+
/** Whether to render as a child component */
|
|
69
|
+
asChild?: boolean;
|
|
70
|
+
/** Optional children render prop that receives the date picker props */
|
|
71
|
+
children?: AsChildChildren<{
|
|
72
|
+
selectedDate: Date | null;
|
|
73
|
+
onDateChange: (date: Date) => void;
|
|
74
|
+
minDate: Date;
|
|
75
|
+
maxDate: Date;
|
|
76
|
+
}> | React.ReactNode;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Headless component for fulfillment date selection
|
|
80
|
+
* Provides date picker functionality with default input type="date" rendering
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* // Default usage - renders input type="date"
|
|
85
|
+
* <FulfillmentDetails.FulfillmentDate />
|
|
86
|
+
*
|
|
87
|
+
* // With custom class name
|
|
88
|
+
* <FulfillmentDetails.FulfillmentDate className="my-date-input" />
|
|
89
|
+
*
|
|
90
|
+
* // Using asChild pattern
|
|
91
|
+
* <FulfillmentDetails.FulfillmentDate asChild>
|
|
92
|
+
* {({ selectedDate, onDateChange, minDate, maxDate }) => (
|
|
93
|
+
* <input
|
|
94
|
+
* type="date"
|
|
95
|
+
* value={selectedDate?.toISOString().split('T')[0]}
|
|
96
|
+
* onChange={(e) => onDateChange(new Date(e.target.value))}
|
|
97
|
+
* min={minDate.toISOString().split('T')[0]}
|
|
98
|
+
* max={maxDate.toISOString().split('T')[0]}
|
|
99
|
+
* />
|
|
100
|
+
* )}
|
|
101
|
+
* </FulfillmentDetails.FulfillmentDate>
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare const FulfillmentDate: React.ForwardRefExoticComponent<FulfillmentDateProps & React.RefAttributes<HTMLInputElement>>;
|
|
105
|
+
interface AvailableTimeSlotsProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
106
|
+
/** Child components that will have access to time slot context */
|
|
107
|
+
children: React.ReactNode;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Container component for available time slots
|
|
111
|
+
* Provides context for time slot selection
|
|
112
|
+
* Does not render if no time slots are available
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```tsx
|
|
116
|
+
* <FulfillmentDetails.AvailableTimeSlots>
|
|
117
|
+
* <FulfillmentDetails.TimeSlotOptions emptyState={<div>No slots</div>}>
|
|
118
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
119
|
+
* {({ label, isSelected }) => (
|
|
120
|
+
* <div data-selected={isSelected}>{label}</div>
|
|
121
|
+
* )}
|
|
122
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
123
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
124
|
+
* </FulfillmentDetails.AvailableTimeSlots>
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare const AvailableTimeSlots: React.ForwardRefExoticComponent<AvailableTimeSlotsProps & React.RefAttributes<HTMLDivElement>>;
|
|
128
|
+
type TimeSlotRenderProps = {
|
|
129
|
+
timeSlots: TimeSlotContextValue['timeSlots'];
|
|
130
|
+
selectedTimeSlotId: string | null;
|
|
131
|
+
onTimeSlotChange: (timeSlotId: string) => void;
|
|
132
|
+
hasTimeSlots: boolean;
|
|
133
|
+
};
|
|
134
|
+
interface TimeSlotOptionsProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
|
|
135
|
+
/** Whether to render as a child component */
|
|
136
|
+
asChild?: boolean;
|
|
137
|
+
/** Child components or render prop that receives time slot data */
|
|
138
|
+
children?: ((props: TimeSlotRenderProps) => React.ReactNode) | React.ReactNode;
|
|
139
|
+
/** Optional content to display when no time slots are available */
|
|
140
|
+
emptyState?: React.ReactNode;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Container for time slot options list with empty state support
|
|
144
|
+
* Supports both regular children and asChild pattern for custom rendering (e.g., select dropdowns)
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```tsx
|
|
148
|
+
* // Regular usage with repeater
|
|
149
|
+
* <FulfillmentDetails.TimeSlotOptions emptyState={<div>No time slots</div>}>
|
|
150
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
151
|
+
* {({ label }) => <div>{label}</div>}
|
|
152
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
153
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
154
|
+
*
|
|
155
|
+
* // With asChild for select dropdown
|
|
156
|
+
* <FulfillmentDetails.TimeSlotOptions asChild>
|
|
157
|
+
* {({ timeSlots, selectedTimeSlotId, onTimeSlotChange }) => (
|
|
158
|
+
* <select value={selectedTimeSlotId || ''} onChange={(e) => onTimeSlotChange(e.target.value)}>
|
|
159
|
+
* {timeSlots.map(slot => <option key={slot.id} value={slot.id}>{slot.label}</option>)}
|
|
160
|
+
* </select>
|
|
161
|
+
* )}
|
|
162
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare const TimeSlotOptions: React.ForwardRefExoticComponent<TimeSlotOptionsProps & React.RefAttributes<HTMLDivElement>>;
|
|
166
|
+
interface TimeSlotOptionRepeaterProps {
|
|
167
|
+
/** Render prop that receives each time slot option data */
|
|
168
|
+
children: (props: {
|
|
169
|
+
id: string;
|
|
170
|
+
label: string;
|
|
171
|
+
startTime: Date;
|
|
172
|
+
endTime: Date;
|
|
173
|
+
isSelected: boolean;
|
|
174
|
+
isAsap: boolean;
|
|
175
|
+
onSelect: () => void;
|
|
176
|
+
}) => React.ReactNode;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Repeater component that renders children for each available time slot
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```tsx
|
|
183
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
184
|
+
* {({ label, isSelected, onSelect, isAsap }) => (
|
|
185
|
+
* <button onClick={onSelect} data-selected={isSelected}>
|
|
186
|
+
* {isAsap && '⚡ '}
|
|
187
|
+
* {label}
|
|
188
|
+
* </button>
|
|
189
|
+
* )}
|
|
190
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare const TimeSlotOptionRepeater: React.FC<TimeSlotOptionRepeaterProps>;
|
|
194
|
+
export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
|
|
195
|
+
interface FulfillmentTypeProps {
|
|
196
|
+
/** Children render prop that receives the fulfillment type selection props */
|
|
197
|
+
children: (props: {
|
|
198
|
+
selectedType: CoreFulfillmentDetails.FulfillmentTypeEnum;
|
|
199
|
+
onTypeChange: (type: CoreFulfillmentDetails.FulfillmentTypeEnum) => void;
|
|
200
|
+
hasAsapOption: boolean;
|
|
201
|
+
hasPreorderOption: boolean;
|
|
202
|
+
}) => React.ReactNode;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Headless component for fulfillment type selection (ASAP or Pre-order)
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```tsx
|
|
209
|
+
* <FulfillmentDetails.FulfillmentType>
|
|
210
|
+
* {({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption }) => (
|
|
211
|
+
* <div>
|
|
212
|
+
* {hasAsapOption && (
|
|
213
|
+
* <button
|
|
214
|
+
* onClick={() => onTypeChange(FulfillmentTypeEnum.ASAP)}
|
|
215
|
+
* data-selected={selectedType === FulfillmentTypeEnum.ASAP}
|
|
216
|
+
* >
|
|
217
|
+
* ASAP
|
|
218
|
+
* </button>
|
|
219
|
+
* )}
|
|
220
|
+
* {hasPreorderOption && (
|
|
221
|
+
* <button
|
|
222
|
+
* onClick={() => onTypeChange(FulfillmentTypeEnum.PREORDER)}
|
|
223
|
+
* data-selected={selectedType === FulfillmentTypeEnum.PREORDER}
|
|
224
|
+
* >
|
|
225
|
+
* Pre-order
|
|
226
|
+
* </button>
|
|
227
|
+
* )}
|
|
228
|
+
* </div>
|
|
229
|
+
* )}
|
|
230
|
+
* </FulfillmentDetails.FulfillmentType>
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export declare const FulfillmentType: React.FC<FulfillmentTypeProps>;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { CoreFulfillmentDetails } from './core/index.js';
|
|
4
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
5
|
+
const TimeSlotContext = React.createContext(null);
|
|
6
|
+
function useTimeSlotContext() {
|
|
7
|
+
const context = React.useContext(TimeSlotContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error('useTimeSlotContext must be used within a FulfillmentDetails.AvailableTimeSlots component');
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
// ========================================
|
|
14
|
+
// FULFILLMENT DETAILS HEADLESS COMPONENTS
|
|
15
|
+
// ========================================
|
|
16
|
+
var TestIds;
|
|
17
|
+
(function (TestIds) {
|
|
18
|
+
TestIds["fulfillmentDetailsRoot"] = "fulfillment-details-root";
|
|
19
|
+
TestIds["addressName"] = "fulfillment-address-name";
|
|
20
|
+
TestIds["fulfillmentDate"] = "fulfillment-date";
|
|
21
|
+
TestIds["availableTimeSlots"] = "fulfillment-available-time-slots";
|
|
22
|
+
TestIds["timeSlotOptions"] = "fulfillment-time-slot-options";
|
|
23
|
+
TestIds["timeSlotOption"] = "fulfillment-time-slot-option";
|
|
24
|
+
TestIds["fulfillmentType"] = "fulfillment-type";
|
|
25
|
+
})(TestIds || (TestIds = {}));
|
|
26
|
+
/**
|
|
27
|
+
* Root headless component for Fulfillment Details
|
|
28
|
+
* Provides context for fulfillment detail components
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <FulfillmentDetails.Root>
|
|
33
|
+
* <FulfillmentDetails.AddressName />
|
|
34
|
+
* <FulfillmentDetails.FulfillmentType />
|
|
35
|
+
* <FulfillmentDetails.FulfillmentDate />
|
|
36
|
+
* <FulfillmentDetails.AvailableTimeSlots>
|
|
37
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater />
|
|
38
|
+
* </FulfillmentDetails.AvailableTimeSlots>
|
|
39
|
+
* </FulfillmentDetails.Root>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export const Root = React.forwardRef(({ children, className, ...rest }, ref) => {
|
|
43
|
+
return (_jsx(CoreFulfillmentDetails.Root, { children: _jsx("div", { ref: ref, className: className, "data-testid": TestIds.fulfillmentDetailsRoot, ...rest, children: children }) }));
|
|
44
|
+
});
|
|
45
|
+
Root.displayName = 'FulfillmentDetails.Root';
|
|
46
|
+
/**
|
|
47
|
+
* Headless component for displaying the fulfillment address name
|
|
48
|
+
* Shows pickup location name or delivery address
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <FulfillmentDetails.AddressName>
|
|
53
|
+
* {({ addressName, dispatchType }) => (
|
|
54
|
+
* <div>
|
|
55
|
+
* {dispatchType === 'PICKUP' ? 'Pickup at: ' : 'Deliver to: '}
|
|
56
|
+
* {addressName}
|
|
57
|
+
* </div>
|
|
58
|
+
* )}
|
|
59
|
+
* </FulfillmentDetails.AddressName>
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const AddressName = React.forwardRef(({ children, asChild, className, ...rest }, ref) => {
|
|
63
|
+
return (_jsx(CoreFulfillmentDetails.AddressName, { children: ({ addressName, fullAddress, hasAddress, dispatchType }) => {
|
|
64
|
+
const displayText = addressName || fullAddress || 'No address selected';
|
|
65
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, customElement: children, customElementProps: {
|
|
66
|
+
addressName,
|
|
67
|
+
fullAddress,
|
|
68
|
+
hasAddress,
|
|
69
|
+
dispatchType,
|
|
70
|
+
}, content: displayText, "data-testid": TestIds.addressName, ...rest, children: hasAddress && _jsx("div", { children: displayText }) }));
|
|
71
|
+
} }));
|
|
72
|
+
});
|
|
73
|
+
AddressName.displayName = 'FulfillmentDetails.AddressName';
|
|
74
|
+
/**
|
|
75
|
+
* Headless component for fulfillment date selection
|
|
76
|
+
* Provides date picker functionality with default input type="date" rendering
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // Default usage - renders input type="date"
|
|
81
|
+
* <FulfillmentDetails.FulfillmentDate />
|
|
82
|
+
*
|
|
83
|
+
* // With custom class name
|
|
84
|
+
* <FulfillmentDetails.FulfillmentDate className="my-date-input" />
|
|
85
|
+
*
|
|
86
|
+
* // Using asChild pattern
|
|
87
|
+
* <FulfillmentDetails.FulfillmentDate asChild>
|
|
88
|
+
* {({ selectedDate, onDateChange, minDate, maxDate }) => (
|
|
89
|
+
* <input
|
|
90
|
+
* type="date"
|
|
91
|
+
* value={selectedDate?.toISOString().split('T')[0]}
|
|
92
|
+
* onChange={(e) => onDateChange(new Date(e.target.value))}
|
|
93
|
+
* min={minDate.toISOString().split('T')[0]}
|
|
94
|
+
* max={maxDate.toISOString().split('T')[0]}
|
|
95
|
+
* />
|
|
96
|
+
* )}
|
|
97
|
+
* </FulfillmentDetails.FulfillmentDate>
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export const FulfillmentDate = React.forwardRef(({ children, asChild, className, ...rest }, ref) => {
|
|
101
|
+
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: {
|
|
104
|
+
selectedDate,
|
|
105
|
+
onDateChange,
|
|
106
|
+
minDate,
|
|
107
|
+
maxDate,
|
|
108
|
+
}, content: defaultContent, "data-testid": TestIds.fulfillmentDate, ...rest, children: defaultContent }));
|
|
109
|
+
} }));
|
|
110
|
+
});
|
|
111
|
+
FulfillmentDate.displayName = 'FulfillmentDetails.FulfillmentDate';
|
|
112
|
+
/**
|
|
113
|
+
* Container component for available time slots
|
|
114
|
+
* Provides context for time slot selection
|
|
115
|
+
* Does not render if no time slots are available
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```tsx
|
|
119
|
+
* <FulfillmentDetails.AvailableTimeSlots>
|
|
120
|
+
* <FulfillmentDetails.TimeSlotOptions emptyState={<div>No slots</div>}>
|
|
121
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
122
|
+
* {({ label, isSelected }) => (
|
|
123
|
+
* <div data-selected={isSelected}>{label}</div>
|
|
124
|
+
* )}
|
|
125
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
126
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
127
|
+
* </FulfillmentDetails.AvailableTimeSlots>
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export const AvailableTimeSlots = React.forwardRef(({ children, className, ...rest }, ref) => {
|
|
131
|
+
return (_jsx(CoreFulfillmentDetails.AvailableTimeSlots, { children: ({ timeSlots, selectedTimeSlotId, onTimeSlotChange, hasTimeSlots }) => {
|
|
132
|
+
if (!hasTimeSlots)
|
|
133
|
+
return null;
|
|
134
|
+
const contextValue = {
|
|
135
|
+
timeSlots,
|
|
136
|
+
selectedTimeSlotId,
|
|
137
|
+
onTimeSlotChange,
|
|
138
|
+
hasTimeSlots,
|
|
139
|
+
};
|
|
140
|
+
return (_jsx(TimeSlotContext.Provider, { value: contextValue, children: _jsx("div", { ref: ref, className: className, "data-testid": TestIds.availableTimeSlots, ...rest, children: children }) }));
|
|
141
|
+
} }));
|
|
142
|
+
});
|
|
143
|
+
AvailableTimeSlots.displayName = 'FulfillmentDetails.AvailableTimeSlots';
|
|
144
|
+
/**
|
|
145
|
+
* Container for time slot options list with empty state support
|
|
146
|
+
* Supports both regular children and asChild pattern for custom rendering (e.g., select dropdowns)
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```tsx
|
|
150
|
+
* // Regular usage with repeater
|
|
151
|
+
* <FulfillmentDetails.TimeSlotOptions emptyState={<div>No time slots</div>}>
|
|
152
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
153
|
+
* {({ label }) => <div>{label}</div>}
|
|
154
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
155
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
156
|
+
*
|
|
157
|
+
* // With asChild for select dropdown
|
|
158
|
+
* <FulfillmentDetails.TimeSlotOptions asChild>
|
|
159
|
+
* {({ timeSlots, selectedTimeSlotId, onTimeSlotChange }) => (
|
|
160
|
+
* <select value={selectedTimeSlotId || ''} onChange={(e) => onTimeSlotChange(e.target.value)}>
|
|
161
|
+
* {timeSlots.map(slot => <option key={slot.id} value={slot.id}>{slot.label}</option>)}
|
|
162
|
+
* </select>
|
|
163
|
+
* )}
|
|
164
|
+
* </FulfillmentDetails.TimeSlotOptions>
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export const TimeSlotOptions = React.forwardRef(({ children, asChild, emptyState, className, ...rest }, ref) => {
|
|
168
|
+
const { hasTimeSlots, timeSlots, selectedTimeSlotId, onTimeSlotChange } = useTimeSlotContext();
|
|
169
|
+
if (!hasTimeSlots) {
|
|
170
|
+
return emptyState || null;
|
|
171
|
+
}
|
|
172
|
+
if (asChild && typeof children === 'function') {
|
|
173
|
+
return children({
|
|
174
|
+
timeSlots,
|
|
175
|
+
selectedTimeSlotId,
|
|
176
|
+
onTimeSlotChange,
|
|
177
|
+
hasTimeSlots,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return (_jsx("div", { ref: ref, className: className, "data-testid": TestIds.timeSlotOptions, ...rest, children: typeof children === 'function' ? null : children }));
|
|
181
|
+
});
|
|
182
|
+
TimeSlotOptions.displayName = 'FulfillmentDetails.TimeSlotOptions';
|
|
183
|
+
/**
|
|
184
|
+
* Repeater component that renders children for each available time slot
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```tsx
|
|
188
|
+
* <FulfillmentDetails.TimeSlotOptionRepeater>
|
|
189
|
+
* {({ label, isSelected, onSelect, isAsap }) => (
|
|
190
|
+
* <button onClick={onSelect} data-selected={isSelected}>
|
|
191
|
+
* {isAsap && '⚡ '}
|
|
192
|
+
* {label}
|
|
193
|
+
* </button>
|
|
194
|
+
* )}
|
|
195
|
+
* </FulfillmentDetails.TimeSlotOptionRepeater>
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export const TimeSlotOptionRepeater = ({ children, }) => {
|
|
199
|
+
const { timeSlots, selectedTimeSlotId, onTimeSlotChange, hasTimeSlots } = useTimeSlotContext();
|
|
200
|
+
if (!hasTimeSlots)
|
|
201
|
+
return null;
|
|
202
|
+
return (_jsx(_Fragment, { children: timeSlots.map((slot) => (_jsx(React.Fragment, { children: children({
|
|
203
|
+
id: slot.id,
|
|
204
|
+
label: slot.label,
|
|
205
|
+
startTime: slot.startTime,
|
|
206
|
+
endTime: slot.endTime,
|
|
207
|
+
isSelected: slot.id === selectedTimeSlotId,
|
|
208
|
+
isAsap: slot.isAsap,
|
|
209
|
+
onSelect: () => onTimeSlotChange(slot.id),
|
|
210
|
+
}) }, slot.id))) }));
|
|
211
|
+
};
|
|
212
|
+
TimeSlotOptionRepeater.displayName =
|
|
213
|
+
'FulfillmentDetails.TimeSlotOptionRepeater';
|
|
214
|
+
// ========================================
|
|
215
|
+
// FULFILLMENT TYPE COMPONENT
|
|
216
|
+
// ========================================
|
|
217
|
+
export { FulfillmentTypeEnum } from './core/FulfillmentDetails.js';
|
|
218
|
+
/**
|
|
219
|
+
* Headless component for fulfillment type selection (ASAP or Pre-order)
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```tsx
|
|
223
|
+
* <FulfillmentDetails.FulfillmentType>
|
|
224
|
+
* {({ selectedType, onTypeChange, hasAsapOption, hasPreorderOption }) => (
|
|
225
|
+
* <div>
|
|
226
|
+
* {hasAsapOption && (
|
|
227
|
+
* <button
|
|
228
|
+
* onClick={() => onTypeChange(FulfillmentTypeEnum.ASAP)}
|
|
229
|
+
* data-selected={selectedType === FulfillmentTypeEnum.ASAP}
|
|
230
|
+
* >
|
|
231
|
+
* ASAP
|
|
232
|
+
* </button>
|
|
233
|
+
* )}
|
|
234
|
+
* {hasPreorderOption && (
|
|
235
|
+
* <button
|
|
236
|
+
* onClick={() => onTypeChange(FulfillmentTypeEnum.PREORDER)}
|
|
237
|
+
* data-selected={selectedType === FulfillmentTypeEnum.PREORDER}
|
|
238
|
+
* >
|
|
239
|
+
* Pre-order
|
|
240
|
+
* </button>
|
|
241
|
+
* )}
|
|
242
|
+
* </div>
|
|
243
|
+
* )}
|
|
244
|
+
* </FulfillmentDetails.FulfillmentType>
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
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
|
+
};
|
|
255
|
+
FulfillmentType.displayName = 'FulfillmentDetails.FulfillmentType';
|