@wix/headless-restaurants-olo 0.0.13 → 0.0.15
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/mappers/operation-mapper.d.ts +3 -0
- package/cjs/dist/mappers/operation-mapper.js +95 -0
- package/cjs/dist/react/ItemDetails.d.ts +0 -31
- package/cjs/dist/react/ItemDetails.js +2 -23
- package/cjs/dist/react/OLO.d.ts +3 -2
- package/cjs/dist/react/OLOMenus.d.ts +20 -0
- package/cjs/dist/react/OLOMenus.js +22 -0
- package/cjs/dist/react/Settings.d.ts +160 -0
- package/cjs/dist/react/Settings.js +94 -0
- package/cjs/dist/react/core/ItemDetails.js +3 -1
- package/cjs/dist/react/core/OLO.js +16 -2
- package/cjs/dist/react/core/OLOMenus.d.ts +7 -0
- package/cjs/dist/react/core/OLOMenus.js +12 -0
- package/cjs/dist/react/core/Settings.d.ts +157 -0
- package/cjs/dist/react/core/Settings.js +192 -0
- 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 +2 -0
- package/cjs/dist/services/fulfillments-service.d.ts +13 -0
- package/cjs/dist/services/fulfillments-service.js +64 -0
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +1 -0
- package/cjs/dist/services/item-details-service.js +1 -1
- package/cjs/dist/services/olo-settings-service.d.ts +14 -8
- package/cjs/dist/services/olo-settings-service.js +24 -5
- package/cjs/dist/types/fulfillments-types.d.ts +33 -0
- package/cjs/dist/types/fulfillments-types.js +7 -0
- package/cjs/dist/types/operation.d.ts +57 -0
- package/cjs/dist/types/operation.js +1 -0
- package/cjs/dist/utils/fulfillments-utils.d.ts +23 -0
- package/cjs/dist/utils/fulfillments-utils.js +144 -0
- package/dist/mappers/operation-mapper.d.ts +3 -0
- package/dist/mappers/operation-mapper.js +95 -0
- package/dist/react/ItemDetails.d.ts +0 -31
- package/dist/react/ItemDetails.js +2 -23
- package/dist/react/OLO.d.ts +3 -2
- package/dist/react/OLOMenus.d.ts +20 -0
- package/dist/react/OLOMenus.js +22 -0
- package/dist/react/Settings.d.ts +160 -0
- package/dist/react/Settings.js +94 -0
- package/dist/react/core/ItemDetails.js +3 -1
- package/dist/react/core/OLO.js +16 -2
- package/dist/react/core/OLOMenus.d.ts +7 -0
- package/dist/react/core/OLOMenus.js +12 -0
- package/dist/react/core/Settings.d.ts +157 -0
- package/dist/react/core/Settings.js +192 -0
- 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 +2 -0
- package/dist/services/fulfillments-service.d.ts +13 -0
- package/dist/services/fulfillments-service.js +64 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/item-details-service.js +1 -1
- package/dist/services/olo-settings-service.d.ts +14 -8
- package/dist/services/olo-settings-service.js +24 -5
- package/dist/types/fulfillments-types.d.ts +33 -0
- package/dist/types/fulfillments-types.js +7 -0
- package/dist/types/operation.d.ts +57 -0
- package/dist/types/operation.js +1 -0
- package/dist/utils/fulfillments-utils.d.ts +23 -0
- package/dist/utils/fulfillments-utils.js +144 -0
- package/package.json +5 -5
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { DispatchType } from './fulfillments-types.js';
|
|
2
|
+
export type MinMaxRange = {
|
|
3
|
+
min: number;
|
|
4
|
+
max: number;
|
|
5
|
+
};
|
|
6
|
+
export type AsapScheduling = {
|
|
7
|
+
maxInMinutes?: number;
|
|
8
|
+
rangeInMinutes?: MinMaxRange;
|
|
9
|
+
};
|
|
10
|
+
export type PreorderScheduling = {
|
|
11
|
+
timeWindowDuration: number;
|
|
12
|
+
timeInAdvance: MinMaxRange;
|
|
13
|
+
};
|
|
14
|
+
export type OperationType = 'PRE_ORDER' | 'ASAP';
|
|
15
|
+
type BaseOperation = {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
19
|
+
export interface StreetAddress {
|
|
20
|
+
apt?: String;
|
|
21
|
+
formattedAddressLine?: String;
|
|
22
|
+
name?: String;
|
|
23
|
+
number?: String;
|
|
24
|
+
}
|
|
25
|
+
export interface Address {
|
|
26
|
+
addressLine?: String;
|
|
27
|
+
addressLine2?: String;
|
|
28
|
+
city?: String;
|
|
29
|
+
country?: String;
|
|
30
|
+
countryFullname?: String;
|
|
31
|
+
formattedAddress?: String;
|
|
32
|
+
hint?: String;
|
|
33
|
+
postalCode?: String;
|
|
34
|
+
streetAddress?: StreetAddress;
|
|
35
|
+
subdivision?: String;
|
|
36
|
+
subdivisionFullname?: String;
|
|
37
|
+
}
|
|
38
|
+
export type OSLocation = {
|
|
39
|
+
name: string;
|
|
40
|
+
address?: Address;
|
|
41
|
+
default?: boolean;
|
|
42
|
+
timeZone?: string;
|
|
43
|
+
};
|
|
44
|
+
export type Operation = BaseOperation & {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
fulfillmentIds: string[];
|
|
47
|
+
asapOptions?: AsapScheduling;
|
|
48
|
+
allowAsapFutureHandling?: boolean;
|
|
49
|
+
businessDaysAheadHandlingOptions?: number;
|
|
50
|
+
operationType: OperationType;
|
|
51
|
+
preOrderOptions?: PreorderScheduling;
|
|
52
|
+
defaultDispatchType?: DispatchType;
|
|
53
|
+
operationGroupId: string;
|
|
54
|
+
locationId: string;
|
|
55
|
+
locationDetails?: OSLocation;
|
|
56
|
+
};
|
|
57
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as operationsSDK from '@wix/auto_sdk_restaurants_operations';
|
|
2
|
+
import { TimeSlot } from '../types/fulfillments-types.js';
|
|
3
|
+
export declare const createTimeSlotId: (startTime: Date, endTime: Date, maxTimeOptions?: number) => string;
|
|
4
|
+
export declare function hasSameByField<T>(field: keyof T, arr: T[]): boolean;
|
|
5
|
+
export declare function getMinValueObjects<T>(key: keyof T, arr: T[]): T[];
|
|
6
|
+
export declare function getMinTime(info: operationsSDK.FulfillmentInfo): number;
|
|
7
|
+
export declare function getFastestTimeOptionsByFulfillmentInfo(arr: operationsSDK.FulfillmentInfo[]): operationsSDK.FulfillmentInfo[];
|
|
8
|
+
export declare function getSlowestTimeOptionByFulfillmentInfo(arr: operationsSDK.FulfillmentInfo[]): operationsSDK.FulfillmentInfo;
|
|
9
|
+
export declare const createTimeRangeByFulfillmentInfo: (arr: operationsSDK.FulfillmentInfo[]) => {
|
|
10
|
+
maxTimeOptions: number | undefined;
|
|
11
|
+
durationRangeOptions?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
durationRangeOptions: {
|
|
14
|
+
minDuration: number | undefined;
|
|
15
|
+
maxDuration: number | undefined;
|
|
16
|
+
};
|
|
17
|
+
maxTimeOptions?: undefined;
|
|
18
|
+
};
|
|
19
|
+
export declare function hasSameTime(arr: operationsSDK.FulfillmentDetails[]): boolean;
|
|
20
|
+
export declare const resolveDifferentMinOrderPriceOptionByFulfillmentInfo: (fulfillmentInfo: operationsSDK.FulfillmentInfo[]) => operationsSDK.FulfillmentInfo | undefined;
|
|
21
|
+
export declare const resolveSameMinOrderPriceOptionByFulfillmentInfo: (fulfillmentInfo: operationsSDK.FulfillmentInfo[]) => operationsSDK.FulfillmentInfo;
|
|
22
|
+
export declare const resolveFulfillmentInfo: (fulfillmentInfo: operationsSDK.FulfillmentInfo[]) => operationsSDK.FulfillmentInfo | undefined;
|
|
23
|
+
export declare const processFulfillmentTimeSlotByOperationList: (operationTimeSlot: operationsSDK.TimeSlotForOperation) => [string, TimeSlot[] | undefined];
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as operationsSDK from '@wix/auto_sdk_restaurants_operations';
|
|
2
|
+
import { DispatchType } from '../types/fulfillments-types.js';
|
|
3
|
+
export const createTimeSlotId = (startTime, endTime, maxTimeOptions = 0) =>
|
|
4
|
+
// maxTimeOptions is used to avoid collisions when order pacing is enabled
|
|
5
|
+
`${startTime?.toUTCString()}-${endTime?.toUTCString()}-${maxTimeOptions}`;
|
|
6
|
+
export function hasSameByField(field, arr) {
|
|
7
|
+
const [first, ...rest] = arr;
|
|
8
|
+
return rest.every((item) => item[field] === first?.[field]);
|
|
9
|
+
}
|
|
10
|
+
export function getMinValueObjects(key, arr) {
|
|
11
|
+
return arr.slice(1).reduce((min, item) => {
|
|
12
|
+
if (Number(item[key]) < Number(min[0]?.[key])) {
|
|
13
|
+
return [item];
|
|
14
|
+
}
|
|
15
|
+
else if (Number(item[key]) === Number(min[0]?.[key])) {
|
|
16
|
+
return [...min, item];
|
|
17
|
+
}
|
|
18
|
+
return min;
|
|
19
|
+
}, (arr[0] ? [arr[0]] : []));
|
|
20
|
+
}
|
|
21
|
+
export function getMinTime(info) {
|
|
22
|
+
return info.durationRange
|
|
23
|
+
? Number(info.durationRange.minDuration)
|
|
24
|
+
: Number(info.maxTime);
|
|
25
|
+
}
|
|
26
|
+
export function getFastestTimeOptionsByFulfillmentInfo(arr) {
|
|
27
|
+
const [first, ...rest] = arr;
|
|
28
|
+
if (!first) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return rest.reduce((fastestOptions, current) => {
|
|
32
|
+
const currentTime = getMinTime(current);
|
|
33
|
+
const fastestTime = getMinTime(fastestOptions[0]);
|
|
34
|
+
if (currentTime < fastestTime) {
|
|
35
|
+
return [current];
|
|
36
|
+
}
|
|
37
|
+
else if (currentTime === fastestTime) {
|
|
38
|
+
return [...fastestOptions, current];
|
|
39
|
+
}
|
|
40
|
+
return fastestOptions;
|
|
41
|
+
}, [first]);
|
|
42
|
+
}
|
|
43
|
+
export function getSlowestTimeOptionByFulfillmentInfo(arr) {
|
|
44
|
+
return arr.reduce((max, item) => {
|
|
45
|
+
const { durationRange, maxTime: maxTimeOptions } = item;
|
|
46
|
+
let maxTime;
|
|
47
|
+
if (max.durationRange) {
|
|
48
|
+
maxTime = Number(max.durationRange?.maxDuration || 0);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
maxTime = Number(max.maxTime || 0);
|
|
52
|
+
}
|
|
53
|
+
if (durationRange) {
|
|
54
|
+
return Number(durationRange.maxDuration) > maxTime ? item : max;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return Number(maxTimeOptions) > maxTime ? item : max;
|
|
58
|
+
}
|
|
59
|
+
}, {});
|
|
60
|
+
}
|
|
61
|
+
export const createTimeRangeByFulfillmentInfo = (arr) => {
|
|
62
|
+
const fastestOption = getFastestTimeOptionsByFulfillmentInfo(arr)[0];
|
|
63
|
+
const slowestOption = getSlowestTimeOptionByFulfillmentInfo(arr);
|
|
64
|
+
const minDuration = fastestOption?.durationRange?.minDuration ?? fastestOption?.maxTime;
|
|
65
|
+
const maxDuration = slowestOption.durationRange?.maxDuration ?? slowestOption.maxTime;
|
|
66
|
+
if (minDuration === maxDuration) {
|
|
67
|
+
return { maxTimeOptions: minDuration };
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return { durationRangeOptions: { minDuration, maxDuration } };
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
export function hasSameTime(arr) {
|
|
74
|
+
return (hasSameByField('fulfillmentTimeType', arr) &&
|
|
75
|
+
(arr[0]?.fulfillmentTimeType === operationsSDK.FulfillmentTimeType.MAX_TIME
|
|
76
|
+
? hasSameByField('maxTimeOptions', arr)
|
|
77
|
+
: arr.every((details) => {
|
|
78
|
+
const { durationRangeOptions } = details;
|
|
79
|
+
return (durationRangeOptions?.maxDuration ===
|
|
80
|
+
arr[0]?.durationRangeOptions?.maxDuration &&
|
|
81
|
+
durationRangeOptions?.minDuration ===
|
|
82
|
+
arr[0]?.durationRangeOptions?.minDuration);
|
|
83
|
+
})));
|
|
84
|
+
}
|
|
85
|
+
export const resolveDifferentMinOrderPriceOptionByFulfillmentInfo = (fulfillmentInfo) => {
|
|
86
|
+
const hasSameFee = hasSameByField('fee', fulfillmentInfo);
|
|
87
|
+
if (hasSameFee && hasSameTime(fulfillmentInfo)) {
|
|
88
|
+
// if fee and time are the same, return the object with the min order price with the min free delivery price threshold
|
|
89
|
+
return getMinValueObjects('freeFulfillmentPriceThreshold', getMinValueObjects('minOrderPrice', fulfillmentInfo))[0];
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// if the fee is the same and time is different, return the fee
|
|
93
|
+
const fee = hasSameFee ? fulfillmentInfo[0]?.fee : undefined;
|
|
94
|
+
// if free delivery price threshold is the same, return free delivery price threshold
|
|
95
|
+
const freeFulfillmentPriceThreshold = hasSameByField('freeFulfillmentPriceThreshold', fulfillmentInfo)
|
|
96
|
+
? fulfillmentInfo[0]?.freeFulfillmentPriceThreshold
|
|
97
|
+
: undefined;
|
|
98
|
+
// create a time range object from all the fulfillments
|
|
99
|
+
return {
|
|
100
|
+
fee,
|
|
101
|
+
...createTimeRangeByFulfillmentInfo(fulfillmentInfo),
|
|
102
|
+
freeFulfillmentPriceThreshold,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
export const resolveSameMinOrderPriceOptionByFulfillmentInfo = (fulfillmentInfo) => {
|
|
107
|
+
// filtering fulfillment details by order of precedent: fee, time, free delivery price threshold
|
|
108
|
+
const cheapestFulfillmentInfo = getMinValueObjects('fee', fulfillmentInfo);
|
|
109
|
+
const fastestFulfillmentInfo = getFastestTimeOptionsByFulfillmentInfo(cheapestFulfillmentInfo);
|
|
110
|
+
return getMinValueObjects('freeFulfillmentPriceThreshold', fastestFulfillmentInfo)[0];
|
|
111
|
+
};
|
|
112
|
+
export const resolveFulfillmentInfo = (fulfillmentInfo) => {
|
|
113
|
+
if (hasSameByField('minOrderPrice', fulfillmentInfo)) {
|
|
114
|
+
return resolveSameMinOrderPriceOptionByFulfillmentInfo(fulfillmentInfo);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return resolveDifferentMinOrderPriceOptionByFulfillmentInfo(fulfillmentInfo);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
export const processFulfillmentTimeSlotByOperationList = (operationTimeSlot) => {
|
|
121
|
+
return [
|
|
122
|
+
operationTimeSlot.operationId ?? '',
|
|
123
|
+
operationTimeSlot.timeslotsPerFulfillmentType?.map((fulfillmentTimeSlot) => {
|
|
124
|
+
const { timeSlot, fulfilmentType, fulfillmentInfo } = fulfillmentTimeSlot;
|
|
125
|
+
const { startTime, endTime, orderSchedulingType } = timeSlot ?? {};
|
|
126
|
+
const selectedFulfillmentInfo = resolveFulfillmentInfo(fulfillmentInfo);
|
|
127
|
+
const fulfillmentDetails = {
|
|
128
|
+
maxTimeOptions: selectedFulfillmentInfo?.maxTime,
|
|
129
|
+
durationRangeOptions: selectedFulfillmentInfo?.durationRange,
|
|
130
|
+
...selectedFulfillmentInfo,
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
id: createTimeSlotId(startTime, endTime),
|
|
134
|
+
startTime: startTime,
|
|
135
|
+
endTime: endTime,
|
|
136
|
+
dispatchType: fulfilmentType === 'DELIVERY'
|
|
137
|
+
? DispatchType.DELIVERY
|
|
138
|
+
: DispatchType.PICKUP,
|
|
139
|
+
startsNow: orderSchedulingType === operationsSDK.OrderSchedulingType.ASAP,
|
|
140
|
+
fulfillmentDetails,
|
|
141
|
+
};
|
|
142
|
+
}),
|
|
143
|
+
];
|
|
144
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as operationsSDK from '@wix/auto_sdk_restaurants_operations';
|
|
2
|
+
import { DispatchType } from '../types/fulfillments-types.js';
|
|
3
|
+
const TIME_UNIT_MULTIPLIER = {
|
|
4
|
+
MINUTES: 1,
|
|
5
|
+
UNKNOWN_TIME_UNIT: 0,
|
|
6
|
+
DAYS: 24 * 60,
|
|
7
|
+
HOURS: 60,
|
|
8
|
+
};
|
|
9
|
+
const getAsapOptionsFromOperation = (operation) => {
|
|
10
|
+
if (!operation.orderScheduling?.asapOptions) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const { timeRangeOptions, maxTimeOptions } = operation.orderScheduling.asapOptions.preparationTime || {};
|
|
14
|
+
if (maxTimeOptions &&
|
|
15
|
+
maxTimeOptions.duration !== null &&
|
|
16
|
+
maxTimeOptions.duration !== undefined &&
|
|
17
|
+
maxTimeOptions.timeUnit) {
|
|
18
|
+
return {
|
|
19
|
+
maxInMinutes: maxTimeOptions.duration * TIME_UNIT_MULTIPLIER[maxTimeOptions.timeUnit],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (timeRangeOptions &&
|
|
23
|
+
timeRangeOptions.timeUnit &&
|
|
24
|
+
timeRangeOptions.maxDuration !== undefined &&
|
|
25
|
+
timeRangeOptions.maxDuration !== null &&
|
|
26
|
+
timeRangeOptions.minDuration !== undefined &&
|
|
27
|
+
timeRangeOptions.minDuration !== null) {
|
|
28
|
+
return {
|
|
29
|
+
rangeInMinutes: {
|
|
30
|
+
min: timeRangeOptions.minDuration *
|
|
31
|
+
TIME_UNIT_MULTIPLIER[timeRangeOptions.timeUnit],
|
|
32
|
+
max: timeRangeOptions.maxDuration *
|
|
33
|
+
TIME_UNIT_MULTIPLIER[timeRangeOptions.timeUnit],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function getPreOrderOptions(operation) {
|
|
39
|
+
if (!operation.orderScheduling?.preorderOptions) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const timeBoundedOptions = operation.orderScheduling?.preorderOptions?.method?.timeBoundedOptions;
|
|
43
|
+
if (!timeBoundedOptions) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { maxTimeInAdvance, minTimeInAdvance } = timeBoundedOptions;
|
|
47
|
+
const max = TIME_UNIT_MULTIPLIER[maxTimeInAdvance?.timeUnit] *
|
|
48
|
+
maxTimeInAdvance?.duration;
|
|
49
|
+
const min = TIME_UNIT_MULTIPLIER[minTimeInAdvance?.timeUnit] *
|
|
50
|
+
minTimeInAdvance?.duration;
|
|
51
|
+
const timeWindowsOptions = operation.orderScheduling?.preorderOptions?.fulfillmentTimesDisplay
|
|
52
|
+
?.timeWindowsOptions;
|
|
53
|
+
const timeWindowDuration = TIME_UNIT_MULTIPLIER[timeWindowsOptions.timeUnit] *
|
|
54
|
+
timeWindowsOptions.duration;
|
|
55
|
+
return {
|
|
56
|
+
timeInAdvance: { min, max },
|
|
57
|
+
timeWindowDuration,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function getOperationType(operation) {
|
|
61
|
+
switch (operation.orderScheduling?.type) {
|
|
62
|
+
case operationsSDK.SchedulingType.PREORDER:
|
|
63
|
+
return 'PRE_ORDER';
|
|
64
|
+
case operationsSDK.SchedulingType.ASAP:
|
|
65
|
+
default:
|
|
66
|
+
return 'ASAP';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export const OperationMapper = (operation) => {
|
|
70
|
+
const { asapFutureHandlingType, businessDaysAheadHandlingOptions } = operation.orderScheduling?.asapOptions || {};
|
|
71
|
+
const { daysCount } = businessDaysAheadHandlingOptions || {};
|
|
72
|
+
const allowAsapFutureHandling = asapFutureHandlingType ===
|
|
73
|
+
operationsSDK.AsapFutureHandlingType.BUSINESS_DAYS_AHEAD_HANDLING &&
|
|
74
|
+
Number(daysCount) >= 0;
|
|
75
|
+
return {
|
|
76
|
+
id: operation._id || '',
|
|
77
|
+
name: operation.name || '',
|
|
78
|
+
// @ts-expect-error - operation is not typed
|
|
79
|
+
enabled: !!operation.enabled,
|
|
80
|
+
fulfillmentIds: operation.fulfillmentIds || [],
|
|
81
|
+
asapOptions: getAsapOptionsFromOperation(operation),
|
|
82
|
+
preOrderOptions: getPreOrderOptions(operation),
|
|
83
|
+
operationType: getOperationType(operation),
|
|
84
|
+
allowAsapFutureHandling,
|
|
85
|
+
businessDaysAheadHandlingOptions: daysCount ?? undefined,
|
|
86
|
+
defaultDispatchType: operation.defaultFulfillmentType ===
|
|
87
|
+
operationsSDK.FulfillmentType.DELIVERY
|
|
88
|
+
? DispatchType.DELIVERY
|
|
89
|
+
: DispatchType.PICKUP,
|
|
90
|
+
operationGroupId: operation.operationGroupId || '',
|
|
91
|
+
locationId: operation.businessLocationId || '',
|
|
92
|
+
// @ts-expect-error - operation is not typed
|
|
93
|
+
locationDetails: operation.businessLocationDetails,
|
|
94
|
+
};
|
|
95
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Commerce } from '@wix/ecom/components';
|
|
3
|
-
import { type LineItem } from '@wix/ecom/services';
|
|
4
3
|
import { type AsChildChildren } from '@wix/headless-utils/react';
|
|
5
4
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
6
5
|
import { EnhancedModifier, EnhancedModifierGroup, EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
@@ -180,35 +179,6 @@ export interface ItemDetailsVariantsProps {
|
|
|
180
179
|
variantPriceClassName?: string;
|
|
181
180
|
}
|
|
182
181
|
export declare const Variants: React.ForwardRefExoticComponent<ItemDetailsVariantsProps & React.RefAttributes<HTMLElement>>;
|
|
183
|
-
export interface AddToCartActionProps {
|
|
184
|
-
/** Whether to render as a child component */
|
|
185
|
-
asChild?: boolean;
|
|
186
|
-
/** Text label for the button */
|
|
187
|
-
label: string;
|
|
188
|
-
/** Custom render function when using asChild */
|
|
189
|
-
lineItems: LineItem[];
|
|
190
|
-
/** CSS classes to apply to the button */
|
|
191
|
-
className?: string;
|
|
192
|
-
/** Content to display when loading */
|
|
193
|
-
loadingState?: string | React.ReactNode;
|
|
194
|
-
children?: React.ReactNode;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Add to Cart button for the menu item.
|
|
198
|
-
* Triggers the action to add the selected item (and its modifiers/variants) to the cart.
|
|
199
|
-
*
|
|
200
|
-
* @component
|
|
201
|
-
* @example
|
|
202
|
-
* ```tsx
|
|
203
|
-
* <ItemDetails>
|
|
204
|
-
* <AddToCart
|
|
205
|
-
* label="Add to Cart"
|
|
206
|
-
* lineItems={[{ catalogReference: { ... }, quantity: 1 }]}
|
|
207
|
-
* />
|
|
208
|
-
* </ItemDetails>
|
|
209
|
-
* ```
|
|
210
|
-
*/
|
|
211
|
-
export declare const AddToCart: React.ForwardRefExoticComponent<AddToCartActionProps & React.RefAttributes<HTMLButtonElement>>;
|
|
212
182
|
/**
|
|
213
183
|
* Multi-line text input component for special requests or instructions.
|
|
214
184
|
* Provides a textarea for customers to add custom notes or modifications.
|
|
@@ -256,7 +226,6 @@ export interface AddToCartButtonProps extends Omit<React.ComponentPropsWithoutRe
|
|
|
256
226
|
children?: React.ReactNode;
|
|
257
227
|
className?: string;
|
|
258
228
|
label?: string;
|
|
259
|
-
onClick?: () => void;
|
|
260
229
|
}
|
|
261
230
|
export interface ItemDetailsQuantityProps {
|
|
262
231
|
children: React.ReactNode;
|
|
@@ -89,29 +89,8 @@ export const Variants = React.forwardRef(({ children, className, asChild, varian
|
|
|
89
89
|
} }));
|
|
90
90
|
});
|
|
91
91
|
Variants.displayName = 'ItemDetails.Variants';
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
* Triggers the action to add the selected item (and its modifiers/variants) to the cart.
|
|
95
|
-
*
|
|
96
|
-
* @component
|
|
97
|
-
* @example
|
|
98
|
-
* ```tsx
|
|
99
|
-
* <ItemDetails>
|
|
100
|
-
* <AddToCart
|
|
101
|
-
* label="Add to Cart"
|
|
102
|
-
* lineItems={[{ catalogReference: { ... }, quantity: 1 }]}
|
|
103
|
-
* />
|
|
104
|
-
* </ItemDetails>
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
export const AddToCart = React.forwardRef(({ lineItems, className, label, ...props }, ref) => {
|
|
108
|
-
return (_jsx(Commerce.Actions.AddToCart, { ref: ref, asChild: false, label: label, className: className, lineItems: lineItems, children: props.children }));
|
|
109
|
-
});
|
|
110
|
-
AddToCart.displayName = 'AddToCart';
|
|
111
|
-
export const AddToCartButton = ({ asChild = false, children, className, onClick, label = 'Add to cart', ...props }) => {
|
|
112
|
-
return (_jsx(CoreItemDetails.LineItemComponent, { children: ({ lineItem }) => (_jsx(AsChildSlot, { asChild: asChild, className: className, customElement: children, customElementProps: {
|
|
113
|
-
onClick,
|
|
114
|
-
}, children: _jsx(Commerce.Actions.AddToCart, { asChild: false, label: label, className: className, lineItems: [lineItem], ...props, children: children }) })) }));
|
|
92
|
+
export const AddToCartButton = ({ asChild, children, className, label = 'Add to cart', ...props }) => {
|
|
93
|
+
return (_jsx(CoreItemDetails.LineItemComponent, { children: ({ lineItem }) => (_jsx(Commerce.Actions.AddToCart, { asChild: asChild, label: label, className: className, lineItems: [lineItem], ...props, children: children })) }));
|
|
115
94
|
};
|
|
116
95
|
export const Quantity = ({ children }) => {
|
|
117
96
|
return (_jsx(CoreItemDetails.QuantityComponent, { children: ({ quantity, onValueChange, }) => (_jsx(QuantityComponent.Root, { onValueChange: onValueChange, initialValue: quantity, children: children })) }));
|
package/dist/react/OLO.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
3
|
+
import { OLOSettingsServiceConfig } from '../services/olo-settings-service.js';
|
|
3
4
|
interface OLORootProps {
|
|
4
5
|
/** The ID of the item to load */
|
|
5
6
|
itemId?: string;
|
|
6
7
|
/** Pre-loaded item service config (optional) */
|
|
7
|
-
itemServiceConfig?:
|
|
8
|
+
itemServiceConfig?: ItemServiceConfig;
|
|
8
9
|
/** Pre-loaded OLO settings service config (optional) */
|
|
9
|
-
oloSettingsServiceConfig?:
|
|
10
|
+
oloSettingsServiceConfig?: OLOSettingsServiceConfig;
|
|
10
11
|
/** Children render prop that receives the service state */
|
|
11
12
|
children: React.ReactNode;
|
|
12
13
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type MenusServiceConfig } from '@wix/headless-restaurants-menus/services';
|
|
3
|
+
declare enum TestIds {
|
|
4
|
+
menusRoot = "menus-root"
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Menus.Root
|
|
8
|
+
* Container for the menus context and data loading.
|
|
9
|
+
* Does not render if there are no menus.
|
|
10
|
+
*/
|
|
11
|
+
export interface MenusRootProps {
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
config: MenusServiceConfig;
|
|
14
|
+
}
|
|
15
|
+
export declare const Root: React.ForwardRefExoticComponent<MenusRootProps & React.RefAttributes<HTMLElement>>;
|
|
16
|
+
export declare const OLOMenus: {
|
|
17
|
+
Root: React.ForwardRefExoticComponent<MenusRootProps & React.RefAttributes<HTMLElement>>;
|
|
18
|
+
TestIds: typeof TestIds;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Menus } from '@wix/headless-restaurants-menus/react';
|
|
4
|
+
import * as CoreOLOMenus from './core/OLOMenus.js';
|
|
5
|
+
// =======================
|
|
6
|
+
// TestIds Enum
|
|
7
|
+
// =======================
|
|
8
|
+
var TestIds;
|
|
9
|
+
(function (TestIds) {
|
|
10
|
+
// Container Level
|
|
11
|
+
TestIds["menusRoot"] = "menus-root";
|
|
12
|
+
})(TestIds || (TestIds = {}));
|
|
13
|
+
export const Root = React.forwardRef((props) => {
|
|
14
|
+
const { children, config } = props;
|
|
15
|
+
return (_jsx(CoreOLOMenus.Root, { "data-testid": TestIds.menusRoot, config: config, children: (updatedConfig) => (_jsx(Menus.Root, { "data-testid": TestIds.menusRoot, config: updatedConfig, children: children })) }));
|
|
16
|
+
});
|
|
17
|
+
Root.displayName = 'Menus.Root';
|
|
18
|
+
// Compose Menus namespace
|
|
19
|
+
export const OLOMenus = {
|
|
20
|
+
Root,
|
|
21
|
+
TestIds,
|
|
22
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
3
|
+
/**
|
|
4
|
+
* Root headless component for OLO Settings
|
|
5
|
+
* Provides access to current details, fulfillment options, location, and extra data
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <Settings.Root>
|
|
10
|
+
* {({ currentDetails, currentFulfillment, currentLocation, extraData, isLoading, error }) => (
|
|
11
|
+
* isLoading ? (
|
|
12
|
+
* <div>Loading settings...</div>
|
|
13
|
+
* ) : error ? (
|
|
14
|
+
* <div>Error: {error}</div>
|
|
15
|
+
* ) : (
|
|
16
|
+
* <div>
|
|
17
|
+
* <h2>{currentDetails.name}</h2>
|
|
18
|
+
* <p>{currentDetails.address}</p>
|
|
19
|
+
* <p>Accepting Orders: {extraData.acceptingOrders ? 'Yes' : 'No'}</p>
|
|
20
|
+
* <p>Delivery Fee: ${extraData.deliveryFee}</p>
|
|
21
|
+
* <p>Min Order: ${extraData.minOrderAmount}</p>
|
|
22
|
+
* <p>Free Delivery: ${extraData.freeDeliveryThreshold}</p>
|
|
23
|
+
* </div>
|
|
24
|
+
* )
|
|
25
|
+
* )}
|
|
26
|
+
* </Settings.Root>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
interface CurrentTimeSlotProps {
|
|
30
|
+
/** Children render prop that receives the current details */
|
|
31
|
+
children?: AsChildChildren<{
|
|
32
|
+
timeSlot: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** CSS classes to apply to the default element */
|
|
35
|
+
className?: string;
|
|
36
|
+
/** Whether to render as a child component */
|
|
37
|
+
asChild?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Headless component for current store details
|
|
41
|
+
* Provides access to store name, address, contact info, and hours
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <Settings.CurrentTimeSlot>
|
|
46
|
+
* {({ details, hasDetails }) => (
|
|
47
|
+
* hasDetails ? (
|
|
48
|
+
* <div>
|
|
49
|
+
* <h3>{details.name}</h3>
|
|
50
|
+
* <p>{details.address}</p>
|
|
51
|
+
* <p>{details.phone}</p>
|
|
52
|
+
* <p>{details.email}</p>
|
|
53
|
+
* </div>
|
|
54
|
+
* ) : (
|
|
55
|
+
* <div>No store details available</div>
|
|
56
|
+
* )
|
|
57
|
+
* )}
|
|
58
|
+
* </Settings.CurrentTimeSlot>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare const CurrentTimeSlot: React.ForwardRefExoticComponent<CurrentTimeSlotProps & React.RefAttributes<HTMLElement>>;
|
|
62
|
+
/**
|
|
63
|
+
* Headless component for current fulfillment options
|
|
64
|
+
* Provides access to pickup, delivery, and dine-in options
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```tsx
|
|
68
|
+
* <Settings.CurrentFulfillment>
|
|
69
|
+
* {({ fulfillment, availableOptions }) => (
|
|
70
|
+
* <div>
|
|
71
|
+
* <h3>Available Options:</h3>
|
|
72
|
+
* {availableOptions.map(option => (
|
|
73
|
+
* <div key={option}>
|
|
74
|
+
* {option}: {fulfillment[option]?.enabled ? 'Available' : 'Unavailable'}
|
|
75
|
+
* {fulfillment[option]?.estimatedTime && (
|
|
76
|
+
* <span> - {fulfillment[option].estimatedTime} mins</span>
|
|
77
|
+
* )}
|
|
78
|
+
* </div>
|
|
79
|
+
* ))}
|
|
80
|
+
* </div>
|
|
81
|
+
* )}
|
|
82
|
+
* </Settings.CurrentFulfillment>
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
interface CurrentLocationProps {
|
|
86
|
+
/** Whether to render as a child component */
|
|
87
|
+
asChild?: boolean;
|
|
88
|
+
/** CSS classes to apply to the default element */
|
|
89
|
+
className?: string;
|
|
90
|
+
/** Children render prop that receives the location data */
|
|
91
|
+
children?: AsChildChildren<{
|
|
92
|
+
currentLocation: {
|
|
93
|
+
name: string;
|
|
94
|
+
};
|
|
95
|
+
hasLocation: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Headless component for current location data
|
|
100
|
+
* Provides access to store location and coordinates
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* <Settings.CurrentLocation>
|
|
105
|
+
* {({ location, hasLocation }) => (
|
|
106
|
+
* <div>
|
|
107
|
+
* <p>{currentLocation.name}</p>
|
|
108
|
+
* {hasLocation && (
|
|
109
|
+
* <p>Coordinates: {location.latitude}, {location.longitude}</p>
|
|
110
|
+
* )}
|
|
111
|
+
* </div>
|
|
112
|
+
* )}
|
|
113
|
+
* </Settings.CurrentLocation>
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare const CurrentLocation: React.FC<CurrentLocationProps>;
|
|
117
|
+
interface ExtraDataProps {
|
|
118
|
+
/** Children render prop that receives the extra settings data */
|
|
119
|
+
children: (props: {
|
|
120
|
+
extraData: {
|
|
121
|
+
acceptingOrders: boolean;
|
|
122
|
+
deliveryFee?: number;
|
|
123
|
+
minOrderAmount?: number;
|
|
124
|
+
freeDeliveryThreshold?: number;
|
|
125
|
+
taxRate?: number;
|
|
126
|
+
serviceCharge?: number;
|
|
127
|
+
isOnline?: boolean;
|
|
128
|
+
orderingDisabledReason?: string;
|
|
129
|
+
};
|
|
130
|
+
hasExtraData: boolean;
|
|
131
|
+
}) => React.ReactNode;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Headless component for extra settings data
|
|
135
|
+
* Provides access to ordering status, fees, and thresholds
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```tsx
|
|
139
|
+
* <Settings.ExtraData>
|
|
140
|
+
* {({ extraData, hasExtraData }) => (
|
|
141
|
+
* hasExtraData ? (
|
|
142
|
+
* <div>
|
|
143
|
+
* <p>Status: {extraData.acceptingOrders ? 'Open' : 'Closed'}</p>
|
|
144
|
+
* {extraData.orderingDisabledReason && (
|
|
145
|
+
* <p>Reason: {extraData.orderingDisabledReason}</p>
|
|
146
|
+
* )}
|
|
147
|
+
* <p>Delivery Fee: ${extraData.deliveryFee}</p>
|
|
148
|
+
* <p>Min Order: ${extraData.minOrderAmount}</p>
|
|
149
|
+
* <p>Free Delivery: ${extraData.freeDeliveryThreshold}</p>
|
|
150
|
+
* <p>Tax Rate: {extraData.taxRate}%</p>
|
|
151
|
+
* </div>
|
|
152
|
+
* ) : (
|
|
153
|
+
* <div>No additional settings available</div>
|
|
154
|
+
* )
|
|
155
|
+
* )}
|
|
156
|
+
* </Settings.ExtraData>
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare const ExtraData: React.FC<ExtraDataProps>;
|
|
160
|
+
export {};
|