@wix/headless-bookings 0.0.7 → 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/api/index.d.ts +5 -0
- package/cjs/dist/api/index.js +5 -0
- package/cjs/dist/api/query-service/index.d.ts +23 -0
- package/cjs/dist/api/query-service/index.js +41 -0
- package/cjs/dist/react/booking/Booking.d.ts +35 -0
- package/cjs/dist/react/booking/Booking.js +25 -0
- package/cjs/dist/react/core/booking/Booking.d.ts +58 -0
- package/cjs/dist/react/core/booking/Booking.js +50 -0
- package/cjs/dist/react/core/service/Service.d.ts +106 -0
- package/cjs/dist/react/core/service/Service.js +90 -0
- package/cjs/dist/react/index.d.ts +2 -4
- package/cjs/dist/react/index.js +2 -5
- package/cjs/dist/react/service/Service.d.ts +208 -0
- package/cjs/dist/react/service/Service.js +202 -0
- package/cjs/dist/services/booking/booking.d.ts +85 -0
- package/cjs/dist/services/booking/booking.js +74 -0
- package/cjs/dist/services/index.d.ts +6 -1
- package/cjs/dist/services/index.js +6 -1
- package/cjs/dist/services/{service-service.d.ts → service/service.d.ts} +27 -42
- package/cjs/dist/services/{service-service.js → service/service.js} +49 -48
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.js +5 -0
- package/dist/api/query-service/index.d.ts +23 -0
- package/dist/api/query-service/index.js +41 -0
- package/dist/react/booking/Booking.d.ts +35 -0
- package/dist/react/booking/Booking.js +25 -0
- package/dist/react/core/booking/Booking.d.ts +58 -0
- package/dist/react/core/booking/Booking.js +50 -0
- package/dist/react/core/service/Service.d.ts +106 -0
- package/dist/react/core/service/Service.js +90 -0
- package/dist/react/index.d.ts +2 -4
- package/dist/react/index.js +2 -5
- package/dist/react/service/Service.d.ts +208 -0
- package/dist/react/service/Service.js +202 -0
- package/dist/services/booking/booking.d.ts +85 -0
- package/dist/services/booking/booking.js +74 -0
- package/dist/services/index.d.ts +6 -1
- package/dist/services/index.js +6 -1
- package/dist/services/{service-service.d.ts → service/service.d.ts} +27 -42
- package/dist/services/{service-service.js → service/service.js} +49 -48
- package/package.json +5 -4
- package/cjs/dist/react/ServiceList.d.ts +0 -50
- package/cjs/dist/react/ServiceList.js +0 -100
- package/cjs/dist/react/ServiceListSort.d.ts +0 -37
- package/cjs/dist/react/ServiceListSort.js +0 -35
- package/cjs/dist/react/core/Service.d.ts +0 -91
- package/cjs/dist/react/core/Service.js +0 -73
- package/cjs/dist/react/core/ServiceList.d.ts +0 -218
- package/cjs/dist/react/core/ServiceList.js +0 -199
- package/cjs/dist/react/test-ids.d.ts +0 -18
- package/cjs/dist/react/test-ids.js +0 -24
- package/cjs/dist/react/types.d.ts +0 -52
- package/cjs/dist/react/types.js +0 -1
- package/cjs/dist/services/services-list-service.d.ts +0 -184
- package/cjs/dist/services/services-list-service.js +0 -168
- package/dist/react/ServiceList.d.ts +0 -50
- package/dist/react/ServiceList.js +0 -100
- package/dist/react/ServiceListSort.d.ts +0 -37
- package/dist/react/ServiceListSort.js +0 -35
- package/dist/react/core/Service.d.ts +0 -91
- package/dist/react/core/Service.js +0 -73
- package/dist/react/core/ServiceList.d.ts +0 -218
- package/dist/react/core/ServiceList.js +0 -199
- package/dist/react/test-ids.d.ts +0 -18
- package/dist/react/test-ids.js +0 -24
- package/dist/react/types.d.ts +0 -52
- package/dist/react/types.js +0 -1
- package/dist/services/services-list-service.d.ts +0 -184
- package/dist/services/services-list-service.js +0 -168
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Service - High-level component for displaying service information
|
|
4
|
+
* Provides components for displaying service details and booking actions
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import * as CoreService from '../core/service/Service.js';
|
|
8
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
9
|
+
var TestIds;
|
|
10
|
+
(function (TestIds) {
|
|
11
|
+
TestIds["serviceRoot"] = "service-root";
|
|
12
|
+
TestIds["serviceName"] = "service-name";
|
|
13
|
+
TestIds["serviceDescription"] = "service-description";
|
|
14
|
+
TestIds["serviceActionSelect"] = "service-action-select";
|
|
15
|
+
TestIds["serviceActionAdd"] = "service-action-add";
|
|
16
|
+
TestIds["serviceActionRemove"] = "service-action-remove";
|
|
17
|
+
})(TestIds || (TestIds = {}));
|
|
18
|
+
/**
|
|
19
|
+
* Root component that provides service context to the entire app.
|
|
20
|
+
*
|
|
21
|
+
* @order 1
|
|
22
|
+
* @component
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { Service } from '@wix/bookings/components';
|
|
26
|
+
*
|
|
27
|
+
* function ServicePage({ service }) {
|
|
28
|
+
* return (
|
|
29
|
+
* <Service.Root service={service}>
|
|
30
|
+
* <Service.Name />
|
|
31
|
+
* <Service.Description />
|
|
32
|
+
* </Service.Root>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const Root = React.forwardRef((props, ref) => {
|
|
38
|
+
const { children, service, asChild, className, ...attrs } = props;
|
|
39
|
+
return (_jsx(CoreService.Root, { serviceServiceConfig: { service }, children: _jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceRoot, customElement: children, ...attrs, children: _jsx("div", { children: children }) }) }));
|
|
40
|
+
});
|
|
41
|
+
Root.displayName = 'Service.Root';
|
|
42
|
+
/**
|
|
43
|
+
* Displays the service name with customizable rendering.
|
|
44
|
+
*
|
|
45
|
+
* @component
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* // Default usage
|
|
49
|
+
* <Service.Name className="text-4xl font-bold" />
|
|
50
|
+
*
|
|
51
|
+
* // asChild with primitive
|
|
52
|
+
* <Service.Name asChild>
|
|
53
|
+
* <h1 className="text-4xl font-bold" />
|
|
54
|
+
* </Service.Name>
|
|
55
|
+
*
|
|
56
|
+
* // asChild with custom component
|
|
57
|
+
* <Service.Name asChild>
|
|
58
|
+
* {React.forwardRef(({name, ...props}, ref) => (
|
|
59
|
+
* <h1 ref={ref} {...props} className="text-4xl font-bold">
|
|
60
|
+
* {name}
|
|
61
|
+
* </h1>
|
|
62
|
+
* ))}
|
|
63
|
+
* </Service.Name>
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export const Name = React.forwardRef((props, ref) => {
|
|
67
|
+
const { asChild, children, className } = props;
|
|
68
|
+
return (_jsx(CoreService.Info, { children: ({ name }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceName, customElement: children, customElementProps: { name }, children: _jsx("span", { children: name }) })) }));
|
|
69
|
+
});
|
|
70
|
+
Name.displayName = 'Service.Name';
|
|
71
|
+
/**
|
|
72
|
+
* Displays the service description with customizable rendering.
|
|
73
|
+
*
|
|
74
|
+
* @component
|
|
75
|
+
* @example
|
|
76
|
+
* ```tsx
|
|
77
|
+
* // Default usage
|
|
78
|
+
* <Service.Description className="text-gray-600" />
|
|
79
|
+
*
|
|
80
|
+
* // asChild with primitive
|
|
81
|
+
* <Service.Description asChild>
|
|
82
|
+
* <p className="text-gray-600" />
|
|
83
|
+
* </Service.Description>
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export const Description = React.forwardRef((props, ref) => {
|
|
87
|
+
const { asChild, children, className } = props;
|
|
88
|
+
return (_jsx(CoreService.Info, { children: ({ description }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceDescription, customElement: children, customElementProps: { description }, children: _jsx("div", { children: description }) })) }));
|
|
89
|
+
});
|
|
90
|
+
Description.displayName = 'Service.Description';
|
|
91
|
+
/**
|
|
92
|
+
* Actions namespace with individual action components
|
|
93
|
+
*/
|
|
94
|
+
export var Actions;
|
|
95
|
+
(function (Actions) {
|
|
96
|
+
/**
|
|
97
|
+
* Select action component - replaces selection with only this service.
|
|
98
|
+
*
|
|
99
|
+
* @component
|
|
100
|
+
* @example
|
|
101
|
+
* ```tsx
|
|
102
|
+
* // Default button
|
|
103
|
+
* <Service.Actions.Select label="Select This Service" />
|
|
104
|
+
*
|
|
105
|
+
* // With asChild using custom Button component
|
|
106
|
+
* <Service.Actions.Select asChild>
|
|
107
|
+
* <Button variant="primary">Select Service</Button>
|
|
108
|
+
* </Service.Actions.Select>
|
|
109
|
+
*
|
|
110
|
+
* // With onClicked callback for navigation
|
|
111
|
+
* <Service.Actions.Select
|
|
112
|
+
* asChild
|
|
113
|
+
* onClicked={(event, service) => {
|
|
114
|
+
* router.push(`/booking/time-slots/${service._id}`);
|
|
115
|
+
* }}
|
|
116
|
+
* >
|
|
117
|
+
* <Button variant="primary">Select Service</Button>
|
|
118
|
+
* </Service.Actions.Select>
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
Actions.Select = React.forwardRef((props, ref) => {
|
|
122
|
+
const { asChild, children, className, label = 'Select Service', onClicked, } = props;
|
|
123
|
+
return (_jsx(CoreService.Actions, { children: ({ select, service }) => {
|
|
124
|
+
const handleClick = (event) => {
|
|
125
|
+
select();
|
|
126
|
+
onClicked?.(event, service);
|
|
127
|
+
};
|
|
128
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionSelect, customElement: children, customElementProps: { onClick: handleClick }, children: _jsx("button", { onClick: handleClick, children: label }) }));
|
|
129
|
+
} }));
|
|
130
|
+
});
|
|
131
|
+
Actions.Select.displayName = 'Service.Actions.Select';
|
|
132
|
+
/**
|
|
133
|
+
* Add action component - adds service to selection array.
|
|
134
|
+
*
|
|
135
|
+
* @component
|
|
136
|
+
* @example
|
|
137
|
+
* ```tsx
|
|
138
|
+
* // Default button
|
|
139
|
+
* <Service.Actions.Add label="Add to Selection" />
|
|
140
|
+
*
|
|
141
|
+
* // With asChild using custom Button component
|
|
142
|
+
* <Service.Actions.Add asChild>
|
|
143
|
+
* <Button variant="secondary">Add Service</Button>
|
|
144
|
+
* </Service.Actions.Add>
|
|
145
|
+
*
|
|
146
|
+
* // With onClicked callback for tracking
|
|
147
|
+
* <Service.Actions.Add
|
|
148
|
+
* label="Add to Cart"
|
|
149
|
+
* onClicked={(event, service) => {
|
|
150
|
+
* analytics.track('service_added', { serviceId: service._id });
|
|
151
|
+
* }}
|
|
152
|
+
* />
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
Actions.Add = React.forwardRef((props, ref) => {
|
|
156
|
+
const { asChild, children, className, label = 'Add Service', onClicked, } = props;
|
|
157
|
+
return (_jsx(CoreService.Actions, { children: ({ add, service }) => {
|
|
158
|
+
const handleClick = (event) => {
|
|
159
|
+
add();
|
|
160
|
+
onClicked?.(event, service);
|
|
161
|
+
};
|
|
162
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionAdd, customElement: children, customElementProps: { onClick: handleClick }, children: _jsx("button", { onClick: handleClick, children: label }) }));
|
|
163
|
+
} }));
|
|
164
|
+
});
|
|
165
|
+
Actions.Add.displayName = 'Service.Actions.Add';
|
|
166
|
+
/**
|
|
167
|
+
* Remove action component - removes service from selection array.
|
|
168
|
+
*
|
|
169
|
+
* @component
|
|
170
|
+
* @example
|
|
171
|
+
* ```tsx
|
|
172
|
+
* // Default button
|
|
173
|
+
* <Service.Actions.Remove label="Remove from Selection" />
|
|
174
|
+
*
|
|
175
|
+
* // With asChild using custom Button component
|
|
176
|
+
* <Service.Actions.Remove asChild>
|
|
177
|
+
* <Button variant="destructive">Remove Service</Button>
|
|
178
|
+
* </Service.Actions.Remove>
|
|
179
|
+
*
|
|
180
|
+
* // With onClicked callback for notifications
|
|
181
|
+
* <Service.Actions.Remove
|
|
182
|
+
* asChild
|
|
183
|
+
* onClicked={(event, service) => {
|
|
184
|
+
* toast.success(`${service.name} removed from selection`);
|
|
185
|
+
* }}
|
|
186
|
+
* >
|
|
187
|
+
* <IconButton icon="trash" />
|
|
188
|
+
* </Service.Actions.Remove>
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
Actions.Remove = React.forwardRef((props, ref) => {
|
|
192
|
+
const { asChild, children, className, label = 'Remove Service', onClicked, } = props;
|
|
193
|
+
return (_jsx(CoreService.Actions, { children: ({ remove, service }) => {
|
|
194
|
+
const handleClick = (event) => {
|
|
195
|
+
remove();
|
|
196
|
+
onClicked?.(event, service);
|
|
197
|
+
};
|
|
198
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceActionRemove, customElement: children, customElementProps: { onClick: handleClick }, children: _jsx("button", { onClick: handleClick, children: label }) }));
|
|
199
|
+
} }));
|
|
200
|
+
});
|
|
201
|
+
Actions.Remove.displayName = 'Service.Actions.Remove';
|
|
202
|
+
})(Actions || (Actions = {}));
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Booking Service - Global booking store
|
|
3
|
+
* Manages booking flow state (selected service, and future: time slot, payment option, participants)
|
|
4
|
+
* Persists across page navigation in SPA until page refresh
|
|
5
|
+
*/
|
|
6
|
+
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
7
|
+
import type { services, availabilityTimeSlots } from '@wix/bookings';
|
|
8
|
+
/**
|
|
9
|
+
* Booking Service interface
|
|
10
|
+
* Note: This is NOT an "API" service - it only exposes signals for state storage
|
|
11
|
+
*/
|
|
12
|
+
export interface BookingService {
|
|
13
|
+
/** Signal containing the currently selected services (can be multiple) */
|
|
14
|
+
selectedServices: Signal<services.Service[]>;
|
|
15
|
+
/** Signal containing the currently selected time slot */
|
|
16
|
+
selectedTimeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Service definition for Booking
|
|
20
|
+
*/
|
|
21
|
+
export declare const BookingServiceDefinition: string & {
|
|
22
|
+
__api: BookingService;
|
|
23
|
+
__config: {};
|
|
24
|
+
isServiceDefinition?: boolean;
|
|
25
|
+
} & BookingService;
|
|
26
|
+
/**
|
|
27
|
+
* Configuration interface for BookingService
|
|
28
|
+
*/
|
|
29
|
+
export interface BookingServiceConfig {
|
|
30
|
+
/** Optional initial services to pre-populate (default: empty array) */
|
|
31
|
+
initialServices?: services.Service[];
|
|
32
|
+
/** Optional initial time slot to pre-populate (default: null) */
|
|
33
|
+
initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Implementation of BookingService
|
|
37
|
+
*
|
|
38
|
+
* This service stores booking state in memory during the session.
|
|
39
|
+
* State persists across page navigation (SPA behavior) until page refresh.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* // In BaseLayout.astro
|
|
44
|
+
* const bookingConfig = await loadBookingServiceConfig();
|
|
45
|
+
*
|
|
46
|
+
* // Wrap app with provider
|
|
47
|
+
* <Booking.Root bookingServiceConfig={bookingConfig}>
|
|
48
|
+
* {children}
|
|
49
|
+
* </Booking.Root>
|
|
50
|
+
*
|
|
51
|
+
* // In any page - access booking data
|
|
52
|
+
* <Booking.Data>
|
|
53
|
+
* {({ selectedServices }) => (
|
|
54
|
+
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
55
|
+
* )}
|
|
56
|
+
* </Booking.Data>
|
|
57
|
+
*
|
|
58
|
+
* // Modify booking data (via action to be added later)
|
|
59
|
+
* const booking = useService(BookingServiceDefinition);
|
|
60
|
+
* booking.selectedServices.set([...currentServices, newService]);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare const BookingService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
64
|
+
__api: BookingService;
|
|
65
|
+
__config: {};
|
|
66
|
+
isServiceDefinition?: boolean;
|
|
67
|
+
} & BookingService, BookingServiceConfig>;
|
|
68
|
+
/**
|
|
69
|
+
* Load configuration for BookingService
|
|
70
|
+
*
|
|
71
|
+
* This function is called during SSR to initialize the service.
|
|
72
|
+
* Currently returns null state - can be extended to load from API in future.
|
|
73
|
+
*
|
|
74
|
+
* @returns Promise resolving to BookingServiceConfig
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```astro
|
|
78
|
+
* ---
|
|
79
|
+
* import { loadBookingServiceConfig } from '@wix/headless-bookings/services';
|
|
80
|
+
*
|
|
81
|
+
* const bookingConfig = await loadBookingServiceConfig();
|
|
82
|
+
* ---
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function loadBookingServiceConfig(): Promise<BookingServiceConfig>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Booking Service - Global booking store
|
|
3
|
+
* Manages booking flow state (selected service, and future: time slot, payment option, participants)
|
|
4
|
+
* Persists across page navigation in SPA until page refresh
|
|
5
|
+
*/
|
|
6
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
7
|
+
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
8
|
+
/**
|
|
9
|
+
* Service definition for Booking
|
|
10
|
+
*/
|
|
11
|
+
export const BookingServiceDefinition = defineService('booking');
|
|
12
|
+
/**
|
|
13
|
+
* Implementation of BookingService
|
|
14
|
+
*
|
|
15
|
+
* This service stores booking state in memory during the session.
|
|
16
|
+
* State persists across page navigation (SPA behavior) until page refresh.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // In BaseLayout.astro
|
|
21
|
+
* const bookingConfig = await loadBookingServiceConfig();
|
|
22
|
+
*
|
|
23
|
+
* // Wrap app with provider
|
|
24
|
+
* <Booking.Root bookingServiceConfig={bookingConfig}>
|
|
25
|
+
* {children}
|
|
26
|
+
* </Booking.Root>
|
|
27
|
+
*
|
|
28
|
+
* // In any page - access booking data
|
|
29
|
+
* <Booking.Data>
|
|
30
|
+
* {({ selectedServices }) => (
|
|
31
|
+
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
32
|
+
* )}
|
|
33
|
+
* </Booking.Data>
|
|
34
|
+
*
|
|
35
|
+
* // Modify booking data (via action to be added later)
|
|
36
|
+
* const booking = useService(BookingServiceDefinition);
|
|
37
|
+
* booking.selectedServices.set([...currentServices, newService]);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
|
|
41
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
42
|
+
// Initialize selectedServices signal with config or empty array
|
|
43
|
+
const selectedServices = signalsService.signal(config.initialServices || []);
|
|
44
|
+
// Initialize selectedTimeSlot signal with config or null
|
|
45
|
+
const selectedTimeSlot = signalsService.signal(config.initialTimeSlot || null);
|
|
46
|
+
return {
|
|
47
|
+
selectedServices,
|
|
48
|
+
selectedTimeSlot,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Load configuration for BookingService
|
|
53
|
+
*
|
|
54
|
+
* This function is called during SSR to initialize the service.
|
|
55
|
+
* Currently returns null state - can be extended to load from API in future.
|
|
56
|
+
*
|
|
57
|
+
* @returns Promise resolving to BookingServiceConfig
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```astro
|
|
61
|
+
* ---
|
|
62
|
+
* import { loadBookingServiceConfig } from '@wix/headless-bookings/services';
|
|
63
|
+
*
|
|
64
|
+
* const bookingConfig = await loadBookingServiceConfig();
|
|
65
|
+
* ---
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export async function loadBookingServiceConfig() {
|
|
69
|
+
// Future: Load persisted selections from API by selection ID
|
|
70
|
+
return {
|
|
71
|
+
initialServices: [],
|
|
72
|
+
initialTimeSlot: null,
|
|
73
|
+
};
|
|
74
|
+
}
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Bookings Services
|
|
3
|
+
* Main export file for all service definitions and implementations
|
|
4
|
+
*/
|
|
5
|
+
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, loadServiceServiceConfig, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
|
+
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, loadBookingServiceConfig, } from './booking/booking.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Bookings Services
|
|
3
|
+
* Main export file for all service definitions and implementations
|
|
4
|
+
*/
|
|
5
|
+
export { ServiceService, ServiceServiceDefinition, loadServiceServiceConfig, } from './service/service.js';
|
|
6
|
+
export { BookingService, BookingServiceDefinition, loadBookingServiceConfig, } from './booking/booking.js';
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Service - Reactive service data management
|
|
3
|
+
* Handles loading and managing a single service's data, loading state, and errors.
|
|
4
|
+
*/
|
|
1
5
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
2
6
|
import { services } from '@wix/bookings';
|
|
3
7
|
/**
|
|
4
8
|
* API interface for the Service service, providing reactive service data management.
|
|
5
|
-
* This service handles loading and managing a single service's data, loading state, and errors.
|
|
6
9
|
*
|
|
7
10
|
* @interface ServiceServiceAPI
|
|
8
11
|
*/
|
|
@@ -15,6 +18,12 @@ export interface ServiceServiceAPI {
|
|
|
15
18
|
error: Signal<string | null>;
|
|
16
19
|
/** Function to load a service by its id */
|
|
17
20
|
loadService: (id: string) => Promise<void>;
|
|
21
|
+
/** Function to select this service (replaces entire selection) */
|
|
22
|
+
select: () => void;
|
|
23
|
+
/** Function to add this service to the selection */
|
|
24
|
+
add: () => void;
|
|
25
|
+
/** Function to remove this service from the selection */
|
|
26
|
+
remove: () => void;
|
|
18
27
|
}
|
|
19
28
|
/**
|
|
20
29
|
* Service definition for the Service service.
|
|
@@ -46,7 +55,7 @@ export interface ServiceServiceConfig {
|
|
|
46
55
|
*
|
|
47
56
|
* @example
|
|
48
57
|
* ```tsx
|
|
49
|
-
* import { ServiceService, ServiceServiceDefinition } from '@wix/
|
|
58
|
+
* import { ServiceService, ServiceServiceDefinition } from '@wix/bookings/services';
|
|
50
59
|
* import { useService } from '@wix/services-manager-react';
|
|
51
60
|
*
|
|
52
61
|
* function ServiceComponent({ serviceConfig }) {
|
|
@@ -78,59 +87,35 @@ export declare const ServiceService: import("@wix/services-definitions").Service
|
|
|
78
87
|
isServiceDefinition?: boolean;
|
|
79
88
|
} & ServiceServiceAPI, ServiceServiceConfig>;
|
|
80
89
|
/**
|
|
81
|
-
*
|
|
82
|
-
* Returned when a service is successfully found and loaded.
|
|
83
|
-
*
|
|
84
|
-
* @interface SuccessServiceServiceConfigResult
|
|
90
|
+
* Result types for service loading operations
|
|
85
91
|
*/
|
|
86
|
-
export
|
|
87
|
-
/** Type "success" means that the service was found and the config is valid */
|
|
92
|
+
export type SuccessServiceServiceConfigResult = {
|
|
88
93
|
type: 'success';
|
|
89
|
-
/** The service config containing the loaded service data */
|
|
90
94
|
config: ServiceServiceConfig;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
* Not found result interface for service service configuration loading.
|
|
94
|
-
* Returned when a service with the given id cannot be found.
|
|
95
|
-
*
|
|
96
|
-
* @interface NotFoundServiceServiceConfigResult
|
|
97
|
-
*/
|
|
98
|
-
export interface NotFoundServiceServiceConfigResult {
|
|
99
|
-
/** Type "notFound" means that the service was not found */
|
|
95
|
+
};
|
|
96
|
+
export type NotFoundServiceServiceConfigResult = {
|
|
100
97
|
type: 'notFound';
|
|
101
|
-
}
|
|
98
|
+
};
|
|
102
99
|
/**
|
|
103
|
-
*
|
|
104
|
-
* This function is designed to be
|
|
105
|
-
*
|
|
100
|
+
* Load service configuration for Server-Side Rendering (SSR).
|
|
101
|
+
* This function is designed to be called during the build or server-side rendering phase
|
|
102
|
+
* to pre-fetch service data before the React components are hydrated on the client.
|
|
106
103
|
*
|
|
107
|
-
* @param
|
|
108
|
-
* @returns
|
|
104
|
+
* @param slug - The slug of the service to load (e.g., "group-trainings", "yoga-class")
|
|
105
|
+
* @returns A promise that resolves to either a success result with the config or a notFound result
|
|
109
106
|
*
|
|
110
107
|
* @example
|
|
111
|
-
* ```
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* import { loadServiceServiceConfig } from '@wix/services/services';
|
|
115
|
-
* import { Service } from '@wix/services/components';
|
|
116
|
-
*
|
|
117
|
-
* // Get service id from URL params
|
|
118
|
-
* const { id } = Astro.params;
|
|
108
|
+
* ```ts
|
|
109
|
+
* // In an Astro page or API route
|
|
110
|
+
* import { loadServiceServiceConfig } from '@wix/headless-bookings/services';
|
|
119
111
|
*
|
|
120
|
-
*
|
|
121
|
-
* const serviceResult = await loadServiceServiceConfig(id);
|
|
112
|
+
* const serviceResult = await loadServiceServiceConfig('group-trainings');
|
|
122
113
|
*
|
|
123
|
-
* // Handle not found case
|
|
124
114
|
* if (serviceResult.type === 'notFound') {
|
|
125
115
|
* return Astro.redirect('/404');
|
|
126
116
|
* }
|
|
127
|
-
* ---
|
|
128
117
|
*
|
|
129
|
-
*
|
|
130
|
-
* <Service.Name>
|
|
131
|
-
* {({ name }) => <h1>{name}</h1>}
|
|
132
|
-
* </Service.Name>
|
|
133
|
-
* </Service.Root>
|
|
118
|
+
* const serviceConfig = serviceResult.config;
|
|
134
119
|
* ```
|
|
135
120
|
*/
|
|
136
|
-
export declare function loadServiceServiceConfig(
|
|
121
|
+
export declare function loadServiceServiceConfig(slug: string): Promise<SuccessServiceServiceConfigResult | NotFoundServiceServiceConfigResult>;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Service - Reactive service data management
|
|
3
|
+
* Handles loading and managing a single service's data, loading state, and errors.
|
|
4
|
+
*/
|
|
1
5
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
6
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
-
import {
|
|
7
|
+
import { getServiceById, getServiceBySlug, } from '../../api/query-service/index.js';
|
|
8
|
+
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
4
9
|
/**
|
|
5
10
|
* Service definition for the Service service.
|
|
6
11
|
* This defines the contract that the ServiceService must implement.
|
|
@@ -15,7 +20,7 @@ export const ServiceServiceDefinition = defineService('service');
|
|
|
15
20
|
*
|
|
16
21
|
* @example
|
|
17
22
|
* ```tsx
|
|
18
|
-
* import { ServiceService, ServiceServiceDefinition } from '@wix/
|
|
23
|
+
* import { ServiceService, ServiceServiceDefinition } from '@wix/bookings/services';
|
|
19
24
|
* import { useService } from '@wix/services-manager-react';
|
|
20
25
|
*
|
|
21
26
|
* function ServiceComponent({ serviceConfig }) {
|
|
@@ -43,86 +48,82 @@ export const ServiceServiceDefinition = defineService('service');
|
|
|
43
48
|
*/
|
|
44
49
|
export const ServiceService = implementService.withConfig()(ServiceServiceDefinition, ({ getService, config }) => {
|
|
45
50
|
const signalsService = getService(SignalsServiceDefinition);
|
|
51
|
+
const bookingService = getService(BookingServiceDefinition);
|
|
46
52
|
const service = signalsService.signal(config.service);
|
|
47
53
|
const isLoading = signalsService.signal(!!config.serviceId);
|
|
48
54
|
const error = signalsService.signal(null);
|
|
49
55
|
const loadService = async (id) => {
|
|
50
56
|
isLoading.set(true);
|
|
51
|
-
|
|
57
|
+
error.set(null);
|
|
58
|
+
const serviceResponse = await getServiceById(id);
|
|
52
59
|
if (!serviceResponse.service) {
|
|
53
60
|
error.set('Service not found');
|
|
61
|
+
isLoading.set(false);
|
|
54
62
|
}
|
|
55
63
|
else {
|
|
56
64
|
service.set(serviceResponse.service);
|
|
57
65
|
error.set(null);
|
|
66
|
+
isLoading.set(false);
|
|
58
67
|
}
|
|
59
|
-
isLoading.set(false);
|
|
60
68
|
};
|
|
61
|
-
if
|
|
69
|
+
// Auto-load if serviceId is provided but no service data
|
|
70
|
+
if (config.serviceId && !config.service) {
|
|
62
71
|
loadService(config.serviceId);
|
|
63
72
|
}
|
|
73
|
+
// Action methods for booking
|
|
74
|
+
const select = () => {
|
|
75
|
+
const currentService = service.get();
|
|
76
|
+
bookingService.selectedServices.set([currentService]);
|
|
77
|
+
};
|
|
78
|
+
const add = () => {
|
|
79
|
+
const currentService = service.get();
|
|
80
|
+
const selectedServices = bookingService.selectedServices.get();
|
|
81
|
+
bookingService.selectedServices.set([
|
|
82
|
+
...selectedServices,
|
|
83
|
+
currentService,
|
|
84
|
+
]);
|
|
85
|
+
};
|
|
86
|
+
const remove = () => {
|
|
87
|
+
const currentService = service.get();
|
|
88
|
+
const selectedServices = bookingService.selectedServices.get();
|
|
89
|
+
const filtered = selectedServices.filter((s) => s._id !== currentService._id);
|
|
90
|
+
bookingService.selectedServices.set(filtered);
|
|
91
|
+
};
|
|
64
92
|
return {
|
|
65
93
|
service,
|
|
66
94
|
isLoading,
|
|
67
95
|
error,
|
|
68
96
|
loadService,
|
|
97
|
+
select,
|
|
98
|
+
add,
|
|
99
|
+
remove,
|
|
69
100
|
};
|
|
70
101
|
});
|
|
71
102
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
103
|
+
* Load service configuration for Server-Side Rendering (SSR).
|
|
104
|
+
* This function is designed to be called during the build or server-side rendering phase
|
|
105
|
+
* to pre-fetch service data before the React components are hydrated on the client.
|
|
74
106
|
*
|
|
75
|
-
* @
|
|
76
|
-
* @
|
|
77
|
-
* @returns {Promise} Service response from the API
|
|
78
|
-
*/
|
|
79
|
-
const loadServiceById = async (id) => {
|
|
80
|
-
try {
|
|
81
|
-
const service = await services.getService(id);
|
|
82
|
-
return { service };
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
console.error(`Failed to load service for id "${id}":`, error);
|
|
86
|
-
return { service: null };
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Loads service service configuration from the Wix Services API for SSR initialization.
|
|
91
|
-
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
92
|
-
* a specific service by id that will be used to configure the ServiceService.
|
|
93
|
-
*
|
|
94
|
-
* @param serviceId The service id to load
|
|
95
|
-
* @returns Promise that resolves to ServiceServiceConfigResult (success with config or notFound)
|
|
107
|
+
* @param slug - The slug of the service to load (e.g., "group-trainings", "yoga-class")
|
|
108
|
+
* @returns A promise that resolves to either a success result with the config or a notFound result
|
|
96
109
|
*
|
|
97
110
|
* @example
|
|
98
|
-
* ```
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* import { loadServiceServiceConfig } from '@wix/services/services';
|
|
102
|
-
* import { Service } from '@wix/services/components';
|
|
103
|
-
*
|
|
104
|
-
* // Get service id from URL params
|
|
105
|
-
* const { id } = Astro.params;
|
|
111
|
+
* ```ts
|
|
112
|
+
* // In an Astro page or API route
|
|
113
|
+
* import { loadServiceServiceConfig } from '@wix/headless-bookings/services';
|
|
106
114
|
*
|
|
107
|
-
*
|
|
108
|
-
* const serviceResult = await loadServiceServiceConfig(id);
|
|
115
|
+
* const serviceResult = await loadServiceServiceConfig('group-trainings');
|
|
109
116
|
*
|
|
110
|
-
* // Handle not found case
|
|
111
117
|
* if (serviceResult.type === 'notFound') {
|
|
112
118
|
* return Astro.redirect('/404');
|
|
113
119
|
* }
|
|
114
|
-
* ---
|
|
115
120
|
*
|
|
116
|
-
*
|
|
117
|
-
* <Service.Name>
|
|
118
|
-
* {({ name }) => <h1>{name}</h1>}
|
|
119
|
-
* </Service.Name>
|
|
120
|
-
* </Service.Root>
|
|
121
|
+
* const serviceConfig = serviceResult.config;
|
|
121
122
|
* ```
|
|
122
123
|
*/
|
|
123
|
-
export async function loadServiceServiceConfig(
|
|
124
|
+
export async function loadServiceServiceConfig(slug) {
|
|
124
125
|
try {
|
|
125
|
-
const serviceResponse = await
|
|
126
|
+
const serviceResponse = await getServiceBySlug(slug);
|
|
126
127
|
if (!serviceResponse.service) {
|
|
127
128
|
return { type: 'notFound' };
|
|
128
129
|
}
|
|
@@ -134,7 +135,7 @@ export async function loadServiceServiceConfig(serviceId) {
|
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
137
|
catch (error) {
|
|
137
|
-
console.error(`Failed to load service for
|
|
138
|
+
console.error(`Failed to load service for slug "${slug}":`, error);
|
|
138
139
|
return { type: 'notFound' };
|
|
139
140
|
}
|
|
140
141
|
}
|