@wix/headless-bookings 0.0.10 → 0.0.12
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/api/index.d.ts +10 -1
- package/cjs/dist/api/index.js +10 -1
- package/cjs/dist/api/query-services/index.d.ts +78 -0
- package/cjs/dist/api/query-services/index.js +137 -0
- package/cjs/dist/react/core/booking/Booking.d.ts +5 -5
- package/cjs/dist/react/core/booking/Booking.js +5 -5
- package/cjs/dist/react/core/location/Location.d.ts +44 -0
- package/cjs/dist/react/core/location/Location.js +78 -0
- package/cjs/dist/react/core/service/Service.d.ts +160 -17
- package/cjs/dist/react/core/service/Service.js +211 -13
- package/cjs/dist/react/core/service-list/ServiceList.d.ts +75 -0
- package/cjs/dist/react/core/service-list/ServiceList.js +58 -0
- package/cjs/dist/react/index.d.ts +2 -0
- package/cjs/dist/react/index.js +2 -0
- package/cjs/dist/react/location/Location.d.ts +77 -0
- package/cjs/dist/react/location/Location.js +89 -0
- package/cjs/dist/react/service/Service.d.ts +1036 -31
- package/cjs/dist/react/service/Service.js +1060 -47
- package/cjs/dist/react/service-list/ServiceList.d.ts +185 -0
- package/cjs/dist/react/service-list/ServiceList.js +184 -0
- package/cjs/dist/services/booking/booking.d.ts +19 -11
- package/cjs/dist/services/booking/booking.js +48 -16
- package/cjs/dist/services/index.d.ts +3 -2
- package/cjs/dist/services/index.js +2 -1
- package/cjs/dist/services/service/service.d.ts +71 -18
- package/cjs/dist/services/service/service.js +186 -51
- package/cjs/dist/services/service-list/service-list.d.ts +157 -0
- package/cjs/dist/services/service-list/service-list.js +274 -0
- package/cjs/dist/utils/dateAndTime.d.ts +2 -0
- package/cjs/dist/utils/dateAndTime.js +18 -0
- package/cjs/dist/utils/money.d.ts +21 -0
- package/cjs/dist/utils/money.js +34 -0
- package/dist/api/index.d.ts +10 -1
- package/dist/api/index.js +10 -1
- package/dist/api/query-services/index.d.ts +78 -0
- package/dist/api/query-services/index.js +137 -0
- package/dist/react/core/booking/Booking.d.ts +5 -5
- package/dist/react/core/booking/Booking.js +5 -5
- package/dist/react/core/location/Location.d.ts +44 -0
- package/dist/react/core/location/Location.js +78 -0
- package/dist/react/core/service/Service.d.ts +160 -17
- package/dist/react/core/service/Service.js +211 -13
- package/dist/react/core/service-list/ServiceList.d.ts +75 -0
- package/dist/react/core/service-list/ServiceList.js +58 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +2 -0
- package/dist/react/location/Location.d.ts +77 -0
- package/dist/react/location/Location.js +89 -0
- package/dist/react/service/Service.d.ts +1036 -31
- package/dist/react/service/Service.js +1060 -47
- package/dist/react/service-list/ServiceList.d.ts +185 -0
- package/dist/react/service-list/ServiceList.js +184 -0
- package/dist/services/booking/booking.d.ts +19 -11
- package/dist/services/booking/booking.js +48 -16
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +2 -1
- package/dist/services/service/service.d.ts +71 -18
- package/dist/services/service/service.js +186 -51
- package/dist/services/service-list/service-list.d.ts +157 -0
- package/dist/services/service-list/service-list.js +274 -0
- package/dist/utils/dateAndTime.d.ts +2 -0
- package/dist/utils/dateAndTime.js +18 -0
- package/dist/utils/money.d.ts +21 -0
- package/dist/utils/money.js +34 -0
- package/package.json +2 -2
- package/cjs/dist/api/query-service/index.d.ts +0 -23
- package/cjs/dist/api/query-service/index.js +0 -41
- package/dist/api/query-service/index.d.ts +0 -23
- package/dist/api/query-service/index.js +0 -41
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceList - High-level component for displaying services list
|
|
3
|
+
* Provides components for displaying services list with pagination
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { ListVariant, GenericListLoadMoreRenderProps } from '@wix/headless-components/react';
|
|
7
|
+
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
|
+
import type { ServiceListServiceConfig } from '../../services/service-list/service-list.js';
|
|
9
|
+
import type { services } from '@wix/bookings';
|
|
10
|
+
/**
|
|
11
|
+
* Props for the ServiceList root component
|
|
12
|
+
*/
|
|
13
|
+
export interface ServiceListRootProps {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
serviceListConfig?: ServiceListServiceConfig;
|
|
16
|
+
className?: string;
|
|
17
|
+
variant?: ListVariant;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Root component that provides the ServiceList service context for rendering services lists.
|
|
21
|
+
*
|
|
22
|
+
* @order 1
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { ServiceList } from '@wix/bookings/components';
|
|
27
|
+
*
|
|
28
|
+
* function ServicesPage({ serviceListConfig }) {
|
|
29
|
+
* return (
|
|
30
|
+
* <ServiceList.Root serviceListConfig={serviceListConfig}>
|
|
31
|
+
* <ServiceList.Services emptyState={<div>No services available</div>}>
|
|
32
|
+
* <ServiceList.ServiceRepeater>
|
|
33
|
+
* <Service.Name />
|
|
34
|
+
* <Service.Price />
|
|
35
|
+
* </ServiceList.ServiceRepeater>
|
|
36
|
+
* </ServiceList.Services>
|
|
37
|
+
* </ServiceList.Root>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare const Root: React.ForwardRefExoticComponent<ServiceListRootProps & React.RefAttributes<HTMLElement>>;
|
|
43
|
+
/**
|
|
44
|
+
* Props for ServiceList Services component
|
|
45
|
+
*/
|
|
46
|
+
export interface ServicesProps {
|
|
47
|
+
children: React.ReactNode;
|
|
48
|
+
emptyState?: React.ReactNode;
|
|
49
|
+
infiniteScroll?: boolean;
|
|
50
|
+
pageSize?: number;
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Container for the services list with empty state support.
|
|
55
|
+
* Wraps GenericList.Items. Follows List Container Level pattern.
|
|
56
|
+
*
|
|
57
|
+
* @component
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* <ServiceList.Services emptyState={<div>No services found</div>}>
|
|
61
|
+
* <ServiceList.ServiceRepeater>
|
|
62
|
+
* <Service.Name />
|
|
63
|
+
* <Service.Price />
|
|
64
|
+
* </ServiceList.ServiceRepeater>
|
|
65
|
+
* </ServiceList.Services>
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare const Services: React.ForwardRefExoticComponent<ServicesProps & React.RefAttributes<HTMLElement>>;
|
|
69
|
+
/**
|
|
70
|
+
* Function children type for Service.Root component
|
|
71
|
+
* Receives { selected, bookable } props from Service.Root
|
|
72
|
+
*/
|
|
73
|
+
export type ServiceRootChildren = AsChildChildren<{
|
|
74
|
+
selected: boolean;
|
|
75
|
+
bookable: boolean;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* Props for the itemWrapper function in asChild pattern
|
|
79
|
+
* Supports both ReactNode and function children that receive { selected, bookable }
|
|
80
|
+
*/
|
|
81
|
+
export interface ServiceItemWrapperProps {
|
|
82
|
+
item: services.Service;
|
|
83
|
+
index?: number;
|
|
84
|
+
/** Children can be ReactNode or a function that receives { selected, bookable } from Service.Root */
|
|
85
|
+
children: React.ReactNode | ServiceRootChildren;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render props for ServiceRepeater asChild pattern
|
|
89
|
+
* Provides items array and itemWrapper function for custom rendering
|
|
90
|
+
*/
|
|
91
|
+
export interface ServiceRepeaterRenderProps {
|
|
92
|
+
items: services.Service[];
|
|
93
|
+
variant?: ListVariant;
|
|
94
|
+
/** Wraps each item in Service.Root - children can be ReactNode or function receiving { selected, bookable } */
|
|
95
|
+
itemWrapper: (props: ServiceItemWrapperProps) => React.ReactNode;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Props for ServiceList ServiceRepeater component
|
|
99
|
+
*/
|
|
100
|
+
export interface ServiceRepeaterProps {
|
|
101
|
+
/**
|
|
102
|
+
* Children can be:
|
|
103
|
+
* - ReactNode: Static content rendered for each service
|
|
104
|
+
* - ServiceRootChildren: Function receiving { selected, bookable } from Service.Root
|
|
105
|
+
* - Function (with asChild=true): Receives { items, itemWrapper } for custom rendering
|
|
106
|
+
*/
|
|
107
|
+
children: React.ReactNode | ((props: ServiceRepeaterRenderProps, ref?: React.Ref<HTMLElement>) => React.ReactNode) | ServiceRootChildren;
|
|
108
|
+
/** Whether to render as child component (asChild pattern) */
|
|
109
|
+
asChild?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Repeater component that renders Service.Root for each service.
|
|
113
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
114
|
+
* Supports asChild pattern for advanced layout components.
|
|
115
|
+
*
|
|
116
|
+
* @component
|
|
117
|
+
* @example
|
|
118
|
+
* ```tsx
|
|
119
|
+
* // Standard usage
|
|
120
|
+
* <ServiceList.ServiceRepeater>
|
|
121
|
+
* <Service.Name />
|
|
122
|
+
* <Service.Price />
|
|
123
|
+
* </ServiceList.ServiceRepeater>
|
|
124
|
+
*
|
|
125
|
+
* // AsChild usage with custom wrapper
|
|
126
|
+
* <ServiceList.ServiceRepeater asChild>
|
|
127
|
+
* {({ items, variant, itemWrapper }) => (
|
|
128
|
+
* <CustomWrapper
|
|
129
|
+
* items={items}
|
|
130
|
+
* variant={variant}
|
|
131
|
+
* itemRenderer={(item, index) =>
|
|
132
|
+
* itemWrapper({ item, index, children: <>
|
|
133
|
+
* <Service.Name />
|
|
134
|
+
* <Service.Price />
|
|
135
|
+
* </> })
|
|
136
|
+
* }
|
|
137
|
+
* />
|
|
138
|
+
* )}
|
|
139
|
+
* </ServiceList.ServiceRepeater>
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare const ServiceRepeater: React.ForwardRefExoticComponent<ServiceRepeaterProps & React.RefAttributes<HTMLElement>>;
|
|
143
|
+
/**
|
|
144
|
+
* Props for ServiceList LoadMore component
|
|
145
|
+
*/
|
|
146
|
+
export interface LoadMoreProps {
|
|
147
|
+
/** Custom render function when using asChild */
|
|
148
|
+
children?: React.ReactNode | React.ForwardRefRenderFunction<HTMLButtonElement, GenericListLoadMoreRenderProps>;
|
|
149
|
+
/**
|
|
150
|
+
* Whether to render as a child component.
|
|
151
|
+
* @default false
|
|
152
|
+
*/
|
|
153
|
+
asChild?: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* The CSS classes to apply to the button.
|
|
156
|
+
*/
|
|
157
|
+
className?: string;
|
|
158
|
+
/**
|
|
159
|
+
* The label to display inside the button.
|
|
160
|
+
*/
|
|
161
|
+
label?: string;
|
|
162
|
+
/**
|
|
163
|
+
* The loading state to display inside the button.
|
|
164
|
+
*/
|
|
165
|
+
loadingState?: React.ReactNode;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Displays a button to load more services. Not rendered if infiniteScroll is false or no services are left to load.
|
|
169
|
+
* Follows the architecture rules - does not support asChild as it's a simple trigger component.
|
|
170
|
+
*
|
|
171
|
+
* @component
|
|
172
|
+
* @example
|
|
173
|
+
* ```tsx
|
|
174
|
+
* <ServiceList.Actions.LoadMore asChild>
|
|
175
|
+
* <button>Load More</button>
|
|
176
|
+
* </ServiceList.Actions.LoadMore>
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export declare const LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & React.RefAttributes<HTMLButtonElement>>;
|
|
180
|
+
/**
|
|
181
|
+
* Actions namespace for ServiceList
|
|
182
|
+
*/
|
|
183
|
+
export declare const Actions: {
|
|
184
|
+
LoadMore: React.ForwardRefExoticComponent<LoadMoreProps & React.RefAttributes<HTMLButtonElement>>;
|
|
185
|
+
};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ServiceList - High-level component for displaying services list
|
|
4
|
+
* Provides components for displaying services list with pagination
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { GenericList, } from '@wix/headless-components/react';
|
|
8
|
+
import { useService } from '@wix/services-manager-react';
|
|
9
|
+
import { ServiceListServiceDefinition } from '../../services/service-list/service-list.js';
|
|
10
|
+
import * as CoreServiceList from '../core/service-list/ServiceList.js';
|
|
11
|
+
import * as Service from '../service/Service.js';
|
|
12
|
+
/**
|
|
13
|
+
* Booking app ID constant
|
|
14
|
+
*/
|
|
15
|
+
const BOOKING_APP_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
|
|
16
|
+
var TestIds;
|
|
17
|
+
(function (TestIds) {
|
|
18
|
+
TestIds["serviceListRoot"] = "service-list-root";
|
|
19
|
+
TestIds["serviceListServices"] = "service-list-services";
|
|
20
|
+
TestIds["serviceListService"] = "service-list-service";
|
|
21
|
+
TestIds["serviceListLoadMore"] = "service-list-load-more";
|
|
22
|
+
})(TestIds || (TestIds = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Root component that provides the ServiceList service context for rendering services lists.
|
|
25
|
+
*
|
|
26
|
+
* @order 1
|
|
27
|
+
* @component
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import { ServiceList } from '@wix/bookings/components';
|
|
31
|
+
*
|
|
32
|
+
* function ServicesPage({ serviceListConfig }) {
|
|
33
|
+
* return (
|
|
34
|
+
* <ServiceList.Root serviceListConfig={serviceListConfig}>
|
|
35
|
+
* <ServiceList.Services emptyState={<div>No services available</div>}>
|
|
36
|
+
* <ServiceList.ServiceRepeater>
|
|
37
|
+
* <Service.Name />
|
|
38
|
+
* <Service.Price />
|
|
39
|
+
* </ServiceList.ServiceRepeater>
|
|
40
|
+
* </ServiceList.Services>
|
|
41
|
+
* </ServiceList.Root>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const Root = React.forwardRef((props, ref) => {
|
|
47
|
+
const { children, serviceListConfig, className, variant } = props;
|
|
48
|
+
const serviceConfig = serviceListConfig || {
|
|
49
|
+
services: [],
|
|
50
|
+
options: {
|
|
51
|
+
appId: BOOKING_APP_ID,
|
|
52
|
+
pagingMetadata: {
|
|
53
|
+
limit: 0,
|
|
54
|
+
offset: 0,
|
|
55
|
+
hasNext: false,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
return (_jsx(CoreServiceList.Root, { serviceListConfig: serviceConfig, children: _jsx(RootContent, { className: className, ref: ref, variant: variant, children: children }) }));
|
|
60
|
+
});
|
|
61
|
+
Root.displayName = 'ServiceList.Root';
|
|
62
|
+
/**
|
|
63
|
+
* Internal component to handle the Root content with service access
|
|
64
|
+
*/
|
|
65
|
+
const RootContent = React.forwardRef((props, ref) => {
|
|
66
|
+
const { children, className, variant } = props;
|
|
67
|
+
const serviceListService = useService(ServiceListServiceDefinition);
|
|
68
|
+
const items = serviceListService.servicesSignal
|
|
69
|
+
.get()
|
|
70
|
+
.map((service) => ({
|
|
71
|
+
...service,
|
|
72
|
+
id: service._id,
|
|
73
|
+
}));
|
|
74
|
+
return (_jsx(GenericList.Root, { items: items, loadMore: () => serviceListService.actions.loadMore(10), hasMore: serviceListService.hasMoreServicesSignal.get(), isLoading: serviceListService.isLoadingSignal.get(), className: className, ref: ref, "data-testid": TestIds.serviceListRoot, variant: variant, children: children }));
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Container for the services list with empty state support.
|
|
78
|
+
* Wraps GenericList.Items. Follows List Container Level pattern.
|
|
79
|
+
*
|
|
80
|
+
* @component
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* <ServiceList.Services emptyState={<div>No services found</div>}>
|
|
84
|
+
* <ServiceList.ServiceRepeater>
|
|
85
|
+
* <Service.Name />
|
|
86
|
+
* <Service.Price />
|
|
87
|
+
* </ServiceList.ServiceRepeater>
|
|
88
|
+
* </ServiceList.Services>
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export const Services = React.forwardRef((props, ref) => {
|
|
92
|
+
const { children, ...otherProps } = props;
|
|
93
|
+
return (_jsx(GenericList.Items, { ref: ref, "data-testid": TestIds.serviceListServices, ...otherProps, children: children }));
|
|
94
|
+
});
|
|
95
|
+
Services.displayName = 'ServiceList.Services';
|
|
96
|
+
/**
|
|
97
|
+
* Repeater component that renders Service.Root for each service.
|
|
98
|
+
* Follows Repeater Level pattern and uses GenericList.Repeater for consistency.
|
|
99
|
+
* Supports asChild pattern for advanced layout components.
|
|
100
|
+
*
|
|
101
|
+
* @component
|
|
102
|
+
* @example
|
|
103
|
+
* ```tsx
|
|
104
|
+
* // Standard usage
|
|
105
|
+
* <ServiceList.ServiceRepeater>
|
|
106
|
+
* <Service.Name />
|
|
107
|
+
* <Service.Price />
|
|
108
|
+
* </ServiceList.ServiceRepeater>
|
|
109
|
+
*
|
|
110
|
+
* // AsChild usage with custom wrapper
|
|
111
|
+
* <ServiceList.ServiceRepeater asChild>
|
|
112
|
+
* {({ items, variant, itemWrapper }) => (
|
|
113
|
+
* <CustomWrapper
|
|
114
|
+
* items={items}
|
|
115
|
+
* variant={variant}
|
|
116
|
+
* itemRenderer={(item, index) =>
|
|
117
|
+
* itemWrapper({ item, index, children: <>
|
|
118
|
+
* <Service.Name />
|
|
119
|
+
* <Service.Price />
|
|
120
|
+
* </> })
|
|
121
|
+
* }
|
|
122
|
+
* />
|
|
123
|
+
* )}
|
|
124
|
+
* </ServiceList.ServiceRepeater>
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export const ServiceRepeater = React.forwardRef((props, ref) => {
|
|
128
|
+
const { children, asChild } = props;
|
|
129
|
+
const serviceListService = useService(ServiceListServiceDefinition);
|
|
130
|
+
const appId = serviceListService.queryOptionsSignal.get().appId;
|
|
131
|
+
// Check if children is a function that matches ServiceRootChildren pattern
|
|
132
|
+
// (function with single parameter that receives { selected, bookable })
|
|
133
|
+
const isServiceRootFunction = typeof children === 'function' && children.length === 1 && !asChild;
|
|
134
|
+
// Custom itemWrapper that matches ItemWrapperProps signature
|
|
135
|
+
const serviceItemWrapper = (wrapperProps) => {
|
|
136
|
+
const { item: service, children: itemChildren } = wrapperProps;
|
|
137
|
+
return (_jsx(Service.Root, { service: service, appId: appId, "data-testid": TestIds.serviceListService, "data-service-id": service._id, "data-item-id": service._id, children: isServiceRootFunction
|
|
138
|
+
? children
|
|
139
|
+
: itemChildren }, service._id));
|
|
140
|
+
};
|
|
141
|
+
// Transform children for asChild pattern to provide custom render props
|
|
142
|
+
const transformedChildren = asChild && typeof children === 'function'
|
|
143
|
+
? (genericProps) => {
|
|
144
|
+
// Create properly typed render props for the consumer
|
|
145
|
+
const renderProps = {
|
|
146
|
+
items: genericProps.items,
|
|
147
|
+
variant: genericProps.variant,
|
|
148
|
+
itemWrapper: (props) => serviceItemWrapper({
|
|
149
|
+
item: props.item,
|
|
150
|
+
index: props.index ?? 0,
|
|
151
|
+
children: props.children,
|
|
152
|
+
}),
|
|
153
|
+
};
|
|
154
|
+
return children(renderProps, ref);
|
|
155
|
+
}
|
|
156
|
+
: isServiceRootFunction
|
|
157
|
+
? undefined
|
|
158
|
+
: children;
|
|
159
|
+
return (_jsx(GenericList.Repeater, { ref: ref, asChild: asChild, itemWrapper: serviceItemWrapper, children: transformedChildren }));
|
|
160
|
+
});
|
|
161
|
+
ServiceRepeater.displayName = 'ServiceList.ServiceRepeater';
|
|
162
|
+
/**
|
|
163
|
+
* Displays a button to load more services. Not rendered if infiniteScroll is false or no services are left to load.
|
|
164
|
+
* Follows the architecture rules - does not support asChild as it's a simple trigger component.
|
|
165
|
+
*
|
|
166
|
+
* @component
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* <ServiceList.Actions.LoadMore asChild>
|
|
170
|
+
* <button>Load More</button>
|
|
171
|
+
* </ServiceList.Actions.LoadMore>
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export const LoadMore = React.forwardRef((props, ref) => {
|
|
175
|
+
const { children = _jsx("button", {}), ...otherProps } = props;
|
|
176
|
+
return (_jsx(GenericList.Actions.LoadMore, { ref: ref, "data-testid": TestIds.serviceListLoadMore, ...otherProps, children: children }));
|
|
177
|
+
});
|
|
178
|
+
LoadMore.displayName = 'ServiceList.Actions.LoadMore';
|
|
179
|
+
/**
|
|
180
|
+
* Actions namespace for ServiceList
|
|
181
|
+
*/
|
|
182
|
+
export const Actions = {
|
|
183
|
+
LoadMore,
|
|
184
|
+
};
|
|
@@ -7,12 +7,16 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
|
7
7
|
import type { services, availabilityTimeSlots } from '@wix/bookings';
|
|
8
8
|
import type { FormValues } from '@wix/form-public';
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* BookingSelection contains the service AND its related selections
|
|
11
11
|
*/
|
|
12
|
-
export interface
|
|
12
|
+
export interface BookingSelection {
|
|
13
|
+
/** Unique identifier for this booking instance (allows same service multiple times) */
|
|
14
|
+
instanceId: string;
|
|
13
15
|
service: services.Service;
|
|
14
16
|
/** Selected resources (staff members, rooms, etc.) */
|
|
15
|
-
|
|
17
|
+
staff?: availabilityTimeSlots.Resource;
|
|
18
|
+
/** Per-service slot data from nested slots (for multi-service bookings) */
|
|
19
|
+
nestedSlotData?: availabilityTimeSlots.NestedTimeSlot;
|
|
16
20
|
}
|
|
17
21
|
export interface Location {
|
|
18
22
|
id: string;
|
|
@@ -22,10 +26,14 @@ export interface Location {
|
|
|
22
26
|
* BookingService actions - setters only, no API calls
|
|
23
27
|
*/
|
|
24
28
|
export interface BookingServiceActions {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
/** Clears all booking selections and sets a single service (instanceId is auto-generated) */
|
|
30
|
+
setService(service: Omit<BookingSelection, 'instanceId'>): string;
|
|
31
|
+
/** Adds a service and returns the generated instanceId */
|
|
32
|
+
addService(service: Omit<BookingSelection, 'instanceId'>): string;
|
|
33
|
+
/** Updates a booking selection by instanceId */
|
|
34
|
+
updateServiceByInstanceId(instanceId: string, updates: Partial<Omit<BookingSelection, 'instanceId'>>): void;
|
|
35
|
+
/** Removes a service selection by instanceId. If no instanceId provided, removes the first service. */
|
|
36
|
+
removeServiceByInstanceId(instanceId?: string): void;
|
|
29
37
|
clearServices(): void;
|
|
30
38
|
setTimeSlot(slot: availabilityTimeSlots.TimeSlot | null): void;
|
|
31
39
|
clearTimeSlot(): void;
|
|
@@ -40,8 +48,8 @@ export interface BookingServiceActions {
|
|
|
40
48
|
* Pure state management - no API calls
|
|
41
49
|
*/
|
|
42
50
|
export interface BookingService {
|
|
43
|
-
/** Signal containing the
|
|
44
|
-
|
|
51
|
+
/** Signal containing the booking selections (services with their related data) */
|
|
52
|
+
bookingSelections: Signal<BookingSelection[]>;
|
|
45
53
|
/** Signal containing the currently selected time slot */
|
|
46
54
|
timeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
|
|
47
55
|
/** Signal containing the selected location (derived from timeSlot) */
|
|
@@ -64,8 +72,8 @@ export declare const BookingServiceDefinition: string & {
|
|
|
64
72
|
* Note: location is NOT in config - it's derived internally from timeSlot
|
|
65
73
|
*/
|
|
66
74
|
export interface BookingServiceConfig {
|
|
67
|
-
/** Optional initial
|
|
68
|
-
|
|
75
|
+
/** Optional initial booking selections to pre-populate */
|
|
76
|
+
initialBookingSelections?: BookingSelection[];
|
|
69
77
|
/** Optional initial time slot to pre-populate */
|
|
70
78
|
initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
|
|
71
79
|
/** Optional initial form values */
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
7
7
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Types
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Generates a unique instance ID for service selections
|
|
13
|
+
*/
|
|
14
|
+
function generateInstanceId() {
|
|
15
|
+
return crypto.randomUUID();
|
|
16
|
+
}
|
|
8
17
|
/**
|
|
9
18
|
* Service definition for Booking
|
|
10
19
|
*/
|
|
@@ -39,7 +48,12 @@ export const BookingServiceDefinition = defineService('booking');
|
|
|
39
48
|
export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
|
|
40
49
|
const signalsService = getService(SignalsServiceDefinition);
|
|
41
50
|
// Initialize signals with config values
|
|
42
|
-
|
|
51
|
+
// Ensure all initial booking selections have instanceIds
|
|
52
|
+
const initialSelectionsWithIds = (config.initialBookingSelections || []).map((s) => ({
|
|
53
|
+
...s,
|
|
54
|
+
instanceId: s.instanceId || generateInstanceId(),
|
|
55
|
+
}));
|
|
56
|
+
const bookingSelectionsSignal = signalsService.signal(initialSelectionsWithIds);
|
|
43
57
|
const timeSlotSignal = signalsService.signal(config.initialTimeSlot || null);
|
|
44
58
|
// Location is derived internally - initialize as null
|
|
45
59
|
const locationSignal = signalsService.signal(null);
|
|
@@ -49,25 +63,43 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
49
63
|
// ========================================================================
|
|
50
64
|
const actions = {
|
|
51
65
|
// Services actions
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
setService(service) {
|
|
67
|
+
const instanceId = generateInstanceId();
|
|
68
|
+
const newSelection = {
|
|
69
|
+
...service,
|
|
70
|
+
instanceId,
|
|
71
|
+
};
|
|
72
|
+
bookingSelectionsSignal.set([newSelection]);
|
|
73
|
+
return instanceId;
|
|
54
74
|
},
|
|
55
75
|
addService(service) {
|
|
56
|
-
const
|
|
57
|
-
|
|
76
|
+
const instanceId = generateInstanceId();
|
|
77
|
+
const current = bookingSelectionsSignal.get();
|
|
78
|
+
const newSelection = {
|
|
79
|
+
...service,
|
|
80
|
+
instanceId,
|
|
81
|
+
};
|
|
82
|
+
bookingSelectionsSignal.set([...current, newSelection]);
|
|
83
|
+
return instanceId;
|
|
58
84
|
},
|
|
59
|
-
|
|
60
|
-
const current =
|
|
61
|
-
const updated = current.map((s) => s.
|
|
62
|
-
|
|
85
|
+
updateServiceByInstanceId(instanceId, updates) {
|
|
86
|
+
const current = bookingSelectionsSignal.get();
|
|
87
|
+
const updated = current.map((s) => s.instanceId === instanceId ? { ...s, ...updates } : s);
|
|
88
|
+
bookingSelectionsSignal.set(updated);
|
|
63
89
|
},
|
|
64
|
-
|
|
65
|
-
const current =
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
removeServiceByInstanceId(instanceId) {
|
|
91
|
+
const current = bookingSelectionsSignal.get();
|
|
92
|
+
if (!instanceId) {
|
|
93
|
+
// Remove first selection if no instanceId provided
|
|
94
|
+
bookingSelectionsSignal.set(current.slice(1));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const filtered = current.filter((s) => s.instanceId !== instanceId);
|
|
98
|
+
bookingSelectionsSignal.set(filtered);
|
|
99
|
+
}
|
|
68
100
|
},
|
|
69
101
|
clearServices() {
|
|
70
|
-
|
|
102
|
+
bookingSelectionsSignal.set([]);
|
|
71
103
|
},
|
|
72
104
|
// Time Slot actions
|
|
73
105
|
setTimeSlot(slot) {
|
|
@@ -92,14 +124,14 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
|
|
|
92
124
|
},
|
|
93
125
|
// Clear all
|
|
94
126
|
clearAll() {
|
|
95
|
-
|
|
127
|
+
bookingSelectionsSignal.set([]);
|
|
96
128
|
timeSlotSignal.set(null);
|
|
97
129
|
locationSignal.set(null);
|
|
98
130
|
formValuesSignal.set(null);
|
|
99
131
|
},
|
|
100
132
|
};
|
|
101
133
|
return {
|
|
102
|
-
|
|
134
|
+
bookingSelections: bookingSelectionsSignal,
|
|
103
135
|
timeSlot: timeSlotSignal,
|
|
104
136
|
location: locationSignal,
|
|
105
137
|
formValues: formValuesSignal,
|
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
* Bookings Services
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
|
-
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig,
|
|
6
|
-
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type
|
|
5
|
+
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, type ServiceActions, type ServicePaymentData, loadServiceServiceInitialData, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
|
+
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
|
|
7
|
+
export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
|
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
* Bookings Services
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
|
-
export { ServiceService, ServiceServiceDefinition,
|
|
5
|
+
export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData, } from './service/service.js';
|
|
6
6
|
export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
|
|
7
|
+
export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
|