@wix/headless-restaurants-olo 0.0.18 → 0.0.20
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 +27 -7
- package/cjs/dist/react/ItemDetails.js +33 -6
- package/cjs/dist/react/core/ItemDetails.d.ts +7 -1
- package/cjs/dist/react/core/ItemDetails.js +18 -4
- package/cjs/dist/services/common-types.d.ts +8 -0
- package/cjs/dist/services/common-types.js +8 -0
- package/cjs/dist/services/index.d.ts +1 -1
- package/cjs/dist/services/index.js +1 -1
- package/cjs/dist/services/item-details-service.d.ts +9 -3
- package/cjs/dist/services/item-details-service.js +46 -29
- package/cjs/dist/services/olo-settings-service.d.ts +4 -0
- package/cjs/dist/services/olo-settings-service.js +4 -0
- package/cjs/dist/services/utils.d.ts +28 -0
- package/cjs/dist/services/utils.js +76 -0
- package/dist/react/ItemDetails.d.ts +27 -7
- package/dist/react/ItemDetails.js +33 -6
- package/dist/react/core/ItemDetails.d.ts +7 -1
- package/dist/react/core/ItemDetails.js +18 -4
- package/dist/services/common-types.d.ts +8 -0
- package/dist/services/common-types.js +8 -0
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/item-details-service.d.ts +9 -3
- package/dist/services/item-details-service.js +46 -29
- package/dist/services/olo-settings-service.d.ts +4 -0
- package/dist/services/olo-settings-service.js +4 -0
- package/dist/services/utils.d.ts +28 -0
- package/dist/services/utils.js +76 -0
- package/package.json +3 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { type AsChildChildren } from '@wix/headless-utils/react';
|
|
4
4
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
5
5
|
import { EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
6
|
-
import { AvailabilityStatus, AvailabilityStatusMap } from '../services/common-types.js';
|
|
6
|
+
import { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState } from '../services/common-types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Root component for menu item display and interaction.
|
|
9
9
|
* Provides context for all menu item-related components like name, price, description, image, etc.
|
|
@@ -72,6 +72,7 @@ export interface SpecialRequestProps {
|
|
|
72
72
|
asChild?: boolean;
|
|
73
73
|
children?: AsChildChildren<{
|
|
74
74
|
description: string;
|
|
75
|
+
onChange: (value: string) => void;
|
|
75
76
|
}>;
|
|
76
77
|
/** Placeholder text for the textarea */
|
|
77
78
|
placeholder?: string;
|
|
@@ -94,16 +95,35 @@ export interface SpecialRequestProps {
|
|
|
94
95
|
* Usage:
|
|
95
96
|
* <ItemDetails.AddToCartButton>Add to cart</ItemDetails.AddToCartButton>
|
|
96
97
|
*/
|
|
97
|
-
export interface AddToCartButtonProps
|
|
98
|
+
export interface AddToCartButtonProps {
|
|
98
99
|
asChild?: boolean;
|
|
99
|
-
children?: React.ReactNode;
|
|
100
100
|
className?: string;
|
|
101
|
-
|
|
101
|
+
addToCartLabelMap: Record<AddToCartButtonState, string>;
|
|
102
|
+
children: (props: {
|
|
103
|
+
lineItem: LineItem;
|
|
104
|
+
buttonState: AddToCartButtonState;
|
|
105
|
+
addToCartButtonDisabled?: boolean;
|
|
106
|
+
/** Content to display when loading */
|
|
107
|
+
loadingState?: string | React.ReactNode;
|
|
108
|
+
/** Text label for the button */
|
|
109
|
+
label: React.ReactNode;
|
|
110
|
+
formattedPrice: string;
|
|
111
|
+
}) => React.ReactNode;
|
|
102
112
|
}
|
|
113
|
+
export declare const AddToCartButton: React.ForwardRefExoticComponent<AddToCartButtonProps & React.RefAttributes<HTMLElement>>;
|
|
103
114
|
export interface ItemDetailsQuantityProps {
|
|
104
|
-
|
|
115
|
+
asChild?: boolean;
|
|
116
|
+
className?: string;
|
|
117
|
+
children: (props: {
|
|
118
|
+
quantity: number;
|
|
119
|
+
increment: () => void;
|
|
120
|
+
decrement: () => void;
|
|
121
|
+
setQuantity: (quantity: number) => void;
|
|
122
|
+
canIncrement: boolean;
|
|
123
|
+
canDecrement: boolean;
|
|
124
|
+
onValueChange: (value: number) => void;
|
|
125
|
+
}) => React.ReactNode;
|
|
105
126
|
}
|
|
106
|
-
export declare const AddToCartButton: React.FC<AddToCartButtonProps>;
|
|
107
127
|
export declare const Quantity: React.FC<ItemDetailsQuantityProps>;
|
|
108
128
|
export declare const SpecialRequest: React.ForwardRefExoticComponent<SpecialRequestProps & React.RefAttributes<never>>;
|
|
109
129
|
export interface ItemDetailsAvailabilityProps {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Commerce } from '@wix/ecom/components';
|
|
4
4
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
@@ -38,15 +38,42 @@ export const Variants = React.forwardRef(({ children, className, asChild, varian
|
|
|
38
38
|
} }));
|
|
39
39
|
});
|
|
40
40
|
Variants.displayName = 'ItemDetails.Variants';
|
|
41
|
-
export const AddToCartButton = ({ asChild, children, className,
|
|
42
|
-
return (_jsx(CoreItemDetails.LineItemComponent, { children: ({ lineItem
|
|
43
|
-
};
|
|
41
|
+
export const AddToCartButton = React.forwardRef(({ asChild, children, className, addToCartLabelMap, ...props }, ref) => {
|
|
42
|
+
return (_jsx(CoreItemDetails.LineItemComponent, { addToCartLabelMap: addToCartLabelMap, children: ({ lineItem, buttonState, addToCartButtonDisabled, loadingState, labelText, formattedPrice, }) => {
|
|
43
|
+
const label = (_jsxs(_Fragment, { children: [_jsx("span", { children: labelText }), " ", _jsx("span", { children: " | " }), _jsx("span", { children: formattedPrice })] }));
|
|
44
|
+
return (_jsx(AsChildSlot, { asChild: asChild, className: className, customElement: children, customElementProps: {
|
|
45
|
+
buttonState,
|
|
46
|
+
addToCartButtonDisabled,
|
|
47
|
+
loadingState,
|
|
48
|
+
lineItem,
|
|
49
|
+
lineItems: [lineItem],
|
|
50
|
+
label,
|
|
51
|
+
formattedPrice,
|
|
52
|
+
}, ref: ref, ...props, children: _jsx(Commerce.Actions.AddToCart, { asChild: false, label: label, className: className, lineItems: [lineItem], ...props, children: children({
|
|
53
|
+
lineItem,
|
|
54
|
+
buttonState,
|
|
55
|
+
addToCartButtonDisabled,
|
|
56
|
+
loadingState,
|
|
57
|
+
label,
|
|
58
|
+
formattedPrice,
|
|
59
|
+
}) }) }));
|
|
60
|
+
} }));
|
|
61
|
+
});
|
|
62
|
+
AddToCartButton.displayName = 'AddToCartButton';
|
|
44
63
|
export const Quantity = ({ children }) => {
|
|
45
|
-
return (_jsx(CoreItemDetails.QuantityComponent, { children: ({ quantity, onValueChange, }) => (_jsx(QuantityComponent.Root, { onValueChange: onValueChange, initialValue: quantity, children: children
|
|
64
|
+
return (_jsx(CoreItemDetails.QuantityComponent, { children: ({ quantity, onValueChange, increment, decrement, setQuantity, canIncrement, canDecrement, }) => (_jsx(QuantityComponent.Root, { onValueChange: onValueChange, initialValue: quantity, children: children({
|
|
65
|
+
quantity,
|
|
66
|
+
increment,
|
|
67
|
+
decrement,
|
|
68
|
+
setQuantity,
|
|
69
|
+
canIncrement,
|
|
70
|
+
canDecrement,
|
|
71
|
+
onValueChange,
|
|
72
|
+
}) })) }));
|
|
46
73
|
};
|
|
47
74
|
Quantity.displayName = 'Quantity';
|
|
48
75
|
export const SpecialRequest = React.forwardRef(({ className, labelClassName, placeholder = 'Any special requests or dietary restrictions?', maxLength = 200, rows = 3, label = 'Special Requests', asChild, children, ...props }, ref) => {
|
|
49
|
-
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 })] })) }));
|
|
76
|
+
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, onChange }, 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 })] })) }));
|
|
50
77
|
});
|
|
51
78
|
SpecialRequest.displayName = 'SpecialRequest';
|
|
52
79
|
export const AvailabilityComponent = React.forwardRef(({ asChild, children, textClassName, buttonClassName, availabilityStatusMap, ...rest }, ref) => {
|
|
@@ -2,7 +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 { EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
5
|
-
import { AvailabilityStatus, AvailabilityStatusMap } from '../../services/common-types.js';
|
|
5
|
+
import { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState } from '../../services/common-types.js';
|
|
6
6
|
interface ItemDetailsRootProps {
|
|
7
7
|
children: (props: {
|
|
8
8
|
item: unknown;
|
|
@@ -18,8 +18,14 @@ interface ItemDetailsSpecialRequestProps {
|
|
|
18
18
|
}
|
|
19
19
|
export declare const SpecialRequest: React.FC<ItemDetailsSpecialRequestProps>;
|
|
20
20
|
interface ItemDetailsLineItemProps {
|
|
21
|
+
addToCartLabelMap: Record<AddToCartButtonState, string>;
|
|
21
22
|
children: (props: {
|
|
23
|
+
loadingState: string | React.ReactNode;
|
|
22
24
|
lineItem: LineItem;
|
|
25
|
+
buttonState: AddToCartButtonState;
|
|
26
|
+
addToCartButtonDisabled: boolean;
|
|
27
|
+
labelText: string;
|
|
28
|
+
formattedPrice: string;
|
|
23
29
|
}) => React.ReactNode;
|
|
24
30
|
}
|
|
25
31
|
export declare const LineItemComponent: React.FC<ItemDetailsLineItemProps>;
|
|
@@ -5,11 +5,10 @@ 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 } from '@wix/headless-restaurants-menus/react';
|
|
8
|
-
import { AvailabilityStatus, } from '../../services/common-types.js';
|
|
8
|
+
import { AvailabilityStatus, AddToCartButtonState, } from '../../services/common-types.js';
|
|
9
9
|
export const Root = ({ children, itemDetailsServiceConfig, }) => {
|
|
10
10
|
const service = useService(OLOSettingsServiceDefinition);
|
|
11
11
|
const selectedItem = service.selectedItem?.get();
|
|
12
|
-
console.log('selectedItem', selectedItem, itemDetailsServiceConfig);
|
|
13
12
|
let config = itemDetailsServiceConfig;
|
|
14
13
|
if (!config) {
|
|
15
14
|
config = loadItemServiceConfig({
|
|
@@ -37,10 +36,25 @@ export const SpecialRequest = ({ children, }) => {
|
|
|
37
36
|
// maxLength: 200
|
|
38
37
|
});
|
|
39
38
|
};
|
|
40
|
-
export const LineItemComponent = ({ children, }) => {
|
|
39
|
+
export const LineItemComponent = ({ addToCartLabelMap, children, }) => {
|
|
41
40
|
const service = useService(ItemServiceDefinition);
|
|
41
|
+
const oloSettingsService = useService(OLOSettingsServiceDefinition);
|
|
42
42
|
const lineItem = service.lineItem?.get?.() ?? {};
|
|
43
|
-
|
|
43
|
+
const loadingState = service.isLoading?.get?.() ?? false;
|
|
44
|
+
const buttonState = service.buttonState?.get?.() ?? AddToCartButtonState.VALID_TO_CONTINUE;
|
|
45
|
+
const addToCartButtonDisabled = service.addToCartButtonDisabled?.get?.() ?? false;
|
|
46
|
+
const price = service.price?.get?.() ?? 0;
|
|
47
|
+
const formatCurrency = oloSettingsService.formatCurrency;
|
|
48
|
+
const formattedPrice = formatCurrency(price);
|
|
49
|
+
const labelText = addToCartLabelMap[buttonState];
|
|
50
|
+
return children({
|
|
51
|
+
loadingState,
|
|
52
|
+
lineItem,
|
|
53
|
+
buttonState,
|
|
54
|
+
addToCartButtonDisabled,
|
|
55
|
+
labelText,
|
|
56
|
+
formattedPrice,
|
|
57
|
+
});
|
|
44
58
|
};
|
|
45
59
|
export const QuantityComponent = ({ children, }) => {
|
|
46
60
|
const service = useService(ItemServiceDefinition);
|
|
@@ -35,3 +35,11 @@ export type AvailabilityStatusObject = {
|
|
|
35
35
|
text?: string;
|
|
36
36
|
};
|
|
37
37
|
export type AvailabilityStatusMap = Partial<Record<Exclude<AvailabilityStatus, NextAvailability>, AvailabilityStatusObject>> & Record<NextAvailability, AvailabilityStatusWithActionObject>;
|
|
38
|
+
export declare enum AddToCartButtonState {
|
|
39
|
+
ITEM_UNAVAILABLE = 0,
|
|
40
|
+
OUT_OF_STOCK = 1,
|
|
41
|
+
NOT_VALID = 2,
|
|
42
|
+
EDITING = 3,
|
|
43
|
+
VALID_TO_CONTINUE = 4
|
|
44
|
+
}
|
|
45
|
+
export type AddToCartButtonLabelMap = Record<AddToCartButtonState, string>;
|
|
@@ -16,3 +16,11 @@ export var AvailabilityStatus;
|
|
|
16
16
|
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_PICKUP"] = 3] = "NEXT_AVAILABILITY_PICKUP";
|
|
17
17
|
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_DELIVERY"] = 4] = "NEXT_AVAILABILITY_DELIVERY";
|
|
18
18
|
})(AvailabilityStatus || (AvailabilityStatus = {}));
|
|
19
|
+
export var AddToCartButtonState;
|
|
20
|
+
(function (AddToCartButtonState) {
|
|
21
|
+
AddToCartButtonState[AddToCartButtonState["ITEM_UNAVAILABLE"] = 0] = "ITEM_UNAVAILABLE";
|
|
22
|
+
AddToCartButtonState[AddToCartButtonState["OUT_OF_STOCK"] = 1] = "OUT_OF_STOCK";
|
|
23
|
+
AddToCartButtonState[AddToCartButtonState["NOT_VALID"] = 2] = "NOT_VALID";
|
|
24
|
+
AddToCartButtonState[AddToCartButtonState["EDITING"] = 3] = "EDITING";
|
|
25
|
+
AddToCartButtonState[AddToCartButtonState["VALID_TO_CONTINUE"] = 4] = "VALID_TO_CONTINUE";
|
|
26
|
+
})(AddToCartButtonState || (AddToCartButtonState = {}));
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
3
|
+
export { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState, AddToCartButtonLabelMap, } from './common-types.js';
|
|
4
4
|
export { FulfillmentsService, FulfillmentsServiceDefinition, loadFulfillmentsServiceConfig, } from './fulfillments-service.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
3
|
+
export { AvailabilityStatus, AddToCartButtonState, } from './common-types.js';
|
|
4
4
|
export { FulfillmentsService, FulfillmentsServiceDefinition, loadFulfillmentsServiceConfig, } from './fulfillments-service.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
1
|
+
import { type Signal, type ReadOnlySignal } 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
|
+
import { AddToCartButtonState, AvailabilityStatus } from './common-types.js';
|
|
6
6
|
type Variant = itemVariants.Variant;
|
|
7
7
|
/**
|
|
8
8
|
* API interface for the Item Detailsservice, providing reactive item data management.
|
|
@@ -15,7 +15,10 @@ export interface ItemServiceAPI {
|
|
|
15
15
|
item?: Signal<EnhancedItem | undefined>;
|
|
16
16
|
quantity: Signal<number>;
|
|
17
17
|
specialRequest: Signal<string>;
|
|
18
|
-
lineItem:
|
|
18
|
+
lineItem: ReadOnlySignal<LineItem>;
|
|
19
|
+
buttonState: ReadOnlySignal<AddToCartButtonState | undefined>;
|
|
20
|
+
addToCartButtonDisabled: Signal<boolean>;
|
|
21
|
+
price: ReadOnlySignal<number>;
|
|
19
22
|
selectedVariant: Signal<Variant | undefined>;
|
|
20
23
|
selectedModifiers: Signal<Record<string, Array<string>>>;
|
|
21
24
|
availabilityStatus: Signal<AvailabilityStatus>;
|
|
@@ -59,6 +62,9 @@ export interface ItemServiceConfig {
|
|
|
59
62
|
itemId?: string;
|
|
60
63
|
operationId?: string;
|
|
61
64
|
availabilityStatus?: AvailabilityStatus;
|
|
65
|
+
editItemMode?: boolean;
|
|
66
|
+
menuId?: string;
|
|
67
|
+
sectionId?: string;
|
|
62
68
|
}
|
|
63
69
|
export declare const ItemService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
64
70
|
__api: ItemServiceAPI;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
2
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
-
import { AvailabilityStatus } from './common-types.js';
|
|
4
|
-
import { getModifiersInitState } from './utils.js';
|
|
3
|
+
import { AddToCartButtonState, AvailabilityStatus } from './common-types.js';
|
|
4
|
+
import { getAreNotEnoughModifiersOfMandatoryModifierGroupInStock, getModifiersInitState, getLineItemModifiers, getPriceVariantOptions, getSelectedModifierPrices, getSelectedVariantPrice, calculateItemPrice, } from './utils.js';
|
|
5
|
+
import { OLOSettingsServiceDefinition } from './olo-settings-service.js';
|
|
5
6
|
/**
|
|
6
7
|
* Service definition for the Item service.
|
|
7
8
|
* This defines the contract that the ItemService must implement.
|
|
@@ -45,13 +46,13 @@ export const ItemServiceDefinition = defineService('item');
|
|
|
45
46
|
const APP_ID = '9a5d83fd-8570-482e-81ab-cfa88942ee60';
|
|
46
47
|
export const ItemService = implementService.withConfig()(ItemServiceDefinition, ({ getService, config }) => {
|
|
47
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
49
|
+
const oloSettingsService = getService(OLOSettingsServiceDefinition);
|
|
48
50
|
const availabilityStatus = signalsService.signal(config.availabilityStatus ?? AvailabilityStatus.AVAILABLE);
|
|
49
51
|
const item = signalsService.signal(config.item);
|
|
50
52
|
const isLoading = signalsService.signal(!!config.item);
|
|
51
53
|
const error = signalsService.signal(config.item ? null : 'Item not found');
|
|
52
54
|
const quantity = signalsService.signal(1);
|
|
53
55
|
const specialRequest = signalsService.signal('');
|
|
54
|
-
const lineItem = signalsService.signal({});
|
|
55
56
|
const priceVariants = config.item?.priceVariants || [];
|
|
56
57
|
const initialVariant = priceVariants.length > 0 ? priceVariants[0] : undefined;
|
|
57
58
|
const selectedVariant = signalsService.signal(initialVariant);
|
|
@@ -65,44 +66,57 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
65
66
|
return acc;
|
|
66
67
|
}, {});
|
|
67
68
|
const modifierGroupError = signalsService.signal(initialModifierGroupError);
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const price = signalsService.computed(() => {
|
|
70
|
+
const basePrice = Number(config?.item?.priceInfo?.price ?? 0);
|
|
71
|
+
const variantPrice = getSelectedVariantPrice(selectedVariant.get(), priceVariants);
|
|
72
|
+
const modifierPrices = getSelectedModifierPrices(selectedModifiers.get() || {}, modifierGroups);
|
|
73
|
+
const itemQuantity = quantity.get() ?? 1;
|
|
74
|
+
return calculateItemPrice(basePrice, variantPrice, modifierPrices, itemQuantity);
|
|
75
|
+
});
|
|
76
|
+
const areModifiersOfMandatoryModifierGroupOutOfStock = getAreNotEnoughModifiersOfMandatoryModifierGroupInStock(modifierGroups);
|
|
77
|
+
const canAcceptOrders = oloSettingsService.canAcceptOrders ?? true;
|
|
78
|
+
const isValidToContinue = canAcceptOrders &&
|
|
79
|
+
config?.item?.orderSettings?.inStock &&
|
|
80
|
+
config.availabilityStatus === AvailabilityStatus.AVAILABLE &&
|
|
81
|
+
!areModifiersOfMandatoryModifierGroupOutOfStock;
|
|
82
|
+
const buttonState = signalsService.computed(() => {
|
|
83
|
+
return !config?.item?.orderSettings?.inStock ||
|
|
84
|
+
areModifiersOfMandatoryModifierGroupOutOfStock
|
|
85
|
+
? AddToCartButtonState.OUT_OF_STOCK
|
|
86
|
+
: availabilityStatus.get() !== AvailabilityStatus.AVAILABLE
|
|
87
|
+
? AddToCartButtonState.ITEM_UNAVAILABLE
|
|
88
|
+
: !canAcceptOrders
|
|
89
|
+
? AddToCartButtonState.NOT_VALID
|
|
90
|
+
: config.editItemMode
|
|
91
|
+
? AddToCartButtonState.EDITING
|
|
92
|
+
: isValidToContinue
|
|
93
|
+
? AddToCartButtonState.VALID_TO_CONTINUE
|
|
94
|
+
: AddToCartButtonState.NOT_VALID;
|
|
95
|
+
});
|
|
96
|
+
const addToCartButtonDisabled = signalsService.signal(!isValidToContinue);
|
|
97
|
+
const lineItem = signalsService.computed(() => {
|
|
98
|
+
const formatCurrency = oloSettingsService.formatCurrency;
|
|
99
|
+
return {
|
|
70
100
|
quantity: quantity.get(),
|
|
71
101
|
catalogReference: {
|
|
72
|
-
|
|
73
|
-
catalogItemId: config.item._id,
|
|
102
|
+
catalogItemId: config.item?._id ?? undefined,
|
|
74
103
|
appId: APP_ID,
|
|
75
104
|
options: {
|
|
76
105
|
operationId: config.operationId,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
menuId: config.menuId,
|
|
107
|
+
sectionId: config.sectionId,
|
|
108
|
+
priceVariant: getPriceVariantOptions(selectedVariant.get(), formatCurrency),
|
|
109
|
+
modifierGroups: getLineItemModifiers(selectedModifiers.get(), modifierGroups, formatCurrency),
|
|
110
|
+
specialRequests: specialRequest.get(),
|
|
81
111
|
},
|
|
82
112
|
},
|
|
83
|
-
}
|
|
84
|
-
}
|
|
113
|
+
};
|
|
114
|
+
});
|
|
85
115
|
const updateQuantity = (_quantity) => {
|
|
86
116
|
quantity.set(_quantity);
|
|
87
|
-
const _lineItem = lineItem.get();
|
|
88
|
-
lineItem.set({
|
|
89
|
-
..._lineItem,
|
|
90
|
-
quantity: _quantity,
|
|
91
|
-
});
|
|
92
117
|
};
|
|
93
118
|
const updateSpecialRequest = (_specialRequest) => {
|
|
94
119
|
specialRequest.set(_specialRequest);
|
|
95
|
-
const _lineItem = lineItem.get();
|
|
96
|
-
lineItem.set({
|
|
97
|
-
..._lineItem,
|
|
98
|
-
catalogReference: {
|
|
99
|
-
..._lineItem.catalogReference,
|
|
100
|
-
options: {
|
|
101
|
-
..._lineItem.catalogReference?.options,
|
|
102
|
-
specialRequest: _specialRequest,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
120
|
};
|
|
107
121
|
const updateSelectedVariant = (variant) => {
|
|
108
122
|
selectedVariant.set(variant);
|
|
@@ -157,6 +171,9 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
157
171
|
availabilityStatus,
|
|
158
172
|
getSelectedModifiers,
|
|
159
173
|
modifierGroupError,
|
|
174
|
+
buttonState,
|
|
175
|
+
addToCartButtonDisabled,
|
|
176
|
+
price,
|
|
160
177
|
};
|
|
161
178
|
});
|
|
162
179
|
/**
|
|
@@ -11,12 +11,16 @@ export interface OLOSettingsServiceAPI {
|
|
|
11
11
|
currentFulfillment: Signal<string>;
|
|
12
12
|
currentTimeSlot: Signal<string>;
|
|
13
13
|
filterMenus: (menus: MenusServiceConfig['menus']) => MenusServiceConfig['menus'];
|
|
14
|
+
canAcceptOrders: boolean;
|
|
15
|
+
formatCurrency: (price?: number) => string;
|
|
14
16
|
}
|
|
15
17
|
export interface OLOSettingsServiceConfig {
|
|
16
18
|
operationGroup?: operationGroupsSDK.OperationGroup;
|
|
17
19
|
operation?: operationsSDK.Operation;
|
|
18
20
|
availabilityDispatchAction?: () => void;
|
|
19
21
|
menuIdsByOperation?: string[];
|
|
22
|
+
canAcceptOrders?: boolean;
|
|
23
|
+
formattedPrice?: (price?: number) => string;
|
|
20
24
|
}
|
|
21
25
|
export declare const OLOSettingsServiceDefinition: string & {
|
|
22
26
|
__api: OLOSettingsServiceAPI;
|
|
@@ -8,6 +8,8 @@ export const OLOSettingsService = implementService.withConfig()(OLOSettingsServi
|
|
|
8
8
|
const availabilityDispatchAction = signalsService.signal(config.availabilityDispatchAction);
|
|
9
9
|
const operationGroup = signalsService.signal(config.operationGroup);
|
|
10
10
|
const operation = signalsService.signal(config.operation);
|
|
11
|
+
const formatCurrency = config.formattedPrice ??
|
|
12
|
+
((price) => price?.toFixed(2)?.toString() ?? '');
|
|
11
13
|
const selectedItem = signalsService.signal(null);
|
|
12
14
|
const isLoading = signalsService.signal(false);
|
|
13
15
|
const error = signalsService.signal(null);
|
|
@@ -27,6 +29,8 @@ export const OLOSettingsService = implementService.withConfig()(OLOSettingsServi
|
|
|
27
29
|
currentFulfillment,
|
|
28
30
|
currentTimeSlot,
|
|
29
31
|
filterMenus,
|
|
32
|
+
canAcceptOrders: config.canAcceptOrders ?? true,
|
|
33
|
+
formatCurrency,
|
|
30
34
|
};
|
|
31
35
|
});
|
|
32
36
|
export async function loadOLOSettingsServiceConfig() {
|
|
@@ -34,4 +34,32 @@ export declare const hasToChooseAtLeastX: ({ required, minSelections, maxSelecti
|
|
|
34
34
|
export declare const chooseUpToX: ({ required, minSelections, maxSelections, }: ruleUtilsArgs) => boolean;
|
|
35
35
|
export declare const hasToChooseBetweenXAndY: ({ required, minSelections, maxSelections, }: ruleUtilsArgs) => boolean;
|
|
36
36
|
export declare const getRuleTypeMapValue: (ruleTypeMap: RuleTypeMap, ruleType: RuleType, modifierGroupName: string, rule: EnhancedModifierGroup["rule"]) => string | undefined;
|
|
37
|
+
export declare const getAreNotEnoughModifiersOfMandatoryModifierGroupInStock: (modifierGroups: EnhancedModifierGroup[]) => boolean;
|
|
38
|
+
export declare const getLineItemModifiers: (selectedModifiers: Record<string, Array<string>>, modifierGroups: EnhancedModifierGroup[], formatCurrency: (price?: number) => string) => {
|
|
39
|
+
id: string;
|
|
40
|
+
modifiers: {
|
|
41
|
+
id: string;
|
|
42
|
+
price: string | undefined;
|
|
43
|
+
formattedPrice: string | undefined;
|
|
44
|
+
}[];
|
|
45
|
+
}[] | undefined;
|
|
46
|
+
export declare const getPriceVariantOptions: (selectedPriceVariant: {
|
|
47
|
+
_id?: string | null;
|
|
48
|
+
priceInfo?: {
|
|
49
|
+
price?: string;
|
|
50
|
+
};
|
|
51
|
+
} | undefined, formatCurrency: (price?: number) => string) => {
|
|
52
|
+
id: string;
|
|
53
|
+
formattedPrice: string;
|
|
54
|
+
} | undefined;
|
|
55
|
+
export declare const getSelectedModifierPrices: (selectedModifiers: Record<string, Array<string>>, modifierGroups: EnhancedModifierGroup[]) => number;
|
|
56
|
+
export declare const getSelectedVariantPrice: (selectedVariant: {
|
|
57
|
+
_id?: string | null;
|
|
58
|
+
} | undefined, priceVariants: Array<{
|
|
59
|
+
_id?: string | null;
|
|
60
|
+
priceInfo?: {
|
|
61
|
+
price?: string;
|
|
62
|
+
};
|
|
63
|
+
}>) => number;
|
|
64
|
+
export declare const calculateItemPrice: (basePrice: number, variantPrice: number, modifierPrices: number, quantity: number) => number;
|
|
37
65
|
export {};
|
|
@@ -136,3 +136,79 @@ export const getRuleTypeMapValue = (ruleTypeMap, ruleType, modifierGroupName, ru
|
|
|
136
136
|
}
|
|
137
137
|
return undefined;
|
|
138
138
|
};
|
|
139
|
+
export const getAreNotEnoughModifiersOfMandatoryModifierGroupInStock = (modifierGroups) => modifierGroups.some((modifierGroup) => {
|
|
140
|
+
const isModifierGroupMandatory = modifierGroup.rule?.required;
|
|
141
|
+
const minimumRequiredModifiers = modifierGroup.rule?.minSelections ?? 0;
|
|
142
|
+
const inStockModifiers = modifierGroup.modifiers.filter((modifier) => modifier.inStock ?? true);
|
|
143
|
+
const areMinimumRequiredModifiersInStock = inStockModifiers.length >= minimumRequiredModifiers;
|
|
144
|
+
return isModifierGroupMandatory && !areMinimumRequiredModifiersInStock;
|
|
145
|
+
});
|
|
146
|
+
export const getLineItemModifiers = (selectedModifiers, modifierGroups, formatCurrency) => {
|
|
147
|
+
const modifierGroupsOptions = modifierGroups
|
|
148
|
+
.map((modifierGroup) => {
|
|
149
|
+
const selectedModifierIds = selectedModifiers[modifierGroup._id ?? ''];
|
|
150
|
+
if (!selectedModifierIds || selectedModifierIds.length === 0) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const modifiers = selectedModifierIds
|
|
154
|
+
.map((modifierIdWithIndex) => {
|
|
155
|
+
const baseModifierId = modifierIdWithIndex.split('~')[0];
|
|
156
|
+
const modifier = modifierGroup.modifiers.find((mod) => mod._id === baseModifierId);
|
|
157
|
+
if (!modifier)
|
|
158
|
+
return null;
|
|
159
|
+
const price = Number(modifier?.additionalChargeInfo?.additionalCharge ?? 0);
|
|
160
|
+
return {
|
|
161
|
+
id: modifier._id ?? '',
|
|
162
|
+
price: modifier?.additionalChargeInfo?.additionalCharge,
|
|
163
|
+
formattedPrice: price > 0 ? formatCurrency(price) : undefined,
|
|
164
|
+
};
|
|
165
|
+
})
|
|
166
|
+
.filter((modifier) => modifier !== null);
|
|
167
|
+
if (modifiers.length === 0 || !modifierGroup._id) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
id: modifierGroup._id,
|
|
172
|
+
modifiers,
|
|
173
|
+
};
|
|
174
|
+
})
|
|
175
|
+
.filter((modifierGroup) => modifierGroup !== null &&
|
|
176
|
+
modifierGroup.modifiers.length > 0 &&
|
|
177
|
+
!!modifierGroup?.id?.length);
|
|
178
|
+
return modifierGroupsOptions.length > 0 ? modifierGroupsOptions : undefined;
|
|
179
|
+
};
|
|
180
|
+
export const getPriceVariantOptions = (selectedPriceVariant, formatCurrency) => {
|
|
181
|
+
const variantId = selectedPriceVariant?._id;
|
|
182
|
+
const variantPrice = selectedPriceVariant?.priceInfo?.price;
|
|
183
|
+
if (!variantId) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
const price = variantPrice ? Number(variantPrice) : undefined;
|
|
187
|
+
return {
|
|
188
|
+
id: variantId,
|
|
189
|
+
formattedPrice: formatCurrency(price),
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
export const getSelectedModifierPrices = (selectedModifiers, modifierGroups) => {
|
|
193
|
+
return Object.entries(selectedModifiers).reduce((total, [modifierGroupId, modifierIds]) => {
|
|
194
|
+
const groupTotal = modifierIds.reduce((groupSum, modifierId) => {
|
|
195
|
+
const baseModifierId = modifierId.split('~')[0];
|
|
196
|
+
const modifier = modifierGroups
|
|
197
|
+
.find((group) => group._id === modifierGroupId)
|
|
198
|
+
?.modifiers.find((mod) => mod._id === baseModifierId);
|
|
199
|
+
return (groupSum +
|
|
200
|
+
Number(modifier?.additionalChargeInfo?.additionalCharge ?? 0));
|
|
201
|
+
}, 0);
|
|
202
|
+
return total + groupTotal;
|
|
203
|
+
}, 0);
|
|
204
|
+
};
|
|
205
|
+
export const getSelectedVariantPrice = (selectedVariant, priceVariants) => {
|
|
206
|
+
if (!selectedVariant?._id) {
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
const variant = priceVariants.find((variant) => variant._id === selectedVariant._id);
|
|
210
|
+
return Number(variant?.priceInfo?.price ?? 0);
|
|
211
|
+
};
|
|
212
|
+
export const calculateItemPrice = (basePrice, variantPrice, modifierPrices, quantity) => {
|
|
213
|
+
return (basePrice + variantPrice + modifierPrices) * quantity;
|
|
214
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { type LineItem } from '@wix/ecom/services';
|
|
3
3
|
import { type AsChildChildren } from '@wix/headless-utils/react';
|
|
4
4
|
import { ItemServiceConfig } from '../services/item-details-service.js';
|
|
5
5
|
import { EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
6
|
-
import { AvailabilityStatus, AvailabilityStatusMap } from '../services/common-types.js';
|
|
6
|
+
import { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState } from '../services/common-types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Root component for menu item display and interaction.
|
|
9
9
|
* Provides context for all menu item-related components like name, price, description, image, etc.
|
|
@@ -72,6 +72,7 @@ export interface SpecialRequestProps {
|
|
|
72
72
|
asChild?: boolean;
|
|
73
73
|
children?: AsChildChildren<{
|
|
74
74
|
description: string;
|
|
75
|
+
onChange: (value: string) => void;
|
|
75
76
|
}>;
|
|
76
77
|
/** Placeholder text for the textarea */
|
|
77
78
|
placeholder?: string;
|
|
@@ -94,16 +95,35 @@ export interface SpecialRequestProps {
|
|
|
94
95
|
* Usage:
|
|
95
96
|
* <ItemDetails.AddToCartButton>Add to cart</ItemDetails.AddToCartButton>
|
|
96
97
|
*/
|
|
97
|
-
export interface AddToCartButtonProps
|
|
98
|
+
export interface AddToCartButtonProps {
|
|
98
99
|
asChild?: boolean;
|
|
99
|
-
children?: React.ReactNode;
|
|
100
100
|
className?: string;
|
|
101
|
-
|
|
101
|
+
addToCartLabelMap: Record<AddToCartButtonState, string>;
|
|
102
|
+
children: (props: {
|
|
103
|
+
lineItem: LineItem;
|
|
104
|
+
buttonState: AddToCartButtonState;
|
|
105
|
+
addToCartButtonDisabled?: boolean;
|
|
106
|
+
/** Content to display when loading */
|
|
107
|
+
loadingState?: string | React.ReactNode;
|
|
108
|
+
/** Text label for the button */
|
|
109
|
+
label: React.ReactNode;
|
|
110
|
+
formattedPrice: string;
|
|
111
|
+
}) => React.ReactNode;
|
|
102
112
|
}
|
|
113
|
+
export declare const AddToCartButton: React.ForwardRefExoticComponent<AddToCartButtonProps & React.RefAttributes<HTMLElement>>;
|
|
103
114
|
export interface ItemDetailsQuantityProps {
|
|
104
|
-
|
|
115
|
+
asChild?: boolean;
|
|
116
|
+
className?: string;
|
|
117
|
+
children: (props: {
|
|
118
|
+
quantity: number;
|
|
119
|
+
increment: () => void;
|
|
120
|
+
decrement: () => void;
|
|
121
|
+
setQuantity: (quantity: number) => void;
|
|
122
|
+
canIncrement: boolean;
|
|
123
|
+
canDecrement: boolean;
|
|
124
|
+
onValueChange: (value: number) => void;
|
|
125
|
+
}) => React.ReactNode;
|
|
105
126
|
}
|
|
106
|
-
export declare const AddToCartButton: React.FC<AddToCartButtonProps>;
|
|
107
127
|
export declare const Quantity: React.FC<ItemDetailsQuantityProps>;
|
|
108
128
|
export declare const SpecialRequest: React.ForwardRefExoticComponent<SpecialRequestProps & React.RefAttributes<never>>;
|
|
109
129
|
export interface ItemDetailsAvailabilityProps {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Commerce } from '@wix/ecom/components';
|
|
4
4
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
@@ -38,15 +38,42 @@ export const Variants = React.forwardRef(({ children, className, asChild, varian
|
|
|
38
38
|
} }));
|
|
39
39
|
});
|
|
40
40
|
Variants.displayName = 'ItemDetails.Variants';
|
|
41
|
-
export const AddToCartButton = ({ asChild, children, className,
|
|
42
|
-
return (_jsx(CoreItemDetails.LineItemComponent, { children: ({ lineItem
|
|
43
|
-
};
|
|
41
|
+
export const AddToCartButton = React.forwardRef(({ asChild, children, className, addToCartLabelMap, ...props }, ref) => {
|
|
42
|
+
return (_jsx(CoreItemDetails.LineItemComponent, { addToCartLabelMap: addToCartLabelMap, children: ({ lineItem, buttonState, addToCartButtonDisabled, loadingState, labelText, formattedPrice, }) => {
|
|
43
|
+
const label = (_jsxs(_Fragment, { children: [_jsx("span", { children: labelText }), " ", _jsx("span", { children: " | " }), _jsx("span", { children: formattedPrice })] }));
|
|
44
|
+
return (_jsx(AsChildSlot, { asChild: asChild, className: className, customElement: children, customElementProps: {
|
|
45
|
+
buttonState,
|
|
46
|
+
addToCartButtonDisabled,
|
|
47
|
+
loadingState,
|
|
48
|
+
lineItem,
|
|
49
|
+
lineItems: [lineItem],
|
|
50
|
+
label,
|
|
51
|
+
formattedPrice,
|
|
52
|
+
}, ref: ref, ...props, children: _jsx(Commerce.Actions.AddToCart, { asChild: false, label: label, className: className, lineItems: [lineItem], ...props, children: children({
|
|
53
|
+
lineItem,
|
|
54
|
+
buttonState,
|
|
55
|
+
addToCartButtonDisabled,
|
|
56
|
+
loadingState,
|
|
57
|
+
label,
|
|
58
|
+
formattedPrice,
|
|
59
|
+
}) }) }));
|
|
60
|
+
} }));
|
|
61
|
+
});
|
|
62
|
+
AddToCartButton.displayName = 'AddToCartButton';
|
|
44
63
|
export const Quantity = ({ children }) => {
|
|
45
|
-
return (_jsx(CoreItemDetails.QuantityComponent, { children: ({ quantity, onValueChange, }) => (_jsx(QuantityComponent.Root, { onValueChange: onValueChange, initialValue: quantity, children: children
|
|
64
|
+
return (_jsx(CoreItemDetails.QuantityComponent, { children: ({ quantity, onValueChange, increment, decrement, setQuantity, canIncrement, canDecrement, }) => (_jsx(QuantityComponent.Root, { onValueChange: onValueChange, initialValue: quantity, children: children({
|
|
65
|
+
quantity,
|
|
66
|
+
increment,
|
|
67
|
+
decrement,
|
|
68
|
+
setQuantity,
|
|
69
|
+
canIncrement,
|
|
70
|
+
canDecrement,
|
|
71
|
+
onValueChange,
|
|
72
|
+
}) })) }));
|
|
46
73
|
};
|
|
47
74
|
Quantity.displayName = 'Quantity';
|
|
48
75
|
export const SpecialRequest = React.forwardRef(({ className, labelClassName, placeholder = 'Any special requests or dietary restrictions?', maxLength = 200, rows = 3, label = 'Special Requests', asChild, children, ...props }, ref) => {
|
|
49
|
-
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 })] })) }));
|
|
76
|
+
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, onChange }, 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 })] })) }));
|
|
50
77
|
});
|
|
51
78
|
SpecialRequest.displayName = 'SpecialRequest';
|
|
52
79
|
export const AvailabilityComponent = React.forwardRef(({ asChild, children, textClassName, buttonClassName, availabilityStatusMap, ...rest }, ref) => {
|
|
@@ -2,7 +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 { EnhancedVariant } from '@wix/headless-restaurants-menus/services';
|
|
5
|
-
import { AvailabilityStatus, AvailabilityStatusMap } from '../../services/common-types.js';
|
|
5
|
+
import { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState } from '../../services/common-types.js';
|
|
6
6
|
interface ItemDetailsRootProps {
|
|
7
7
|
children: (props: {
|
|
8
8
|
item: unknown;
|
|
@@ -18,8 +18,14 @@ interface ItemDetailsSpecialRequestProps {
|
|
|
18
18
|
}
|
|
19
19
|
export declare const SpecialRequest: React.FC<ItemDetailsSpecialRequestProps>;
|
|
20
20
|
interface ItemDetailsLineItemProps {
|
|
21
|
+
addToCartLabelMap: Record<AddToCartButtonState, string>;
|
|
21
22
|
children: (props: {
|
|
23
|
+
loadingState: string | React.ReactNode;
|
|
22
24
|
lineItem: LineItem;
|
|
25
|
+
buttonState: AddToCartButtonState;
|
|
26
|
+
addToCartButtonDisabled: boolean;
|
|
27
|
+
labelText: string;
|
|
28
|
+
formattedPrice: string;
|
|
23
29
|
}) => React.ReactNode;
|
|
24
30
|
}
|
|
25
31
|
export declare const LineItemComponent: React.FC<ItemDetailsLineItemProps>;
|
|
@@ -5,11 +5,10 @@ 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 } from '@wix/headless-restaurants-menus/react';
|
|
8
|
-
import { AvailabilityStatus, } from '../../services/common-types.js';
|
|
8
|
+
import { AvailabilityStatus, AddToCartButtonState, } from '../../services/common-types.js';
|
|
9
9
|
export const Root = ({ children, itemDetailsServiceConfig, }) => {
|
|
10
10
|
const service = useService(OLOSettingsServiceDefinition);
|
|
11
11
|
const selectedItem = service.selectedItem?.get();
|
|
12
|
-
console.log('selectedItem', selectedItem, itemDetailsServiceConfig);
|
|
13
12
|
let config = itemDetailsServiceConfig;
|
|
14
13
|
if (!config) {
|
|
15
14
|
config = loadItemServiceConfig({
|
|
@@ -37,10 +36,25 @@ export const SpecialRequest = ({ children, }) => {
|
|
|
37
36
|
// maxLength: 200
|
|
38
37
|
});
|
|
39
38
|
};
|
|
40
|
-
export const LineItemComponent = ({ children, }) => {
|
|
39
|
+
export const LineItemComponent = ({ addToCartLabelMap, children, }) => {
|
|
41
40
|
const service = useService(ItemServiceDefinition);
|
|
41
|
+
const oloSettingsService = useService(OLOSettingsServiceDefinition);
|
|
42
42
|
const lineItem = service.lineItem?.get?.() ?? {};
|
|
43
|
-
|
|
43
|
+
const loadingState = service.isLoading?.get?.() ?? false;
|
|
44
|
+
const buttonState = service.buttonState?.get?.() ?? AddToCartButtonState.VALID_TO_CONTINUE;
|
|
45
|
+
const addToCartButtonDisabled = service.addToCartButtonDisabled?.get?.() ?? false;
|
|
46
|
+
const price = service.price?.get?.() ?? 0;
|
|
47
|
+
const formatCurrency = oloSettingsService.formatCurrency;
|
|
48
|
+
const formattedPrice = formatCurrency(price);
|
|
49
|
+
const labelText = addToCartLabelMap[buttonState];
|
|
50
|
+
return children({
|
|
51
|
+
loadingState,
|
|
52
|
+
lineItem,
|
|
53
|
+
buttonState,
|
|
54
|
+
addToCartButtonDisabled,
|
|
55
|
+
labelText,
|
|
56
|
+
formattedPrice,
|
|
57
|
+
});
|
|
44
58
|
};
|
|
45
59
|
export const QuantityComponent = ({ children, }) => {
|
|
46
60
|
const service = useService(ItemServiceDefinition);
|
|
@@ -35,3 +35,11 @@ export type AvailabilityStatusObject = {
|
|
|
35
35
|
text?: string;
|
|
36
36
|
};
|
|
37
37
|
export type AvailabilityStatusMap = Partial<Record<Exclude<AvailabilityStatus, NextAvailability>, AvailabilityStatusObject>> & Record<NextAvailability, AvailabilityStatusWithActionObject>;
|
|
38
|
+
export declare enum AddToCartButtonState {
|
|
39
|
+
ITEM_UNAVAILABLE = 0,
|
|
40
|
+
OUT_OF_STOCK = 1,
|
|
41
|
+
NOT_VALID = 2,
|
|
42
|
+
EDITING = 3,
|
|
43
|
+
VALID_TO_CONTINUE = 4
|
|
44
|
+
}
|
|
45
|
+
export type AddToCartButtonLabelMap = Record<AddToCartButtonState, string>;
|
|
@@ -16,3 +16,11 @@ export var AvailabilityStatus;
|
|
|
16
16
|
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_PICKUP"] = 3] = "NEXT_AVAILABILITY_PICKUP";
|
|
17
17
|
AvailabilityStatus[AvailabilityStatus["NEXT_AVAILABILITY_DELIVERY"] = 4] = "NEXT_AVAILABILITY_DELIVERY";
|
|
18
18
|
})(AvailabilityStatus || (AvailabilityStatus = {}));
|
|
19
|
+
export var AddToCartButtonState;
|
|
20
|
+
(function (AddToCartButtonState) {
|
|
21
|
+
AddToCartButtonState[AddToCartButtonState["ITEM_UNAVAILABLE"] = 0] = "ITEM_UNAVAILABLE";
|
|
22
|
+
AddToCartButtonState[AddToCartButtonState["OUT_OF_STOCK"] = 1] = "OUT_OF_STOCK";
|
|
23
|
+
AddToCartButtonState[AddToCartButtonState["NOT_VALID"] = 2] = "NOT_VALID";
|
|
24
|
+
AddToCartButtonState[AddToCartButtonState["EDITING"] = 3] = "EDITING";
|
|
25
|
+
AddToCartButtonState[AddToCartButtonState["VALID_TO_CONTINUE"] = 4] = "VALID_TO_CONTINUE";
|
|
26
|
+
})(AddToCartButtonState || (AddToCartButtonState = {}));
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
3
|
+
export { AvailabilityStatus, AvailabilityStatusMap, AddToCartButtonState, AddToCartButtonLabelMap, } from './common-types.js';
|
|
4
4
|
export { FulfillmentsService, FulfillmentsServiceDefinition, loadFulfillmentsServiceConfig, } from './fulfillments-service.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
3
|
+
export { AvailabilityStatus, AddToCartButtonState, } from './common-types.js';
|
|
4
4
|
export { FulfillmentsService, FulfillmentsServiceDefinition, loadFulfillmentsServiceConfig, } from './fulfillments-service.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
1
|
+
import { type Signal, type ReadOnlySignal } 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
|
+
import { AddToCartButtonState, AvailabilityStatus } from './common-types.js';
|
|
6
6
|
type Variant = itemVariants.Variant;
|
|
7
7
|
/**
|
|
8
8
|
* API interface for the Item Detailsservice, providing reactive item data management.
|
|
@@ -15,7 +15,10 @@ export interface ItemServiceAPI {
|
|
|
15
15
|
item?: Signal<EnhancedItem | undefined>;
|
|
16
16
|
quantity: Signal<number>;
|
|
17
17
|
specialRequest: Signal<string>;
|
|
18
|
-
lineItem:
|
|
18
|
+
lineItem: ReadOnlySignal<LineItem>;
|
|
19
|
+
buttonState: ReadOnlySignal<AddToCartButtonState | undefined>;
|
|
20
|
+
addToCartButtonDisabled: Signal<boolean>;
|
|
21
|
+
price: ReadOnlySignal<number>;
|
|
19
22
|
selectedVariant: Signal<Variant | undefined>;
|
|
20
23
|
selectedModifiers: Signal<Record<string, Array<string>>>;
|
|
21
24
|
availabilityStatus: Signal<AvailabilityStatus>;
|
|
@@ -59,6 +62,9 @@ export interface ItemServiceConfig {
|
|
|
59
62
|
itemId?: string;
|
|
60
63
|
operationId?: string;
|
|
61
64
|
availabilityStatus?: AvailabilityStatus;
|
|
65
|
+
editItemMode?: boolean;
|
|
66
|
+
menuId?: string;
|
|
67
|
+
sectionId?: string;
|
|
62
68
|
}
|
|
63
69
|
export declare const ItemService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
64
70
|
__api: ItemServiceAPI;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
2
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
-
import { AvailabilityStatus } from './common-types.js';
|
|
4
|
-
import { getModifiersInitState } from './utils.js';
|
|
3
|
+
import { AddToCartButtonState, AvailabilityStatus } from './common-types.js';
|
|
4
|
+
import { getAreNotEnoughModifiersOfMandatoryModifierGroupInStock, getModifiersInitState, getLineItemModifiers, getPriceVariantOptions, getSelectedModifierPrices, getSelectedVariantPrice, calculateItemPrice, } from './utils.js';
|
|
5
|
+
import { OLOSettingsServiceDefinition } from './olo-settings-service.js';
|
|
5
6
|
/**
|
|
6
7
|
* Service definition for the Item service.
|
|
7
8
|
* This defines the contract that the ItemService must implement.
|
|
@@ -45,13 +46,13 @@ export const ItemServiceDefinition = defineService('item');
|
|
|
45
46
|
const APP_ID = '9a5d83fd-8570-482e-81ab-cfa88942ee60';
|
|
46
47
|
export const ItemService = implementService.withConfig()(ItemServiceDefinition, ({ getService, config }) => {
|
|
47
48
|
const signalsService = getService(SignalsServiceDefinition);
|
|
49
|
+
const oloSettingsService = getService(OLOSettingsServiceDefinition);
|
|
48
50
|
const availabilityStatus = signalsService.signal(config.availabilityStatus ?? AvailabilityStatus.AVAILABLE);
|
|
49
51
|
const item = signalsService.signal(config.item);
|
|
50
52
|
const isLoading = signalsService.signal(!!config.item);
|
|
51
53
|
const error = signalsService.signal(config.item ? null : 'Item not found');
|
|
52
54
|
const quantity = signalsService.signal(1);
|
|
53
55
|
const specialRequest = signalsService.signal('');
|
|
54
|
-
const lineItem = signalsService.signal({});
|
|
55
56
|
const priceVariants = config.item?.priceVariants || [];
|
|
56
57
|
const initialVariant = priceVariants.length > 0 ? priceVariants[0] : undefined;
|
|
57
58
|
const selectedVariant = signalsService.signal(initialVariant);
|
|
@@ -65,44 +66,57 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
65
66
|
return acc;
|
|
66
67
|
}, {});
|
|
67
68
|
const modifierGroupError = signalsService.signal(initialModifierGroupError);
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const price = signalsService.computed(() => {
|
|
70
|
+
const basePrice = Number(config?.item?.priceInfo?.price ?? 0);
|
|
71
|
+
const variantPrice = getSelectedVariantPrice(selectedVariant.get(), priceVariants);
|
|
72
|
+
const modifierPrices = getSelectedModifierPrices(selectedModifiers.get() || {}, modifierGroups);
|
|
73
|
+
const itemQuantity = quantity.get() ?? 1;
|
|
74
|
+
return calculateItemPrice(basePrice, variantPrice, modifierPrices, itemQuantity);
|
|
75
|
+
});
|
|
76
|
+
const areModifiersOfMandatoryModifierGroupOutOfStock = getAreNotEnoughModifiersOfMandatoryModifierGroupInStock(modifierGroups);
|
|
77
|
+
const canAcceptOrders = oloSettingsService.canAcceptOrders ?? true;
|
|
78
|
+
const isValidToContinue = canAcceptOrders &&
|
|
79
|
+
config?.item?.orderSettings?.inStock &&
|
|
80
|
+
config.availabilityStatus === AvailabilityStatus.AVAILABLE &&
|
|
81
|
+
!areModifiersOfMandatoryModifierGroupOutOfStock;
|
|
82
|
+
const buttonState = signalsService.computed(() => {
|
|
83
|
+
return !config?.item?.orderSettings?.inStock ||
|
|
84
|
+
areModifiersOfMandatoryModifierGroupOutOfStock
|
|
85
|
+
? AddToCartButtonState.OUT_OF_STOCK
|
|
86
|
+
: availabilityStatus.get() !== AvailabilityStatus.AVAILABLE
|
|
87
|
+
? AddToCartButtonState.ITEM_UNAVAILABLE
|
|
88
|
+
: !canAcceptOrders
|
|
89
|
+
? AddToCartButtonState.NOT_VALID
|
|
90
|
+
: config.editItemMode
|
|
91
|
+
? AddToCartButtonState.EDITING
|
|
92
|
+
: isValidToContinue
|
|
93
|
+
? AddToCartButtonState.VALID_TO_CONTINUE
|
|
94
|
+
: AddToCartButtonState.NOT_VALID;
|
|
95
|
+
});
|
|
96
|
+
const addToCartButtonDisabled = signalsService.signal(!isValidToContinue);
|
|
97
|
+
const lineItem = signalsService.computed(() => {
|
|
98
|
+
const formatCurrency = oloSettingsService.formatCurrency;
|
|
99
|
+
return {
|
|
70
100
|
quantity: quantity.get(),
|
|
71
101
|
catalogReference: {
|
|
72
|
-
|
|
73
|
-
catalogItemId: config.item._id,
|
|
102
|
+
catalogItemId: config.item?._id ?? undefined,
|
|
74
103
|
appId: APP_ID,
|
|
75
104
|
options: {
|
|
76
105
|
operationId: config.operationId,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
menuId: config.menuId,
|
|
107
|
+
sectionId: config.sectionId,
|
|
108
|
+
priceVariant: getPriceVariantOptions(selectedVariant.get(), formatCurrency),
|
|
109
|
+
modifierGroups: getLineItemModifiers(selectedModifiers.get(), modifierGroups, formatCurrency),
|
|
110
|
+
specialRequests: specialRequest.get(),
|
|
81
111
|
},
|
|
82
112
|
},
|
|
83
|
-
}
|
|
84
|
-
}
|
|
113
|
+
};
|
|
114
|
+
});
|
|
85
115
|
const updateQuantity = (_quantity) => {
|
|
86
116
|
quantity.set(_quantity);
|
|
87
|
-
const _lineItem = lineItem.get();
|
|
88
|
-
lineItem.set({
|
|
89
|
-
..._lineItem,
|
|
90
|
-
quantity: _quantity,
|
|
91
|
-
});
|
|
92
117
|
};
|
|
93
118
|
const updateSpecialRequest = (_specialRequest) => {
|
|
94
119
|
specialRequest.set(_specialRequest);
|
|
95
|
-
const _lineItem = lineItem.get();
|
|
96
|
-
lineItem.set({
|
|
97
|
-
..._lineItem,
|
|
98
|
-
catalogReference: {
|
|
99
|
-
..._lineItem.catalogReference,
|
|
100
|
-
options: {
|
|
101
|
-
..._lineItem.catalogReference?.options,
|
|
102
|
-
specialRequest: _specialRequest,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
120
|
};
|
|
107
121
|
const updateSelectedVariant = (variant) => {
|
|
108
122
|
selectedVariant.set(variant);
|
|
@@ -157,6 +171,9 @@ export const ItemService = implementService.withConfig()(ItemServiceDefinition,
|
|
|
157
171
|
availabilityStatus,
|
|
158
172
|
getSelectedModifiers,
|
|
159
173
|
modifierGroupError,
|
|
174
|
+
buttonState,
|
|
175
|
+
addToCartButtonDisabled,
|
|
176
|
+
price,
|
|
160
177
|
};
|
|
161
178
|
});
|
|
162
179
|
/**
|
|
@@ -11,12 +11,16 @@ export interface OLOSettingsServiceAPI {
|
|
|
11
11
|
currentFulfillment: Signal<string>;
|
|
12
12
|
currentTimeSlot: Signal<string>;
|
|
13
13
|
filterMenus: (menus: MenusServiceConfig['menus']) => MenusServiceConfig['menus'];
|
|
14
|
+
canAcceptOrders: boolean;
|
|
15
|
+
formatCurrency: (price?: number) => string;
|
|
14
16
|
}
|
|
15
17
|
export interface OLOSettingsServiceConfig {
|
|
16
18
|
operationGroup?: operationGroupsSDK.OperationGroup;
|
|
17
19
|
operation?: operationsSDK.Operation;
|
|
18
20
|
availabilityDispatchAction?: () => void;
|
|
19
21
|
menuIdsByOperation?: string[];
|
|
22
|
+
canAcceptOrders?: boolean;
|
|
23
|
+
formattedPrice?: (price?: number) => string;
|
|
20
24
|
}
|
|
21
25
|
export declare const OLOSettingsServiceDefinition: string & {
|
|
22
26
|
__api: OLOSettingsServiceAPI;
|
|
@@ -8,6 +8,8 @@ export const OLOSettingsService = implementService.withConfig()(OLOSettingsServi
|
|
|
8
8
|
const availabilityDispatchAction = signalsService.signal(config.availabilityDispatchAction);
|
|
9
9
|
const operationGroup = signalsService.signal(config.operationGroup);
|
|
10
10
|
const operation = signalsService.signal(config.operation);
|
|
11
|
+
const formatCurrency = config.formattedPrice ??
|
|
12
|
+
((price) => price?.toFixed(2)?.toString() ?? '');
|
|
11
13
|
const selectedItem = signalsService.signal(null);
|
|
12
14
|
const isLoading = signalsService.signal(false);
|
|
13
15
|
const error = signalsService.signal(null);
|
|
@@ -27,6 +29,8 @@ export const OLOSettingsService = implementService.withConfig()(OLOSettingsServi
|
|
|
27
29
|
currentFulfillment,
|
|
28
30
|
currentTimeSlot,
|
|
29
31
|
filterMenus,
|
|
32
|
+
canAcceptOrders: config.canAcceptOrders ?? true,
|
|
33
|
+
formatCurrency,
|
|
30
34
|
};
|
|
31
35
|
});
|
|
32
36
|
export async function loadOLOSettingsServiceConfig() {
|
package/dist/services/utils.d.ts
CHANGED
|
@@ -34,4 +34,32 @@ export declare const hasToChooseAtLeastX: ({ required, minSelections, maxSelecti
|
|
|
34
34
|
export declare const chooseUpToX: ({ required, minSelections, maxSelections, }: ruleUtilsArgs) => boolean;
|
|
35
35
|
export declare const hasToChooseBetweenXAndY: ({ required, minSelections, maxSelections, }: ruleUtilsArgs) => boolean;
|
|
36
36
|
export declare const getRuleTypeMapValue: (ruleTypeMap: RuleTypeMap, ruleType: RuleType, modifierGroupName: string, rule: EnhancedModifierGroup["rule"]) => string | undefined;
|
|
37
|
+
export declare const getAreNotEnoughModifiersOfMandatoryModifierGroupInStock: (modifierGroups: EnhancedModifierGroup[]) => boolean;
|
|
38
|
+
export declare const getLineItemModifiers: (selectedModifiers: Record<string, Array<string>>, modifierGroups: EnhancedModifierGroup[], formatCurrency: (price?: number) => string) => {
|
|
39
|
+
id: string;
|
|
40
|
+
modifiers: {
|
|
41
|
+
id: string;
|
|
42
|
+
price: string | undefined;
|
|
43
|
+
formattedPrice: string | undefined;
|
|
44
|
+
}[];
|
|
45
|
+
}[] | undefined;
|
|
46
|
+
export declare const getPriceVariantOptions: (selectedPriceVariant: {
|
|
47
|
+
_id?: string | null;
|
|
48
|
+
priceInfo?: {
|
|
49
|
+
price?: string;
|
|
50
|
+
};
|
|
51
|
+
} | undefined, formatCurrency: (price?: number) => string) => {
|
|
52
|
+
id: string;
|
|
53
|
+
formattedPrice: string;
|
|
54
|
+
} | undefined;
|
|
55
|
+
export declare const getSelectedModifierPrices: (selectedModifiers: Record<string, Array<string>>, modifierGroups: EnhancedModifierGroup[]) => number;
|
|
56
|
+
export declare const getSelectedVariantPrice: (selectedVariant: {
|
|
57
|
+
_id?: string | null;
|
|
58
|
+
} | undefined, priceVariants: Array<{
|
|
59
|
+
_id?: string | null;
|
|
60
|
+
priceInfo?: {
|
|
61
|
+
price?: string;
|
|
62
|
+
};
|
|
63
|
+
}>) => number;
|
|
64
|
+
export declare const calculateItemPrice: (basePrice: number, variantPrice: number, modifierPrices: number, quantity: number) => number;
|
|
37
65
|
export {};
|
package/dist/services/utils.js
CHANGED
|
@@ -136,3 +136,79 @@ export const getRuleTypeMapValue = (ruleTypeMap, ruleType, modifierGroupName, ru
|
|
|
136
136
|
}
|
|
137
137
|
return undefined;
|
|
138
138
|
};
|
|
139
|
+
export const getAreNotEnoughModifiersOfMandatoryModifierGroupInStock = (modifierGroups) => modifierGroups.some((modifierGroup) => {
|
|
140
|
+
const isModifierGroupMandatory = modifierGroup.rule?.required;
|
|
141
|
+
const minimumRequiredModifiers = modifierGroup.rule?.minSelections ?? 0;
|
|
142
|
+
const inStockModifiers = modifierGroup.modifiers.filter((modifier) => modifier.inStock ?? true);
|
|
143
|
+
const areMinimumRequiredModifiersInStock = inStockModifiers.length >= minimumRequiredModifiers;
|
|
144
|
+
return isModifierGroupMandatory && !areMinimumRequiredModifiersInStock;
|
|
145
|
+
});
|
|
146
|
+
export const getLineItemModifiers = (selectedModifiers, modifierGroups, formatCurrency) => {
|
|
147
|
+
const modifierGroupsOptions = modifierGroups
|
|
148
|
+
.map((modifierGroup) => {
|
|
149
|
+
const selectedModifierIds = selectedModifiers[modifierGroup._id ?? ''];
|
|
150
|
+
if (!selectedModifierIds || selectedModifierIds.length === 0) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const modifiers = selectedModifierIds
|
|
154
|
+
.map((modifierIdWithIndex) => {
|
|
155
|
+
const baseModifierId = modifierIdWithIndex.split('~')[0];
|
|
156
|
+
const modifier = modifierGroup.modifiers.find((mod) => mod._id === baseModifierId);
|
|
157
|
+
if (!modifier)
|
|
158
|
+
return null;
|
|
159
|
+
const price = Number(modifier?.additionalChargeInfo?.additionalCharge ?? 0);
|
|
160
|
+
return {
|
|
161
|
+
id: modifier._id ?? '',
|
|
162
|
+
price: modifier?.additionalChargeInfo?.additionalCharge,
|
|
163
|
+
formattedPrice: price > 0 ? formatCurrency(price) : undefined,
|
|
164
|
+
};
|
|
165
|
+
})
|
|
166
|
+
.filter((modifier) => modifier !== null);
|
|
167
|
+
if (modifiers.length === 0 || !modifierGroup._id) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
id: modifierGroup._id,
|
|
172
|
+
modifiers,
|
|
173
|
+
};
|
|
174
|
+
})
|
|
175
|
+
.filter((modifierGroup) => modifierGroup !== null &&
|
|
176
|
+
modifierGroup.modifiers.length > 0 &&
|
|
177
|
+
!!modifierGroup?.id?.length);
|
|
178
|
+
return modifierGroupsOptions.length > 0 ? modifierGroupsOptions : undefined;
|
|
179
|
+
};
|
|
180
|
+
export const getPriceVariantOptions = (selectedPriceVariant, formatCurrency) => {
|
|
181
|
+
const variantId = selectedPriceVariant?._id;
|
|
182
|
+
const variantPrice = selectedPriceVariant?.priceInfo?.price;
|
|
183
|
+
if (!variantId) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
const price = variantPrice ? Number(variantPrice) : undefined;
|
|
187
|
+
return {
|
|
188
|
+
id: variantId,
|
|
189
|
+
formattedPrice: formatCurrency(price),
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
export const getSelectedModifierPrices = (selectedModifiers, modifierGroups) => {
|
|
193
|
+
return Object.entries(selectedModifiers).reduce((total, [modifierGroupId, modifierIds]) => {
|
|
194
|
+
const groupTotal = modifierIds.reduce((groupSum, modifierId) => {
|
|
195
|
+
const baseModifierId = modifierId.split('~')[0];
|
|
196
|
+
const modifier = modifierGroups
|
|
197
|
+
.find((group) => group._id === modifierGroupId)
|
|
198
|
+
?.modifiers.find((mod) => mod._id === baseModifierId);
|
|
199
|
+
return (groupSum +
|
|
200
|
+
Number(modifier?.additionalChargeInfo?.additionalCharge ?? 0));
|
|
201
|
+
}, 0);
|
|
202
|
+
return total + groupTotal;
|
|
203
|
+
}, 0);
|
|
204
|
+
};
|
|
205
|
+
export const getSelectedVariantPrice = (selectedVariant, priceVariants) => {
|
|
206
|
+
if (!selectedVariant?._id) {
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
const variant = priceVariants.find((variant) => variant._id === selectedVariant._id);
|
|
210
|
+
return Number(variant?.priceInfo?.price ?? 0);
|
|
211
|
+
};
|
|
212
|
+
export const calculateItemPrice = (basePrice, variantPrice, modifierPrices, quantity) => {
|
|
213
|
+
return (basePrice + variantPrice + modifierPrices) * quantity;
|
|
214
|
+
};
|
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.20",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@radix-ui/react-slot": "^1.1.0",
|
|
57
57
|
"@wix/auto_sdk_restaurants_items": "^1.0.48",
|
|
58
58
|
"@wix/ecom": "^1.0.1461",
|
|
59
|
-
"@wix/headless-components": "0.0.
|
|
59
|
+
"@wix/headless-components": "0.0.29",
|
|
60
60
|
"@wix/headless-media": "0.0.17",
|
|
61
61
|
"@wix/headless-restaurants-menus": "0.0.20",
|
|
62
62
|
"@wix/headless-utils": "0.0.7",
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"groupId": "com.wixpress.headless-components"
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
|
-
"falconPackageHash": "
|
|
79
|
+
"falconPackageHash": "62b03d48ee9763fd64c2c4dd77886b6399b70c84d6cf03279404176c"
|
|
80
80
|
}
|