@wix/headless-restaurants-olo 0.0.8 → 0.0.9
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/ItemDetails.d.ts +14 -0
- package/cjs/dist/react/ItemDetails.js +16 -0
- package/cjs/dist/react/core/ItemDetails.d.ts +11 -0
- package/cjs/dist/react/core/ItemDetails.js +25 -8
- package/cjs/dist/services/common-types.d.ts +16 -0
- package/cjs/dist/services/common-types.js +8 -1
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +1 -0
- package/cjs/dist/services/item-details-service.d.ts +5 -0
- package/cjs/dist/services/item-details-service.js +27 -19
- package/cjs/dist/services/olo-settings-service.d.ts +5 -0
- package/cjs/dist/services/olo-settings-service.js +10 -0
- package/cjs/dist/services/utils.d.ts +20 -0
- package/cjs/dist/services/utils.js +34 -0
- package/dist/react/ItemDetails.d.ts +14 -0
- package/dist/react/ItemDetails.js +16 -0
- package/dist/react/core/ItemDetails.d.ts +11 -0
- package/dist/react/core/ItemDetails.js +25 -8
- package/dist/services/common-types.d.ts +16 -0
- package/dist/services/common-types.js +8 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/item-details-service.d.ts +5 -0
- package/dist/services/item-details-service.js +27 -19
- package/dist/services/olo-settings-service.d.ts +5 -0
- package/dist/services/olo-settings-service.js +10 -0
- package/dist/services/utils.d.ts +20 -0
- package/dist/services/utils.js +34 -0
- package/package.json +2 -2
|
@@ -4,6 +4,7 @@ import { type LineItem } from '@wix/ecom/services';
|
|
|
4
4
|
import { type AsChildChildren } from '@wix/headless-utils/react';
|
|
5
5
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
6
6
|
import { EnhancedModifier, EnhancedModifierGroup, EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
7
|
+
import { AvailabilityStatus, AvailabilityStatusMap } from '../services/common-types.js';
|
|
7
8
|
/**
|
|
8
9
|
* Root component for menu item display and interaction.
|
|
9
10
|
* Provides context for all menu item-related components like name, price, description, image, etc.
|
|
@@ -266,3 +267,16 @@ export interface ItemDetailsQuantityProps {
|
|
|
266
267
|
export declare const AddToCartButton: React.FC<AddToCartButtonProps>;
|
|
267
268
|
export declare const Quantity: React.FC<ItemDetailsQuantityProps>;
|
|
268
269
|
export declare const SpecialRequest: React.ForwardRefExoticComponent<SpecialRequestProps & React.RefAttributes<never>>;
|
|
270
|
+
export interface ItemDetailsAvailabilityProps {
|
|
271
|
+
asChild?: boolean;
|
|
272
|
+
textClassName?: string;
|
|
273
|
+
buttonClassName?: string;
|
|
274
|
+
availabilityStatusMap: AvailabilityStatusMap;
|
|
275
|
+
children: (props: {
|
|
276
|
+
availabilityStatus: AvailabilityStatus;
|
|
277
|
+
availabilityStatusText?: string;
|
|
278
|
+
availabilityStatusButtonText?: string;
|
|
279
|
+
availabilityAction?: () => void;
|
|
280
|
+
}) => React.ReactNode;
|
|
281
|
+
}
|
|
282
|
+
export declare const AvailabilityComponent: React.ForwardRefExoticComponent<ItemDetailsAvailabilityProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -7,6 +7,7 @@ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
|
7
7
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
8
8
|
import { Item, Modifier, ModifierGroup, useModifierContext, } from '@wix/headless-restaurants-menus/react';
|
|
9
9
|
import * as CoreItemDetails from './core/ItemDetails.js';
|
|
10
|
+
import { AvailabilityStatus, } from '../services/common-types.js';
|
|
10
11
|
var TestIds;
|
|
11
12
|
(function (TestIds) {
|
|
12
13
|
TestIds["itemName"] = "item-name";
|
|
@@ -18,6 +19,7 @@ var TestIds;
|
|
|
18
19
|
TestIds["itemLabels"] = "item-labels";
|
|
19
20
|
TestIds["itemVariants"] = "item-variants";
|
|
20
21
|
TestIds["itemModifier"] = "item-modifier";
|
|
22
|
+
TestIds["itemAvailability"] = "item-availability";
|
|
21
23
|
})(TestIds || (TestIds = {}));
|
|
22
24
|
const CheckIcon = () => (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z", fill: "currentColor" }) }));
|
|
23
25
|
export const Root = ({ children, itemDetailsServiceConfig }) => {
|
|
@@ -120,3 +122,17 @@ export const SpecialRequest = React.forwardRef(({ className, labelClassName, pla
|
|
|
120
122
|
return (_jsx(CoreItemDetails.SpecialRequest, { children: ({ value, onChange, }) => (_jsxs(AsChildSlot, { ref: ref, asChild: asChild, className: className, onChange: onChange, "data-testid": TestIds.itemSpecialRequest, customElement: children, customElementProps: { label, value }, content: value, ...props, children: [label && _jsx("label", { className: labelClassName, children: label }), _jsx("textarea", { value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, maxLength: maxLength, rows: rows, className: className, children: value })] })) }));
|
|
121
123
|
});
|
|
122
124
|
SpecialRequest.displayName = 'SpecialRequest';
|
|
125
|
+
export const AvailabilityComponent = React.forwardRef(({ asChild, children, textClassName, buttonClassName, availabilityStatusMap, ...rest }, ref) => {
|
|
126
|
+
return (_jsx(CoreItemDetails.AvailabilityComponent, { availabilityStatusMap: availabilityStatusMap, children: ({ availabilityStatus, availabilityAction, availabilityStatusText, availabilityStatusButtonText, }) => {
|
|
127
|
+
if (availabilityStatus === AvailabilityStatus.AVAILABLE) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return (_jsxs(AsChildSlot, { asChild: asChild, "data-testid": TestIds.itemAvailability, customElement: children, customElementProps: {
|
|
131
|
+
availabilityStatus,
|
|
132
|
+
availabilityStatusText,
|
|
133
|
+
availabilityStatusButtonText,
|
|
134
|
+
availabilityAction,
|
|
135
|
+
}, ref: ref, ...rest, children: [_jsx("p", { className: textClassName, children: availabilityStatusText }), availabilityStatusButtonText && availabilityAction && (_jsx("button", { className: buttonClassName, onClick: availabilityAction, children: availabilityStatusButtonText }))] }));
|
|
136
|
+
} }));
|
|
137
|
+
});
|
|
138
|
+
AvailabilityComponent.displayName = 'AvailabilityComponent';
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { ItemServiceConfig } from '../../services/item-details-service.js';
|
|
4
4
|
import { EnhancedModifier, EnhancedModifierGroup, EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
5
|
+
import { AvailabilityStatus, AvailabilityStatusMap } from '../../services/common-types.js';
|
|
5
6
|
interface ItemDetailsRootProps {
|
|
6
7
|
children: (props: {
|
|
7
8
|
item: unknown;
|
|
@@ -54,4 +55,14 @@ interface ItemDetailsModifiersProps {
|
|
|
54
55
|
singleSelect?: boolean;
|
|
55
56
|
}
|
|
56
57
|
export declare const ModifiersComponent: React.FC<ItemDetailsModifiersProps>;
|
|
58
|
+
interface ItemDetailsAvailabilityProps {
|
|
59
|
+
availabilityStatusMap: AvailabilityStatusMap;
|
|
60
|
+
children: (props: {
|
|
61
|
+
availabilityStatus: AvailabilityStatus;
|
|
62
|
+
availabilityAction?: () => void;
|
|
63
|
+
availabilityStatusText?: string;
|
|
64
|
+
availabilityStatusButtonText?: string;
|
|
65
|
+
}) => React.ReactNode;
|
|
66
|
+
}
|
|
67
|
+
export declare const AvailabilityComponent: React.FC<ItemDetailsAvailabilityProps>;
|
|
57
68
|
export {};
|
|
@@ -5,6 +5,8 @@ import { createServicesMap } from '@wix/services-manager';
|
|
|
5
5
|
import { ItemService, ItemServiceDefinition, loadItemServiceConfig, } from '../../services/item-details-service.js';
|
|
6
6
|
import { OLOSettingsServiceDefinition } from '../../services/olo-settings-service.js';
|
|
7
7
|
import { useItemContext, useModifierGroupContext, } from '@wix/headless-restaurants-menus/react';
|
|
8
|
+
import { AvailabilityStatus, } from '../../services/common-types.js';
|
|
9
|
+
import { convertModifierToFormModifier } from '../../services/utils.js';
|
|
8
10
|
export const Root = ({ children, itemDetailsServiceConfig, }) => {
|
|
9
11
|
const service = useService(OLOSettingsServiceDefinition);
|
|
10
12
|
const selectedItem = service.selectedItem?.get();
|
|
@@ -87,12 +89,9 @@ export const VariantsComponent = ({ children, }) => {
|
|
|
87
89
|
export const ModifiersComponent = ({ children, singleSelect, }) => {
|
|
88
90
|
const service = useService(ItemServiceDefinition);
|
|
89
91
|
const { modifierGroup } = useModifierGroupContext();
|
|
90
|
-
const selectedModifiers = service.selectedModifiers?.get?.() ?? {};
|
|
91
92
|
// Get selected modifier IDs for this group
|
|
92
93
|
const groupId = modifierGroup._id;
|
|
93
|
-
const groupSelectedModifierIds = groupId
|
|
94
|
-
? selectedModifiers[groupId] || []
|
|
95
|
-
: [];
|
|
94
|
+
const groupSelectedModifierIds = service.getSelectedModifiers?.(groupId ?? '');
|
|
96
95
|
const onToggle = (modifierId) => {
|
|
97
96
|
if (groupId) {
|
|
98
97
|
service.toggleModifier?.(groupId, modifierId, singleSelect);
|
|
@@ -102,9 +101,27 @@ export const ModifiersComponent = ({ children, singleSelect, }) => {
|
|
|
102
101
|
selectedModifierIds: groupSelectedModifierIds,
|
|
103
102
|
onToggle,
|
|
104
103
|
modifierGroup,
|
|
105
|
-
modifiers: modifierGroup.modifiers.map(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
modifiers: modifierGroup.modifiers.map(convertModifierToFormModifier),
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
export const AvailabilityComponent = ({ children, availabilityStatusMap, }) => {
|
|
108
|
+
const oloSettingsService = useService(OLOSettingsServiceDefinition);
|
|
109
|
+
const availabilityDispatchAction = oloSettingsService.availabilityDispatchAction?.get?.();
|
|
110
|
+
const itemService = useService(ItemServiceDefinition);
|
|
111
|
+
const availabilityStatus = itemService.availabilityStatus?.get?.() ?? AvailabilityStatus.AVAILABLE;
|
|
112
|
+
const availabilityStatusWithAction = availabilityStatus === AvailabilityStatus.NEXT_AVAILABILITY_PICKUP ||
|
|
113
|
+
availabilityStatus === AvailabilityStatus.NEXT_AVAILABILITY_DELIVERY;
|
|
114
|
+
const availabilityStatusObject = availabilityStatusMap[availabilityStatus];
|
|
115
|
+
const availabilityStatusButtonText = availabilityStatusWithAction
|
|
116
|
+
? availabilityStatusObject
|
|
117
|
+
?.buttonText
|
|
118
|
+
: undefined;
|
|
119
|
+
return children({
|
|
120
|
+
availabilityStatus,
|
|
121
|
+
availabilityAction: availabilityStatusWithAction
|
|
122
|
+
? availabilityDispatchAction
|
|
123
|
+
: undefined,
|
|
124
|
+
availabilityStatusText: availabilityStatusObject?.text,
|
|
125
|
+
availabilityStatusButtonText,
|
|
109
126
|
});
|
|
110
127
|
};
|
|
@@ -1,3 +1,19 @@
|
|
|
1
1
|
import * as currentCart from '@wix/auto_sdk_ecom_current-cart';
|
|
2
2
|
export type LineItem = currentCart.LineItem;
|
|
3
3
|
export type DescriptionLine = currentCart.DescriptionLine;
|
|
4
|
+
export declare enum AvailabilityStatus {
|
|
5
|
+
AVAILABLE = 0,
|
|
6
|
+
NOT_AVAILABLE = 1,
|
|
7
|
+
OUT_OF_STOCK = 2,
|
|
8
|
+
NEXT_AVAILABILITY_PICKUP = 3,
|
|
9
|
+
NEXT_AVAILABILITY_DELIVERY = 4
|
|
10
|
+
}
|
|
11
|
+
export type NextAvailability = AvailabilityStatus.NEXT_AVAILABILITY_PICKUP | AvailabilityStatus.NEXT_AVAILABILITY_DELIVERY;
|
|
12
|
+
export type AvailabilityStatusWithActionObject = {
|
|
13
|
+
text?: string;
|
|
14
|
+
buttonText?: string;
|
|
15
|
+
};
|
|
16
|
+
export type AvailabilityStatusObject = {
|
|
17
|
+
text?: string;
|
|
18
|
+
};
|
|
19
|
+
export type AvailabilityStatusMap = Partial<Record<Exclude<AvailabilityStatus, NextAvailability>, AvailabilityStatusObject>> & Record<NextAvailability, AvailabilityStatusWithActionObject>;
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var AvailabilityStatus;
|
|
2
|
+
(function (AvailabilityStatus) {
|
|
3
|
+
AvailabilityStatus[AvailabilityStatus["AVAILABLE"] = 0] = "AVAILABLE";
|
|
4
|
+
AvailabilityStatus[AvailabilityStatus["NOT_AVAILABLE"] = 1] = "NOT_AVAILABLE";
|
|
5
|
+
AvailabilityStatus[AvailabilityStatus["OUT_OF_STOCK"] = 2] = "OUT_OF_STOCK";
|
|
6
|
+
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_PICKUP"] = 3] = "NEXT_AVAILABILITY_PICKUP";
|
|
7
|
+
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_DELIVERY"] = 4] = "NEXT_AVAILABILITY_DELIVERY";
|
|
8
|
+
})(AvailabilityStatus || (AvailabilityStatus = {}));
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { ItemService, ItemServiceDefinition, loadItemServiceConfig, ItemServiceConfig, } from './item-details-service.js';
|
|
2
2
|
export { OLOSettingsService, OLOSettingsServiceDefinition, loadOLOSettingsServiceConfig, type OLOSettingsServiceConfig, type OLOSettingsServiceAPI, } from './olo-settings-service.js';
|
|
3
|
+
export { AvailabilityStatus, AvailabilityStatusMap } from './common-types.js';
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { ItemService, ItemServiceDefinition, loadItemServiceConfig, } from './item-details-service.js';
|
|
2
2
|
export { OLOSettingsService, OLOSettingsServiceDefinition, loadOLOSettingsServiceConfig, } from './olo-settings-service.js';
|
|
3
|
+
export { AvailabilityStatus } from './common-types.js';
|
|
@@ -2,6 +2,7 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
|
2
2
|
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { itemVariants } from '@wix/restaurants';
|
|
4
4
|
import type { EnhancedItem } from '@wix/headless-restaurants-menus/services';
|
|
5
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
6
|
type Variant = itemVariants.Variant;
|
|
6
7
|
/**
|
|
7
8
|
* API interface for the Item Detailsservice, providing reactive item data management.
|
|
@@ -17,6 +18,7 @@ export interface ItemServiceAPI {
|
|
|
17
18
|
lineItem: Signal<LineItem>;
|
|
18
19
|
selectedVariant: Signal<Variant | undefined>;
|
|
19
20
|
selectedModifiers: Signal<Record<string, Array<string>>>;
|
|
21
|
+
availabilityStatus: Signal<AvailabilityStatus>;
|
|
20
22
|
/** Reactive signal indicating if a item is currently being loaded */
|
|
21
23
|
isLoading: Signal<boolean>;
|
|
22
24
|
/** Reactive signal containing any error message, or null if no error */
|
|
@@ -29,6 +31,8 @@ export interface ItemServiceAPI {
|
|
|
29
31
|
updateSelectedVariant: (variant: Variant) => void;
|
|
30
32
|
/** Function to toggle a modifier instance in a specific group */
|
|
31
33
|
toggleModifier: (modifierGroupId: string, modifierId: string, singleSelect?: boolean) => void;
|
|
34
|
+
/** Function to get the selected modifiers for a specific group */
|
|
35
|
+
getSelectedModifiers: (modifierGroupId: string) => Array<string>;
|
|
32
36
|
}
|
|
33
37
|
/**
|
|
34
38
|
* Service definition for the Item service.
|
|
@@ -52,6 +56,7 @@ export interface ItemServiceConfig {
|
|
|
52
56
|
item?: EnhancedItem;
|
|
53
57
|
itemId?: string;
|
|
54
58
|
operationId?: string;
|
|
59
|
+
menuId?: string;
|
|
55
60
|
}
|
|
56
61
|
export declare const ItemService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
57
62
|
__api: ItemServiceAPI;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
2
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { OLOSettingsServiceDefinition } from './olo-settings-service.js';
|
|
4
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
|
+
import { getModifiersInitState } from './utils.js';
|
|
3
6
|
/**
|
|
4
7
|
* Service definition for the Item service.
|
|
5
8
|
* This defines the contract that the ItemService must implement.
|
|
@@ -43,6 +46,11 @@ export const ItemServiceDefinition = defineService('item');
|
|
|
43
46
|
const APP_ID = '9a5d83fd-8570-482e-81ab-cfa88942ee60';
|
|
44
47
|
export const ItemService = implementService.withConfig()(ItemServiceDefinition, ({ getService, config }) => {
|
|
45
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
49
|
+
const oloSettingsService = getService(OLOSettingsServiceDefinition);
|
|
50
|
+
const getAvailabilityStatusFn = oloSettingsService.getAvailabilityStatus?.get?.();
|
|
51
|
+
const initialAvailabilityStatus = getAvailabilityStatusFn?.(config.menuId ?? '') ??
|
|
52
|
+
AvailabilityStatus.AVAILABLE;
|
|
53
|
+
const availabilityStatus = signalsService.signal(initialAvailabilityStatus);
|
|
46
54
|
const item = signalsService.signal(config.item);
|
|
47
55
|
const isLoading = signalsService.signal(!!config.item);
|
|
48
56
|
const error = signalsService.signal(config.item ? null : 'Item not found');
|
|
@@ -53,12 +61,7 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
53
61
|
const initialVariant = priceVariants.length > 0 ? priceVariants[0] : undefined;
|
|
54
62
|
const selectedVariant = signalsService.signal(initialVariant);
|
|
55
63
|
const modifierGroups = config.item?.modifierGroups || [];
|
|
56
|
-
const initialSelectedModifiers =
|
|
57
|
-
modifierGroups.forEach((group) => {
|
|
58
|
-
if (group._id) {
|
|
59
|
-
initialSelectedModifiers[group._id] = [];
|
|
60
|
-
}
|
|
61
|
-
});
|
|
64
|
+
const initialSelectedModifiers = getModifiersInitState(modifierGroups);
|
|
62
65
|
const selectedModifiers = signalsService.signal(initialSelectedModifiers);
|
|
63
66
|
if (config.item) {
|
|
64
67
|
console.log('config.item', config.item);
|
|
@@ -103,37 +106,40 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
103
106
|
const updateSelectedVariant = (variant) => {
|
|
104
107
|
selectedVariant.set(variant);
|
|
105
108
|
};
|
|
106
|
-
const
|
|
109
|
+
const getModifierIds = (modifierGroupId, modifierId, singleSelect = false) => {
|
|
107
110
|
const currentSelectedModifiers = selectedModifiers.get();
|
|
108
111
|
const groupModifierIds = currentSelectedModifiers[modifierGroupId] || [];
|
|
109
112
|
// Check if this modifier is already selected
|
|
110
113
|
const isModifierSelected = groupModifierIds.includes(modifierId);
|
|
111
114
|
if (singleSelect) {
|
|
112
115
|
// Single select behavior: select the modifier, replacing any existing selection
|
|
113
|
-
|
|
114
|
-
...currentSelectedModifiers,
|
|
115
|
-
[modifierGroupId]: [modifierId],
|
|
116
|
-
});
|
|
116
|
+
return [modifierId];
|
|
117
117
|
}
|
|
118
118
|
else {
|
|
119
119
|
// Multi-select behavior: toggle the modifier
|
|
120
120
|
if (isModifierSelected) {
|
|
121
121
|
// Remove the modifier if it exists
|
|
122
122
|
const updatedModifierIds = groupModifierIds.filter((id) => id !== modifierId);
|
|
123
|
-
|
|
124
|
-
...currentSelectedModifiers,
|
|
125
|
-
[modifierGroupId]: updatedModifierIds,
|
|
126
|
-
});
|
|
123
|
+
return updatedModifierIds;
|
|
127
124
|
}
|
|
128
125
|
else {
|
|
129
126
|
// Add the modifier to the existing selection
|
|
130
|
-
|
|
131
|
-
...currentSelectedModifiers,
|
|
132
|
-
[modifierGroupId]: [...groupModifierIds, modifierId],
|
|
133
|
-
});
|
|
127
|
+
return [...groupModifierIds, modifierId];
|
|
134
128
|
}
|
|
135
129
|
}
|
|
136
130
|
};
|
|
131
|
+
const toggleModifier = (modifierGroupId, modifierId, singleSelect = false) => {
|
|
132
|
+
const currentSelectedModifiers = selectedModifiers.get();
|
|
133
|
+
const modifierIds = getModifierIds(modifierGroupId, modifierId, singleSelect);
|
|
134
|
+
selectedModifiers.set({
|
|
135
|
+
...currentSelectedModifiers,
|
|
136
|
+
[modifierGroupId]: modifierIds,
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
const getSelectedModifiers = (modifierGroupId) => {
|
|
140
|
+
const currentSelectedModifiers = selectedModifiers.get();
|
|
141
|
+
return currentSelectedModifiers[modifierGroupId] || [];
|
|
142
|
+
};
|
|
137
143
|
return {
|
|
138
144
|
item,
|
|
139
145
|
quantity,
|
|
@@ -147,6 +153,8 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
147
153
|
lineItem,
|
|
148
154
|
selectedVariant,
|
|
149
155
|
selectedModifiers,
|
|
156
|
+
availabilityStatus,
|
|
157
|
+
getSelectedModifiers,
|
|
150
158
|
};
|
|
151
159
|
});
|
|
152
160
|
/**
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import * as operationGroupsApi from '@wix/auto_sdk_restaurants_operation-groups';
|
|
2
2
|
import * as operationsApi from '@wix/auto_sdk_restaurants_operations';
|
|
3
3
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
4
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
4
5
|
export interface OLOSettingsServiceAPI {
|
|
5
6
|
operationGroup: Signal<operationGroupsApi.OperationGroup | undefined>;
|
|
6
7
|
operation: Signal<operationsApi.Operation | undefined>;
|
|
7
8
|
selectedItem?: Signal<unknown>;
|
|
8
9
|
isLoading: Signal<boolean>;
|
|
9
10
|
error: Signal<string | null>;
|
|
11
|
+
getAvailabilityStatus: Signal<(menuId: string) => AvailabilityStatus>;
|
|
12
|
+
availabilityDispatchAction?: Signal<(() => void) | undefined>;
|
|
10
13
|
}
|
|
11
14
|
export interface OLOSettingsServiceConfig {
|
|
12
15
|
operationGroup?: operationGroupsApi.OperationGroup;
|
|
13
16
|
operation?: operationsApi.Operation;
|
|
17
|
+
availabilityStatusMenuMap: Record<string, AvailabilityStatus>;
|
|
18
|
+
availabilityDispatchAction?: () => void;
|
|
14
19
|
}
|
|
15
20
|
export declare const OLOSettingsServiceDefinition: string & {
|
|
16
21
|
__api: OLOSettingsServiceAPI;
|
|
@@ -2,20 +2,30 @@ import { defineService, implementService } from '@wix/services-definitions';
|
|
|
2
2
|
import * as operationGroupsApi from '@wix/auto_sdk_restaurants_operation-groups';
|
|
3
3
|
import * as operationsApi from '@wix/auto_sdk_restaurants_operations';
|
|
4
4
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
5
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
6
|
export const OLOSettingsServiceDefinition = defineService('oloSettings');
|
|
6
7
|
export const OLOSettingsService = implementService.withConfig()(OLOSettingsServiceDefinition, ({ getService, config }) => {
|
|
7
8
|
const signalsService = getService(SignalsServiceDefinition);
|
|
9
|
+
const availabilityStatusMenuMap = signalsService.signal(config.availabilityStatusMenuMap);
|
|
10
|
+
const availabilityDispatchAction = signalsService.signal(config.availabilityDispatchAction);
|
|
8
11
|
const operationGroup = signalsService.signal(config.operationGroup);
|
|
9
12
|
const operation = signalsService.signal(config.operation);
|
|
10
13
|
const selectedItem = signalsService.signal(null);
|
|
11
14
|
const isLoading = signalsService.signal(false);
|
|
12
15
|
const error = signalsService.signal(null);
|
|
16
|
+
const getAvailabilityStatusFn = (menuId) => {
|
|
17
|
+
return (availabilityStatusMenuMap.get()?.[menuId] ??
|
|
18
|
+
AvailabilityStatus.AVAILABLE);
|
|
19
|
+
};
|
|
20
|
+
const getAvailabilityStatus = signalsService.signal(getAvailabilityStatusFn);
|
|
13
21
|
return {
|
|
14
22
|
operationGroup,
|
|
15
23
|
operation,
|
|
16
24
|
isLoading,
|
|
17
25
|
error,
|
|
18
26
|
selectedItem,
|
|
27
|
+
getAvailabilityStatus,
|
|
28
|
+
availabilityDispatchAction,
|
|
19
29
|
};
|
|
20
30
|
});
|
|
21
31
|
export async function loadOLOSettingsServiceConfig() {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EnhancedModifier, EnhancedModifierGroup } from '@wix/headless-restaurants-menus/services';
|
|
2
|
+
export declare const getModifiersInitState: (modifierGroups: EnhancedModifierGroup[]) => Record<string, string[]>;
|
|
3
|
+
export declare const isSingleSelectRule: (rule: NonNullable<EnhancedModifierGroup["rule"]>) => boolean | null | undefined;
|
|
4
|
+
export declare const getFirstPreSelectedModifier: (modifiers: EnhancedModifier[]) => string | null | undefined;
|
|
5
|
+
export declare const getPreSelectedModifiers: (modifiers: EnhancedModifier[]) => string[];
|
|
6
|
+
export declare const convertModifierToFormModifier: (modifier: EnhancedModifier, index: number) => {
|
|
7
|
+
_id: string;
|
|
8
|
+
revision?: string | null;
|
|
9
|
+
_createdDate?: Date | null;
|
|
10
|
+
_updatedDate?: Date | null;
|
|
11
|
+
name?: string | null;
|
|
12
|
+
extendedFields?: import("@wix/auto_sdk_restaurants_item-modifiers").ExtendedFields;
|
|
13
|
+
inStock?: boolean | null;
|
|
14
|
+
businessLocationIds?: string[];
|
|
15
|
+
additionalChargeInfo?: {
|
|
16
|
+
additionalCharge?: string;
|
|
17
|
+
formattedAdditionalCharge?: string;
|
|
18
|
+
};
|
|
19
|
+
preSelected?: boolean;
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const getModifiersInitState = (modifierGroups) => {
|
|
2
|
+
const initialSelectedModifiers = {};
|
|
3
|
+
modifierGroups.forEach((group) => {
|
|
4
|
+
if (group._id) {
|
|
5
|
+
const isMultiSelectItem = !isSingleSelectRule(group.rule ?? {});
|
|
6
|
+
const formModifiers = group.modifiers.map(convertModifierToFormModifier);
|
|
7
|
+
if (isMultiSelectItem) {
|
|
8
|
+
const preSelectedModifiers = getPreSelectedModifiers(formModifiers);
|
|
9
|
+
initialSelectedModifiers[group._id] = preSelectedModifiers;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const preSelectedModifier = getFirstPreSelectedModifier(formModifiers);
|
|
13
|
+
initialSelectedModifiers[group._id] = preSelectedModifier
|
|
14
|
+
? [preSelectedModifier]
|
|
15
|
+
: [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return initialSelectedModifiers;
|
|
20
|
+
};
|
|
21
|
+
export const isSingleSelectRule = (rule) => rule.required && rule.minSelections === 1 && rule.maxSelections === 1;
|
|
22
|
+
export const getFirstPreSelectedModifier = (modifiers) => modifiers.find(({ preSelected, inStock }) => preSelected && inStock)?._id;
|
|
23
|
+
export const getPreSelectedModifiers = (modifiers) => modifiers.reduce((acc, modifier) => {
|
|
24
|
+
if (modifier.preSelected && modifier.inStock && modifier._id) {
|
|
25
|
+
return [...acc, modifier._id];
|
|
26
|
+
}
|
|
27
|
+
return acc;
|
|
28
|
+
}, []);
|
|
29
|
+
export const convertModifierToFormModifier = (modifier, index) => {
|
|
30
|
+
return {
|
|
31
|
+
...modifier,
|
|
32
|
+
_id: `${modifier._id}~${index}`,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -4,6 +4,7 @@ import { type LineItem } from '@wix/ecom/services';
|
|
|
4
4
|
import { type AsChildChildren } from '@wix/headless-utils/react';
|
|
5
5
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
6
6
|
import { EnhancedModifier, EnhancedModifierGroup, EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
7
|
+
import { AvailabilityStatus, AvailabilityStatusMap } from '../services/common-types.js';
|
|
7
8
|
/**
|
|
8
9
|
* Root component for menu item display and interaction.
|
|
9
10
|
* Provides context for all menu item-related components like name, price, description, image, etc.
|
|
@@ -266,3 +267,16 @@ export interface ItemDetailsQuantityProps {
|
|
|
266
267
|
export declare const AddToCartButton: React.FC<AddToCartButtonProps>;
|
|
267
268
|
export declare const Quantity: React.FC<ItemDetailsQuantityProps>;
|
|
268
269
|
export declare const SpecialRequest: React.ForwardRefExoticComponent<SpecialRequestProps & React.RefAttributes<never>>;
|
|
270
|
+
export interface ItemDetailsAvailabilityProps {
|
|
271
|
+
asChild?: boolean;
|
|
272
|
+
textClassName?: string;
|
|
273
|
+
buttonClassName?: string;
|
|
274
|
+
availabilityStatusMap: AvailabilityStatusMap;
|
|
275
|
+
children: (props: {
|
|
276
|
+
availabilityStatus: AvailabilityStatus;
|
|
277
|
+
availabilityStatusText?: string;
|
|
278
|
+
availabilityStatusButtonText?: string;
|
|
279
|
+
availabilityAction?: () => void;
|
|
280
|
+
}) => React.ReactNode;
|
|
281
|
+
}
|
|
282
|
+
export declare const AvailabilityComponent: React.ForwardRefExoticComponent<ItemDetailsAvailabilityProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -7,6 +7,7 @@ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
|
7
7
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
8
8
|
import { Item, Modifier, ModifierGroup, useModifierContext, } from '@wix/headless-restaurants-menus/react';
|
|
9
9
|
import * as CoreItemDetails from './core/ItemDetails.js';
|
|
10
|
+
import { AvailabilityStatus, } from '../services/common-types.js';
|
|
10
11
|
var TestIds;
|
|
11
12
|
(function (TestIds) {
|
|
12
13
|
TestIds["itemName"] = "item-name";
|
|
@@ -18,6 +19,7 @@ var TestIds;
|
|
|
18
19
|
TestIds["itemLabels"] = "item-labels";
|
|
19
20
|
TestIds["itemVariants"] = "item-variants";
|
|
20
21
|
TestIds["itemModifier"] = "item-modifier";
|
|
22
|
+
TestIds["itemAvailability"] = "item-availability";
|
|
21
23
|
})(TestIds || (TestIds = {}));
|
|
22
24
|
const CheckIcon = () => (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z", fill: "currentColor" }) }));
|
|
23
25
|
export const Root = ({ children, itemDetailsServiceConfig }) => {
|
|
@@ -120,3 +122,17 @@ export const SpecialRequest = React.forwardRef(({ className, labelClassName, pla
|
|
|
120
122
|
return (_jsx(CoreItemDetails.SpecialRequest, { children: ({ value, onChange, }) => (_jsxs(AsChildSlot, { ref: ref, asChild: asChild, className: className, onChange: onChange, "data-testid": TestIds.itemSpecialRequest, customElement: children, customElementProps: { label, value }, content: value, ...props, children: [label && _jsx("label", { className: labelClassName, children: label }), _jsx("textarea", { value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, maxLength: maxLength, rows: rows, className: className, children: value })] })) }));
|
|
121
123
|
});
|
|
122
124
|
SpecialRequest.displayName = 'SpecialRequest';
|
|
125
|
+
export const AvailabilityComponent = React.forwardRef(({ asChild, children, textClassName, buttonClassName, availabilityStatusMap, ...rest }, ref) => {
|
|
126
|
+
return (_jsx(CoreItemDetails.AvailabilityComponent, { availabilityStatusMap: availabilityStatusMap, children: ({ availabilityStatus, availabilityAction, availabilityStatusText, availabilityStatusButtonText, }) => {
|
|
127
|
+
if (availabilityStatus === AvailabilityStatus.AVAILABLE) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return (_jsxs(AsChildSlot, { asChild: asChild, "data-testid": TestIds.itemAvailability, customElement: children, customElementProps: {
|
|
131
|
+
availabilityStatus,
|
|
132
|
+
availabilityStatusText,
|
|
133
|
+
availabilityStatusButtonText,
|
|
134
|
+
availabilityAction,
|
|
135
|
+
}, ref: ref, ...rest, children: [_jsx("p", { className: textClassName, children: availabilityStatusText }), availabilityStatusButtonText && availabilityAction && (_jsx("button", { className: buttonClassName, onClick: availabilityAction, children: availabilityStatusButtonText }))] }));
|
|
136
|
+
} }));
|
|
137
|
+
});
|
|
138
|
+
AvailabilityComponent.displayName = 'AvailabilityComponent';
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { ItemServiceConfig } from '../../services/item-details-service.js';
|
|
4
4
|
import { EnhancedModifier, EnhancedModifierGroup, EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
5
|
+
import { AvailabilityStatus, AvailabilityStatusMap } from '../../services/common-types.js';
|
|
5
6
|
interface ItemDetailsRootProps {
|
|
6
7
|
children: (props: {
|
|
7
8
|
item: unknown;
|
|
@@ -54,4 +55,14 @@ interface ItemDetailsModifiersProps {
|
|
|
54
55
|
singleSelect?: boolean;
|
|
55
56
|
}
|
|
56
57
|
export declare const ModifiersComponent: React.FC<ItemDetailsModifiersProps>;
|
|
58
|
+
interface ItemDetailsAvailabilityProps {
|
|
59
|
+
availabilityStatusMap: AvailabilityStatusMap;
|
|
60
|
+
children: (props: {
|
|
61
|
+
availabilityStatus: AvailabilityStatus;
|
|
62
|
+
availabilityAction?: () => void;
|
|
63
|
+
availabilityStatusText?: string;
|
|
64
|
+
availabilityStatusButtonText?: string;
|
|
65
|
+
}) => React.ReactNode;
|
|
66
|
+
}
|
|
67
|
+
export declare const AvailabilityComponent: React.FC<ItemDetailsAvailabilityProps>;
|
|
57
68
|
export {};
|
|
@@ -5,6 +5,8 @@ import { createServicesMap } from '@wix/services-manager';
|
|
|
5
5
|
import { ItemService, ItemServiceDefinition, loadItemServiceConfig, } from '../../services/item-details-service.js';
|
|
6
6
|
import { OLOSettingsServiceDefinition } from '../../services/olo-settings-service.js';
|
|
7
7
|
import { useItemContext, useModifierGroupContext, } from '@wix/headless-restaurants-menus/react';
|
|
8
|
+
import { AvailabilityStatus, } from '../../services/common-types.js';
|
|
9
|
+
import { convertModifierToFormModifier } from '../../services/utils.js';
|
|
8
10
|
export const Root = ({ children, itemDetailsServiceConfig, }) => {
|
|
9
11
|
const service = useService(OLOSettingsServiceDefinition);
|
|
10
12
|
const selectedItem = service.selectedItem?.get();
|
|
@@ -87,12 +89,9 @@ export const VariantsComponent = ({ children, }) => {
|
|
|
87
89
|
export const ModifiersComponent = ({ children, singleSelect, }) => {
|
|
88
90
|
const service = useService(ItemServiceDefinition);
|
|
89
91
|
const { modifierGroup } = useModifierGroupContext();
|
|
90
|
-
const selectedModifiers = service.selectedModifiers?.get?.() ?? {};
|
|
91
92
|
// Get selected modifier IDs for this group
|
|
92
93
|
const groupId = modifierGroup._id;
|
|
93
|
-
const groupSelectedModifierIds = groupId
|
|
94
|
-
? selectedModifiers[groupId] || []
|
|
95
|
-
: [];
|
|
94
|
+
const groupSelectedModifierIds = service.getSelectedModifiers?.(groupId ?? '');
|
|
96
95
|
const onToggle = (modifierId) => {
|
|
97
96
|
if (groupId) {
|
|
98
97
|
service.toggleModifier?.(groupId, modifierId, singleSelect);
|
|
@@ -102,9 +101,27 @@ export const ModifiersComponent = ({ children, singleSelect, }) => {
|
|
|
102
101
|
selectedModifierIds: groupSelectedModifierIds,
|
|
103
102
|
onToggle,
|
|
104
103
|
modifierGroup,
|
|
105
|
-
modifiers: modifierGroup.modifiers.map(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
modifiers: modifierGroup.modifiers.map(convertModifierToFormModifier),
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
export const AvailabilityComponent = ({ children, availabilityStatusMap, }) => {
|
|
108
|
+
const oloSettingsService = useService(OLOSettingsServiceDefinition);
|
|
109
|
+
const availabilityDispatchAction = oloSettingsService.availabilityDispatchAction?.get?.();
|
|
110
|
+
const itemService = useService(ItemServiceDefinition);
|
|
111
|
+
const availabilityStatus = itemService.availabilityStatus?.get?.() ?? AvailabilityStatus.AVAILABLE;
|
|
112
|
+
const availabilityStatusWithAction = availabilityStatus === AvailabilityStatus.NEXT_AVAILABILITY_PICKUP ||
|
|
113
|
+
availabilityStatus === AvailabilityStatus.NEXT_AVAILABILITY_DELIVERY;
|
|
114
|
+
const availabilityStatusObject = availabilityStatusMap[availabilityStatus];
|
|
115
|
+
const availabilityStatusButtonText = availabilityStatusWithAction
|
|
116
|
+
? availabilityStatusObject
|
|
117
|
+
?.buttonText
|
|
118
|
+
: undefined;
|
|
119
|
+
return children({
|
|
120
|
+
availabilityStatus,
|
|
121
|
+
availabilityAction: availabilityStatusWithAction
|
|
122
|
+
? availabilityDispatchAction
|
|
123
|
+
: undefined,
|
|
124
|
+
availabilityStatusText: availabilityStatusObject?.text,
|
|
125
|
+
availabilityStatusButtonText,
|
|
109
126
|
});
|
|
110
127
|
};
|
|
@@ -1,3 +1,19 @@
|
|
|
1
1
|
import * as currentCart from '@wix/auto_sdk_ecom_current-cart';
|
|
2
2
|
export type LineItem = currentCart.LineItem;
|
|
3
3
|
export type DescriptionLine = currentCart.DescriptionLine;
|
|
4
|
+
export declare enum AvailabilityStatus {
|
|
5
|
+
AVAILABLE = 0,
|
|
6
|
+
NOT_AVAILABLE = 1,
|
|
7
|
+
OUT_OF_STOCK = 2,
|
|
8
|
+
NEXT_AVAILABILITY_PICKUP = 3,
|
|
9
|
+
NEXT_AVAILABILITY_DELIVERY = 4
|
|
10
|
+
}
|
|
11
|
+
export type NextAvailability = AvailabilityStatus.NEXT_AVAILABILITY_PICKUP | AvailabilityStatus.NEXT_AVAILABILITY_DELIVERY;
|
|
12
|
+
export type AvailabilityStatusWithActionObject = {
|
|
13
|
+
text?: string;
|
|
14
|
+
buttonText?: string;
|
|
15
|
+
};
|
|
16
|
+
export type AvailabilityStatusObject = {
|
|
17
|
+
text?: string;
|
|
18
|
+
};
|
|
19
|
+
export type AvailabilityStatusMap = Partial<Record<Exclude<AvailabilityStatus, NextAvailability>, AvailabilityStatusObject>> & Record<NextAvailability, AvailabilityStatusWithActionObject>;
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var AvailabilityStatus;
|
|
2
|
+
(function (AvailabilityStatus) {
|
|
3
|
+
AvailabilityStatus[AvailabilityStatus["AVAILABLE"] = 0] = "AVAILABLE";
|
|
4
|
+
AvailabilityStatus[AvailabilityStatus["NOT_AVAILABLE"] = 1] = "NOT_AVAILABLE";
|
|
5
|
+
AvailabilityStatus[AvailabilityStatus["OUT_OF_STOCK"] = 2] = "OUT_OF_STOCK";
|
|
6
|
+
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_PICKUP"] = 3] = "NEXT_AVAILABILITY_PICKUP";
|
|
7
|
+
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_DELIVERY"] = 4] = "NEXT_AVAILABILITY_DELIVERY";
|
|
8
|
+
})(AvailabilityStatus || (AvailabilityStatus = {}));
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { ItemService, ItemServiceDefinition, loadItemServiceConfig, ItemServiceConfig, } from './item-details-service.js';
|
|
2
2
|
export { OLOSettingsService, OLOSettingsServiceDefinition, loadOLOSettingsServiceConfig, type OLOSettingsServiceConfig, type OLOSettingsServiceAPI, } from './olo-settings-service.js';
|
|
3
|
+
export { AvailabilityStatus, AvailabilityStatusMap } from './common-types.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { ItemService, ItemServiceDefinition, loadItemServiceConfig, } from './item-details-service.js';
|
|
2
2
|
export { OLOSettingsService, OLOSettingsServiceDefinition, loadOLOSettingsServiceConfig, } from './olo-settings-service.js';
|
|
3
|
+
export { AvailabilityStatus } from './common-types.js';
|
|
@@ -2,6 +2,7 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
|
2
2
|
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { itemVariants } from '@wix/restaurants';
|
|
4
4
|
import type { EnhancedItem } from '@wix/headless-restaurants-menus/services';
|
|
5
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
6
|
type Variant = itemVariants.Variant;
|
|
6
7
|
/**
|
|
7
8
|
* API interface for the Item Detailsservice, providing reactive item data management.
|
|
@@ -17,6 +18,7 @@ export interface ItemServiceAPI {
|
|
|
17
18
|
lineItem: Signal<LineItem>;
|
|
18
19
|
selectedVariant: Signal<Variant | undefined>;
|
|
19
20
|
selectedModifiers: Signal<Record<string, Array<string>>>;
|
|
21
|
+
availabilityStatus: Signal<AvailabilityStatus>;
|
|
20
22
|
/** Reactive signal indicating if a item is currently being loaded */
|
|
21
23
|
isLoading: Signal<boolean>;
|
|
22
24
|
/** Reactive signal containing any error message, or null if no error */
|
|
@@ -29,6 +31,8 @@ export interface ItemServiceAPI {
|
|
|
29
31
|
updateSelectedVariant: (variant: Variant) => void;
|
|
30
32
|
/** Function to toggle a modifier instance in a specific group */
|
|
31
33
|
toggleModifier: (modifierGroupId: string, modifierId: string, singleSelect?: boolean) => void;
|
|
34
|
+
/** Function to get the selected modifiers for a specific group */
|
|
35
|
+
getSelectedModifiers: (modifierGroupId: string) => Array<string>;
|
|
32
36
|
}
|
|
33
37
|
/**
|
|
34
38
|
* Service definition for the Item service.
|
|
@@ -52,6 +56,7 @@ export interface ItemServiceConfig {
|
|
|
52
56
|
item?: EnhancedItem;
|
|
53
57
|
itemId?: string;
|
|
54
58
|
operationId?: string;
|
|
59
|
+
menuId?: string;
|
|
55
60
|
}
|
|
56
61
|
export declare const ItemService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
57
62
|
__api: ItemServiceAPI;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
2
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { OLOSettingsServiceDefinition } from './olo-settings-service.js';
|
|
4
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
|
+
import { getModifiersInitState } from './utils.js';
|
|
3
6
|
/**
|
|
4
7
|
* Service definition for the Item service.
|
|
5
8
|
* This defines the contract that the ItemService must implement.
|
|
@@ -43,6 +46,11 @@ export const ItemServiceDefinition = defineService('item');
|
|
|
43
46
|
const APP_ID = '9a5d83fd-8570-482e-81ab-cfa88942ee60';
|
|
44
47
|
export const ItemService = implementService.withConfig()(ItemServiceDefinition, ({ getService, config }) => {
|
|
45
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
49
|
+
const oloSettingsService = getService(OLOSettingsServiceDefinition);
|
|
50
|
+
const getAvailabilityStatusFn = oloSettingsService.getAvailabilityStatus?.get?.();
|
|
51
|
+
const initialAvailabilityStatus = getAvailabilityStatusFn?.(config.menuId ?? '') ??
|
|
52
|
+
AvailabilityStatus.AVAILABLE;
|
|
53
|
+
const availabilityStatus = signalsService.signal(initialAvailabilityStatus);
|
|
46
54
|
const item = signalsService.signal(config.item);
|
|
47
55
|
const isLoading = signalsService.signal(!!config.item);
|
|
48
56
|
const error = signalsService.signal(config.item ? null : 'Item not found');
|
|
@@ -53,12 +61,7 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
53
61
|
const initialVariant = priceVariants.length > 0 ? priceVariants[0] : undefined;
|
|
54
62
|
const selectedVariant = signalsService.signal(initialVariant);
|
|
55
63
|
const modifierGroups = config.item?.modifierGroups || [];
|
|
56
|
-
const initialSelectedModifiers =
|
|
57
|
-
modifierGroups.forEach((group) => {
|
|
58
|
-
if (group._id) {
|
|
59
|
-
initialSelectedModifiers[group._id] = [];
|
|
60
|
-
}
|
|
61
|
-
});
|
|
64
|
+
const initialSelectedModifiers = getModifiersInitState(modifierGroups);
|
|
62
65
|
const selectedModifiers = signalsService.signal(initialSelectedModifiers);
|
|
63
66
|
if (config.item) {
|
|
64
67
|
console.log('config.item', config.item);
|
|
@@ -103,37 +106,40 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
103
106
|
const updateSelectedVariant = (variant) => {
|
|
104
107
|
selectedVariant.set(variant);
|
|
105
108
|
};
|
|
106
|
-
const
|
|
109
|
+
const getModifierIds = (modifierGroupId, modifierId, singleSelect = false) => {
|
|
107
110
|
const currentSelectedModifiers = selectedModifiers.get();
|
|
108
111
|
const groupModifierIds = currentSelectedModifiers[modifierGroupId] || [];
|
|
109
112
|
// Check if this modifier is already selected
|
|
110
113
|
const isModifierSelected = groupModifierIds.includes(modifierId);
|
|
111
114
|
if (singleSelect) {
|
|
112
115
|
// Single select behavior: select the modifier, replacing any existing selection
|
|
113
|
-
|
|
114
|
-
...currentSelectedModifiers,
|
|
115
|
-
[modifierGroupId]: [modifierId],
|
|
116
|
-
});
|
|
116
|
+
return [modifierId];
|
|
117
117
|
}
|
|
118
118
|
else {
|
|
119
119
|
// Multi-select behavior: toggle the modifier
|
|
120
120
|
if (isModifierSelected) {
|
|
121
121
|
// Remove the modifier if it exists
|
|
122
122
|
const updatedModifierIds = groupModifierIds.filter((id) => id !== modifierId);
|
|
123
|
-
|
|
124
|
-
...currentSelectedModifiers,
|
|
125
|
-
[modifierGroupId]: updatedModifierIds,
|
|
126
|
-
});
|
|
123
|
+
return updatedModifierIds;
|
|
127
124
|
}
|
|
128
125
|
else {
|
|
129
126
|
// Add the modifier to the existing selection
|
|
130
|
-
|
|
131
|
-
...currentSelectedModifiers,
|
|
132
|
-
[modifierGroupId]: [...groupModifierIds, modifierId],
|
|
133
|
-
});
|
|
127
|
+
return [...groupModifierIds, modifierId];
|
|
134
128
|
}
|
|
135
129
|
}
|
|
136
130
|
};
|
|
131
|
+
const toggleModifier = (modifierGroupId, modifierId, singleSelect = false) => {
|
|
132
|
+
const currentSelectedModifiers = selectedModifiers.get();
|
|
133
|
+
const modifierIds = getModifierIds(modifierGroupId, modifierId, singleSelect);
|
|
134
|
+
selectedModifiers.set({
|
|
135
|
+
...currentSelectedModifiers,
|
|
136
|
+
[modifierGroupId]: modifierIds,
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
const getSelectedModifiers = (modifierGroupId) => {
|
|
140
|
+
const currentSelectedModifiers = selectedModifiers.get();
|
|
141
|
+
return currentSelectedModifiers[modifierGroupId] || [];
|
|
142
|
+
};
|
|
137
143
|
return {
|
|
138
144
|
item,
|
|
139
145
|
quantity,
|
|
@@ -147,6 +153,8 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
147
153
|
lineItem,
|
|
148
154
|
selectedVariant,
|
|
149
155
|
selectedModifiers,
|
|
156
|
+
availabilityStatus,
|
|
157
|
+
getSelectedModifiers,
|
|
150
158
|
};
|
|
151
159
|
});
|
|
152
160
|
/**
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import * as operationGroupsApi from '@wix/auto_sdk_restaurants_operation-groups';
|
|
2
2
|
import * as operationsApi from '@wix/auto_sdk_restaurants_operations';
|
|
3
3
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
4
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
4
5
|
export interface OLOSettingsServiceAPI {
|
|
5
6
|
operationGroup: Signal<operationGroupsApi.OperationGroup | undefined>;
|
|
6
7
|
operation: Signal<operationsApi.Operation | undefined>;
|
|
7
8
|
selectedItem?: Signal<unknown>;
|
|
8
9
|
isLoading: Signal<boolean>;
|
|
9
10
|
error: Signal<string | null>;
|
|
11
|
+
getAvailabilityStatus: Signal<(menuId: string) => AvailabilityStatus>;
|
|
12
|
+
availabilityDispatchAction?: Signal<(() => void) | undefined>;
|
|
10
13
|
}
|
|
11
14
|
export interface OLOSettingsServiceConfig {
|
|
12
15
|
operationGroup?: operationGroupsApi.OperationGroup;
|
|
13
16
|
operation?: operationsApi.Operation;
|
|
17
|
+
availabilityStatusMenuMap: Record<string, AvailabilityStatus>;
|
|
18
|
+
availabilityDispatchAction?: () => void;
|
|
14
19
|
}
|
|
15
20
|
export declare const OLOSettingsServiceDefinition: string & {
|
|
16
21
|
__api: OLOSettingsServiceAPI;
|
|
@@ -2,20 +2,30 @@ import { defineService, implementService } from '@wix/services-definitions';
|
|
|
2
2
|
import * as operationGroupsApi from '@wix/auto_sdk_restaurants_operation-groups';
|
|
3
3
|
import * as operationsApi from '@wix/auto_sdk_restaurants_operations';
|
|
4
4
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
5
|
+
import { AvailabilityStatus } from './common-types.js';
|
|
5
6
|
export const OLOSettingsServiceDefinition = defineService('oloSettings');
|
|
6
7
|
export const OLOSettingsService = implementService.withConfig()(OLOSettingsServiceDefinition, ({ getService, config }) => {
|
|
7
8
|
const signalsService = getService(SignalsServiceDefinition);
|
|
9
|
+
const availabilityStatusMenuMap = signalsService.signal(config.availabilityStatusMenuMap);
|
|
10
|
+
const availabilityDispatchAction = signalsService.signal(config.availabilityDispatchAction);
|
|
8
11
|
const operationGroup = signalsService.signal(config.operationGroup);
|
|
9
12
|
const operation = signalsService.signal(config.operation);
|
|
10
13
|
const selectedItem = signalsService.signal(null);
|
|
11
14
|
const isLoading = signalsService.signal(false);
|
|
12
15
|
const error = signalsService.signal(null);
|
|
16
|
+
const getAvailabilityStatusFn = (menuId) => {
|
|
17
|
+
return (availabilityStatusMenuMap.get()?.[menuId] ??
|
|
18
|
+
AvailabilityStatus.AVAILABLE);
|
|
19
|
+
};
|
|
20
|
+
const getAvailabilityStatus = signalsService.signal(getAvailabilityStatusFn);
|
|
13
21
|
return {
|
|
14
22
|
operationGroup,
|
|
15
23
|
operation,
|
|
16
24
|
isLoading,
|
|
17
25
|
error,
|
|
18
26
|
selectedItem,
|
|
27
|
+
getAvailabilityStatus,
|
|
28
|
+
availabilityDispatchAction,
|
|
19
29
|
};
|
|
20
30
|
});
|
|
21
31
|
export async function loadOLOSettingsServiceConfig() {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EnhancedModifier, EnhancedModifierGroup } from '@wix/headless-restaurants-menus/services';
|
|
2
|
+
export declare const getModifiersInitState: (modifierGroups: EnhancedModifierGroup[]) => Record<string, string[]>;
|
|
3
|
+
export declare const isSingleSelectRule: (rule: NonNullable<EnhancedModifierGroup["rule"]>) => boolean | null | undefined;
|
|
4
|
+
export declare const getFirstPreSelectedModifier: (modifiers: EnhancedModifier[]) => string | null | undefined;
|
|
5
|
+
export declare const getPreSelectedModifiers: (modifiers: EnhancedModifier[]) => string[];
|
|
6
|
+
export declare const convertModifierToFormModifier: (modifier: EnhancedModifier, index: number) => {
|
|
7
|
+
_id: string;
|
|
8
|
+
revision?: string | null;
|
|
9
|
+
_createdDate?: Date | null;
|
|
10
|
+
_updatedDate?: Date | null;
|
|
11
|
+
name?: string | null;
|
|
12
|
+
extendedFields?: import("@wix/auto_sdk_restaurants_item-modifiers").ExtendedFields;
|
|
13
|
+
inStock?: boolean | null;
|
|
14
|
+
businessLocationIds?: string[];
|
|
15
|
+
additionalChargeInfo?: {
|
|
16
|
+
additionalCharge?: string;
|
|
17
|
+
formattedAdditionalCharge?: string;
|
|
18
|
+
};
|
|
19
|
+
preSelected?: boolean;
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const getModifiersInitState = (modifierGroups) => {
|
|
2
|
+
const initialSelectedModifiers = {};
|
|
3
|
+
modifierGroups.forEach((group) => {
|
|
4
|
+
if (group._id) {
|
|
5
|
+
const isMultiSelectItem = !isSingleSelectRule(group.rule ?? {});
|
|
6
|
+
const formModifiers = group.modifiers.map(convertModifierToFormModifier);
|
|
7
|
+
if (isMultiSelectItem) {
|
|
8
|
+
const preSelectedModifiers = getPreSelectedModifiers(formModifiers);
|
|
9
|
+
initialSelectedModifiers[group._id] = preSelectedModifiers;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const preSelectedModifier = getFirstPreSelectedModifier(formModifiers);
|
|
13
|
+
initialSelectedModifiers[group._id] = preSelectedModifier
|
|
14
|
+
? [preSelectedModifier]
|
|
15
|
+
: [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return initialSelectedModifiers;
|
|
20
|
+
};
|
|
21
|
+
export const isSingleSelectRule = (rule) => rule.required && rule.minSelections === 1 && rule.maxSelections === 1;
|
|
22
|
+
export const getFirstPreSelectedModifier = (modifiers) => modifiers.find(({ preSelected, inStock }) => preSelected && inStock)?._id;
|
|
23
|
+
export const getPreSelectedModifiers = (modifiers) => modifiers.reduce((acc, modifier) => {
|
|
24
|
+
if (modifier.preSelected && modifier.inStock && modifier._id) {
|
|
25
|
+
return [...acc, modifier._id];
|
|
26
|
+
}
|
|
27
|
+
return acc;
|
|
28
|
+
}, []);
|
|
29
|
+
export const convertModifierToFormModifier = (modifier, index) => {
|
|
30
|
+
return {
|
|
31
|
+
...modifier,
|
|
32
|
+
_id: `${modifier._id}~${index}`,
|
|
33
|
+
};
|
|
34
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-restaurants-olo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "npm run build:esm && npm run build:cjs",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@radix-ui/react-slot": "^1.1.0",
|
|
54
54
|
"@wix/auto_sdk_restaurants_items": "^1.0.48",
|
|
55
55
|
"@wix/headless-media": "0.0.15",
|
|
56
|
-
"@wix/headless-restaurants-menus": "^0.0.
|
|
56
|
+
"@wix/headless-restaurants-menus": "^0.0.12",
|
|
57
57
|
"@wix/headless-utils": "^0.0.4",
|
|
58
58
|
"@wix/redirects": "^1.0.0",
|
|
59
59
|
"@wix/restaurants": "^1.0.396",
|