@wix/headless-bookings 0.0.1 → 0.0.2
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/ServiceList.d.ts +50 -0
- package/cjs/dist/react/ServiceList.js +100 -0
- package/cjs/dist/react/ServiceListSort.d.ts +37 -0
- package/cjs/dist/react/ServiceListSort.js +35 -0
- package/cjs/dist/react/core/Service.d.ts +91 -0
- package/cjs/dist/react/core/Service.js +73 -0
- package/cjs/dist/react/core/ServiceList.d.ts +218 -0
- package/cjs/dist/react/core/ServiceList.js +199 -0
- package/cjs/dist/react/index.d.ts +4 -0
- package/cjs/dist/react/index.js +5 -0
- package/cjs/dist/react/test-ids.d.ts +18 -0
- package/cjs/dist/react/test-ids.js +24 -0
- package/cjs/dist/react/types.d.ts +52 -0
- package/cjs/dist/react/types.js +1 -0
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +1 -0
- package/cjs/dist/services/service-service.d.ts +136 -0
- package/cjs/dist/services/service-service.js +140 -0
- package/cjs/dist/services/services-list-service.d.ts +184 -0
- package/cjs/dist/services/services-list-service.js +168 -0
- package/cjs/package.json +3 -0
- package/dist/react/ServiceList.d.ts +50 -0
- package/dist/react/ServiceList.js +100 -0
- package/dist/react/ServiceListSort.d.ts +37 -0
- package/dist/react/ServiceListSort.js +35 -0
- package/dist/react/core/Service.d.ts +91 -0
- package/dist/react/core/Service.js +73 -0
- package/dist/react/core/ServiceList.d.ts +218 -0
- package/dist/react/core/ServiceList.js +199 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +5 -0
- package/dist/react/test-ids.d.ts +18 -0
- package/dist/react/test-ids.js +24 -0
- package/dist/react/types.d.ts +52 -0
- package/dist/react/types.js +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/service-service.d.ts +136 -0
- package/dist/services/service-service.js +140 -0
- package/dist/services/services-list-service.d.ts +184 -0
- package/dist/services/services-list-service.js +168 -0
- package/package.json +58 -13
- package/react/package.json +4 -0
- package/services/package.json +4 -0
- package/src/react/index.tsx +0 -3
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
|
+
import { createServicesMap } from '@wix/services-manager';
|
|
4
|
+
import { ServicesListService, ServicesListServiceDefinition, } from '../../services/services-list-service.js';
|
|
5
|
+
/**
|
|
6
|
+
* Root component that provides ServiceList service context to its children.
|
|
7
|
+
* This component sets up the necessary services for managing services list state,
|
|
8
|
+
* including filtering, sorting, and pagination functionality.
|
|
9
|
+
*
|
|
10
|
+
* @order 1
|
|
11
|
+
* @component
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { ServiceList, Service } from '@wix/headless-services/react';
|
|
15
|
+
*
|
|
16
|
+
* function ServiceListPage() {
|
|
17
|
+
* return (
|
|
18
|
+
* <ServiceList.Root
|
|
19
|
+
* servicesListConfig={{
|
|
20
|
+
* services: myServices,
|
|
21
|
+
* searchOptions: {
|
|
22
|
+
* cursorPaging: { limit: 10 },
|
|
23
|
+
* sort: [{ fieldName: 'name', order: 'ASC' }]
|
|
24
|
+
* },
|
|
25
|
+
* pagingMetadata: { count: 10, hasNext: true }
|
|
26
|
+
* }}
|
|
27
|
+
* >
|
|
28
|
+
* <ServiceList.Options>
|
|
29
|
+
* <ServiceList.ServiceRepeater>
|
|
30
|
+
* <Service.Name>
|
|
31
|
+
* {({ name }) => <h3>{name}</h3>}
|
|
32
|
+
* </Service.Name>
|
|
33
|
+
* <Service.Price>
|
|
34
|
+
* {({ price }) => price && <div>{price.value} {price.currency}</div>}
|
|
35
|
+
* </Service.Price>
|
|
36
|
+
* </ServiceList.ServiceRepeater>
|
|
37
|
+
* </ServiceList.Options>
|
|
38
|
+
* </ServiceList.Root>
|
|
39
|
+
* );
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function Root(props) {
|
|
44
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(ServicesListServiceDefinition, ServicesListService, props.servicesListConfig), children: props.children }));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Component that renders content when the services list is empty.
|
|
48
|
+
* Only displays its children when there are no services, no loading state, and no errors.
|
|
49
|
+
*
|
|
50
|
+
* @component
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* import { ServiceList } from '@wix/headless-services/react';
|
|
54
|
+
*
|
|
55
|
+
* function EmptyServicesMessage() {
|
|
56
|
+
* return (
|
|
57
|
+
* <ServiceList.EmptyState>
|
|
58
|
+
* {() => (
|
|
59
|
+
* <div className="empty-state">
|
|
60
|
+
* <h3>No services found</h3>
|
|
61
|
+
* <p>Try adjusting your search or filter criteria</p>
|
|
62
|
+
* <button>Clear Filters</button>
|
|
63
|
+
* </div>
|
|
64
|
+
* )}
|
|
65
|
+
* </ServiceList.EmptyState>
|
|
66
|
+
* );
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function EmptyState(props) {
|
|
71
|
+
const { isLoading, error, services: servicesList, } = useService(ServicesListServiceDefinition);
|
|
72
|
+
const isLoadingValue = isLoading.get();
|
|
73
|
+
const errorValue = error.get();
|
|
74
|
+
const servicesValue = servicesList.get();
|
|
75
|
+
if (!isLoadingValue && !errorValue && servicesValue.length === 0) {
|
|
76
|
+
return typeof props.children === 'function'
|
|
77
|
+
? props.children({})
|
|
78
|
+
: props.children;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Component that renders content during loading state.
|
|
84
|
+
* Only displays its children when the services list is currently loading.
|
|
85
|
+
*
|
|
86
|
+
* @component
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* import { ServiceList } from '@wix/headless-services/react';
|
|
90
|
+
*
|
|
91
|
+
* function ServicesLoading() {
|
|
92
|
+
* return (
|
|
93
|
+
* <ServiceList.Loading>
|
|
94
|
+
* {() => (
|
|
95
|
+
* <div className="loading-spinner">
|
|
96
|
+
* <div>Loading services...</div>
|
|
97
|
+
* <div className="spinner"></div>
|
|
98
|
+
* </div>
|
|
99
|
+
* )}
|
|
100
|
+
* </ServiceList.Loading>
|
|
101
|
+
* );
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function Loading(props) {
|
|
106
|
+
const { isLoading } = useService(ServicesListServiceDefinition);
|
|
107
|
+
const isLoadingValue = isLoading.get();
|
|
108
|
+
if (isLoadingValue) {
|
|
109
|
+
return typeof props.children === 'function'
|
|
110
|
+
? props.children({})
|
|
111
|
+
: props.children;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Component that renders content when there's an error loading services.
|
|
117
|
+
* Only displays its children when an error has occurred.
|
|
118
|
+
*
|
|
119
|
+
* @component
|
|
120
|
+
* @example
|
|
121
|
+
* ```tsx
|
|
122
|
+
* import { ServiceList } from '@wix/headless-services/react';
|
|
123
|
+
*
|
|
124
|
+
* function ServicesError() {
|
|
125
|
+
* return (
|
|
126
|
+
* <ServiceList.Error>
|
|
127
|
+
* {({ error }) => (
|
|
128
|
+
* <div className="error-state">
|
|
129
|
+
* <h3>Error loading services</h3>
|
|
130
|
+
* <p>{error}</p>
|
|
131
|
+
* <button onClick={() => window.location.reload()}>
|
|
132
|
+
* Try Again
|
|
133
|
+
* </button>
|
|
134
|
+
* </div>
|
|
135
|
+
* )}
|
|
136
|
+
* </ServiceList.Error>
|
|
137
|
+
* );
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function Error(props) {
|
|
142
|
+
const { error } = useService(ServicesListServiceDefinition);
|
|
143
|
+
const errorValue = error.get();
|
|
144
|
+
if (errorValue) {
|
|
145
|
+
return typeof props.children === 'function'
|
|
146
|
+
? props.children({ error: errorValue })
|
|
147
|
+
: props.children;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Component that renders content for each service in the list.
|
|
153
|
+
* Maps over all services and provides each service through a service context.
|
|
154
|
+
* Only renders when services are successfully loaded (not loading, no error, and has services).
|
|
155
|
+
*
|
|
156
|
+
* @component
|
|
157
|
+
* @example
|
|
158
|
+
* ```tsx
|
|
159
|
+
* import { ServiceList, Service } from '@wix/headless-services/react';
|
|
160
|
+
*
|
|
161
|
+
* function ServicesGrid() {
|
|
162
|
+
* return (
|
|
163
|
+
* <ServiceList.ItemContent>
|
|
164
|
+
* {({ service }) => (
|
|
165
|
+
* <div className="service-card">
|
|
166
|
+
* <Service.Image>
|
|
167
|
+
* {({ image, alt }) => <img src={image} alt={alt} />}
|
|
168
|
+
* </Service.Image>
|
|
169
|
+
* <Service.Name>
|
|
170
|
+
* {({ name }) => <h3>{name}</h3>}
|
|
171
|
+
* </Service.Name>
|
|
172
|
+
* <Service.Price>
|
|
173
|
+
* {({ price }) => price && <p>{price.value} {price.currency}</p>}
|
|
174
|
+
* </Service.Price>
|
|
175
|
+
* <button>Book Now</button>
|
|
176
|
+
* </div>
|
|
177
|
+
* )}
|
|
178
|
+
* </ServiceList.ItemContent>
|
|
179
|
+
* );
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function ItemContent(props) {
|
|
184
|
+
const { services: servicesList, isLoading, error, } = useService(ServicesListServiceDefinition);
|
|
185
|
+
const servicesValue = servicesList.get();
|
|
186
|
+
if (isLoading.get() || error.get() || servicesValue.length === 0) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return servicesValue.map((service) => (_jsx(WixServices, { servicesMap: createServicesMap(), children: typeof props.children === 'function'
|
|
190
|
+
? props.children({ service })
|
|
191
|
+
: props.children }, service._id)));
|
|
192
|
+
}
|
|
193
|
+
export function Items(props) {
|
|
194
|
+
const { services: servicesList } = useService(ServicesListServiceDefinition);
|
|
195
|
+
const servicesValue = servicesList.get();
|
|
196
|
+
return typeof props.children === 'function'
|
|
197
|
+
? props.children({ services: servicesValue })
|
|
198
|
+
: props.children;
|
|
199
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare enum TestIds {
|
|
2
|
+
servicesList = "services-list",
|
|
3
|
+
servicesOptions = "services-options",
|
|
4
|
+
serviceRepeater = "service-repeater",
|
|
5
|
+
serviceRoot = "service-root",
|
|
6
|
+
serviceName = "service-name",
|
|
7
|
+
serviceDescription = "service-description",
|
|
8
|
+
servicePrice = "service-price",
|
|
9
|
+
serviceDuration = "service-duration",
|
|
10
|
+
serviceImage = "service-image",
|
|
11
|
+
serviceCategory = "service-category",
|
|
12
|
+
serviceError = "service-error",
|
|
13
|
+
serviceLoadMore = "service-load-more",
|
|
14
|
+
serviceTotalsDisplayed = "service-totals-displayed",
|
|
15
|
+
serviceSort = "service-sort",
|
|
16
|
+
serviceFilter = "service-filter",
|
|
17
|
+
serviceFilterResetTrigger = "service-filter-reset-trigger"
|
|
18
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export var TestIds;
|
|
2
|
+
(function (TestIds) {
|
|
3
|
+
// Container Level
|
|
4
|
+
TestIds["servicesList"] = "services-list";
|
|
5
|
+
// List Container Level
|
|
6
|
+
TestIds["servicesOptions"] = "services-options";
|
|
7
|
+
// Repeater Level
|
|
8
|
+
TestIds["serviceRepeater"] = "service-repeater";
|
|
9
|
+
// Entity Root and Components
|
|
10
|
+
TestIds["serviceRoot"] = "service-root";
|
|
11
|
+
TestIds["serviceName"] = "service-name";
|
|
12
|
+
TestIds["serviceDescription"] = "service-description";
|
|
13
|
+
TestIds["servicePrice"] = "service-price";
|
|
14
|
+
TestIds["serviceDuration"] = "service-duration";
|
|
15
|
+
TestIds["serviceImage"] = "service-image";
|
|
16
|
+
TestIds["serviceCategory"] = "service-category";
|
|
17
|
+
// Additional Components
|
|
18
|
+
TestIds["serviceError"] = "service-error";
|
|
19
|
+
TestIds["serviceLoadMore"] = "service-load-more";
|
|
20
|
+
TestIds["serviceTotalsDisplayed"] = "service-totals-displayed";
|
|
21
|
+
TestIds["serviceSort"] = "service-sort";
|
|
22
|
+
TestIds["serviceFilter"] = "service-filter";
|
|
23
|
+
TestIds["serviceFilterResetTrigger"] = "service-filter-reset-trigger";
|
|
24
|
+
})(TestIds || (TestIds = {}));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { services } from '@wix/bookings';
|
|
2
|
+
export interface ServiceListConfig {
|
|
3
|
+
services: services.Service[];
|
|
4
|
+
searchOptions: {
|
|
5
|
+
cursorPaging: {
|
|
6
|
+
limit: number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
pagingMetadata: {
|
|
10
|
+
count: number;
|
|
11
|
+
};
|
|
12
|
+
aggregations: {
|
|
13
|
+
results: any[];
|
|
14
|
+
};
|
|
15
|
+
customizations: any[];
|
|
16
|
+
}
|
|
17
|
+
export interface ServiceContextValue {
|
|
18
|
+
service: services.Service;
|
|
19
|
+
}
|
|
20
|
+
export interface ServiceListRenderProps {
|
|
21
|
+
services: services.Service[];
|
|
22
|
+
}
|
|
23
|
+
export interface ServiceRenderProps {
|
|
24
|
+
service: services.Service;
|
|
25
|
+
}
|
|
26
|
+
export interface ErrorRenderProps {
|
|
27
|
+
error: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface ServiceListState {
|
|
30
|
+
services: services.Service[];
|
|
31
|
+
pagingMetadata: {
|
|
32
|
+
count: number;
|
|
33
|
+
};
|
|
34
|
+
filters: Record<string, any>;
|
|
35
|
+
error: string | null;
|
|
36
|
+
}
|
|
37
|
+
export interface ServiceListServiceValue {
|
|
38
|
+
services: {
|
|
39
|
+
get: () => services.Service[];
|
|
40
|
+
};
|
|
41
|
+
pagingMetadata: {
|
|
42
|
+
get: () => {
|
|
43
|
+
count: number;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
filters: {
|
|
47
|
+
get: () => Record<string, any>;
|
|
48
|
+
};
|
|
49
|
+
error: {
|
|
50
|
+
get: () => string | null;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './services-list-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './services-list-service.js';
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
2
|
+
import { services } from '@wix/bookings';
|
|
3
|
+
/**
|
|
4
|
+
* 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
|
+
*
|
|
7
|
+
* @interface ServiceServiceAPI
|
|
8
|
+
*/
|
|
9
|
+
export interface ServiceServiceAPI {
|
|
10
|
+
/** Reactive signal containing the current service data */
|
|
11
|
+
service: Signal<services.Service>;
|
|
12
|
+
/** Reactive signal indicating if a service is currently being loaded */
|
|
13
|
+
isLoading: Signal<boolean>;
|
|
14
|
+
/** Reactive signal containing any error message, or null if no error */
|
|
15
|
+
error: Signal<string | null>;
|
|
16
|
+
/** Function to load a service by its id */
|
|
17
|
+
loadService: (id: string) => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Service definition for the Service service.
|
|
21
|
+
* This defines the contract that the ServiceService must implement.
|
|
22
|
+
*
|
|
23
|
+
* @constant
|
|
24
|
+
*/
|
|
25
|
+
export declare const ServiceServiceDefinition: string & {
|
|
26
|
+
__api: ServiceServiceAPI;
|
|
27
|
+
__config: {};
|
|
28
|
+
isServiceDefinition?: boolean;
|
|
29
|
+
} & ServiceServiceAPI;
|
|
30
|
+
/**
|
|
31
|
+
* Configuration interface required to initialize the ServiceService.
|
|
32
|
+
* Contains the initial service data that will be loaded into the service.
|
|
33
|
+
*
|
|
34
|
+
* @interface ServiceServiceConfig
|
|
35
|
+
*/
|
|
36
|
+
export interface ServiceServiceConfig {
|
|
37
|
+
/** The initial service data to configure the service with */
|
|
38
|
+
service?: services.Service;
|
|
39
|
+
/** The service ID to load if no initial service is provided */
|
|
40
|
+
serviceId?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Implementation of the Service service that manages reactive service data.
|
|
44
|
+
* This service provides signals for service data, loading state, and error handling,
|
|
45
|
+
* along with methods to dynamically load services.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* import { ServiceService, ServiceServiceDefinition } from '@wix/services/services';
|
|
50
|
+
* import { useService } from '@wix/services-manager-react';
|
|
51
|
+
*
|
|
52
|
+
* function ServiceComponent({ serviceConfig }) {
|
|
53
|
+
* return (
|
|
54
|
+
* <ServiceProvider services={createServicesMap([
|
|
55
|
+
* [ServiceServiceDefinition, ServiceService.withConfig(serviceConfig)]
|
|
56
|
+
* ])}>
|
|
57
|
+
* <ServiceDisplay />
|
|
58
|
+
* </ServiceProvider>
|
|
59
|
+
* );
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* function ServiceDisplay() {
|
|
63
|
+
* const serviceService = useService(ServiceServiceDefinition);
|
|
64
|
+
* const service = serviceService.service.get();
|
|
65
|
+
* const isLoading = serviceService.isLoading.get();
|
|
66
|
+
* const error = serviceService.error.get();
|
|
67
|
+
*
|
|
68
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
69
|
+
* if (error) return <div>Error: {error}</div>;
|
|
70
|
+
*
|
|
71
|
+
* return <h1>{service.name}</h1>;
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare const ServiceService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
76
|
+
__api: ServiceServiceAPI;
|
|
77
|
+
__config: {};
|
|
78
|
+
isServiceDefinition?: boolean;
|
|
79
|
+
} & ServiceServiceAPI, ServiceServiceConfig>;
|
|
80
|
+
/**
|
|
81
|
+
* Success result interface for service service configuration loading.
|
|
82
|
+
* Returned when a service is successfully found and loaded.
|
|
83
|
+
*
|
|
84
|
+
* @interface SuccessServiceServiceConfigResult
|
|
85
|
+
*/
|
|
86
|
+
export interface SuccessServiceServiceConfigResult {
|
|
87
|
+
/** Type "success" means that the service was found and the config is valid */
|
|
88
|
+
type: 'success';
|
|
89
|
+
/** The service config containing the loaded service data */
|
|
90
|
+
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 */
|
|
100
|
+
type: 'notFound';
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Loads service service configuration from the Wix Services API for SSR initialization.
|
|
104
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
105
|
+
* a specific service by id that will be used to configure the ServiceService.
|
|
106
|
+
*
|
|
107
|
+
* @param serviceId The service id to load
|
|
108
|
+
* @returns Promise that resolves to ServiceServiceConfigResult (success with config or notFound)
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```astro
|
|
112
|
+
* ---
|
|
113
|
+
* // Astro page example - pages/service/[id].astro
|
|
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;
|
|
119
|
+
*
|
|
120
|
+
* // Load service data during SSR
|
|
121
|
+
* const serviceResult = await loadServiceServiceConfig(id);
|
|
122
|
+
*
|
|
123
|
+
* // Handle not found case
|
|
124
|
+
* if (serviceResult.type === 'notFound') {
|
|
125
|
+
* return Astro.redirect('/404');
|
|
126
|
+
* }
|
|
127
|
+
* ---
|
|
128
|
+
*
|
|
129
|
+
* <Service.Root serviceConfig={serviceResult.config}>
|
|
130
|
+
* <Service.Name>
|
|
131
|
+
* {({ name }) => <h1>{name}</h1>}
|
|
132
|
+
* </Service.Name>
|
|
133
|
+
* </Service.Root>
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare function loadServiceServiceConfig(serviceId: string): Promise<SuccessServiceServiceConfigResult | NotFoundServiceServiceConfigResult>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { defineService, implementService } from '@wix/services-definitions';
|
|
2
|
+
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
3
|
+
import { services } from '@wix/bookings';
|
|
4
|
+
/**
|
|
5
|
+
* Service definition for the Service service.
|
|
6
|
+
* This defines the contract that the ServiceService must implement.
|
|
7
|
+
*
|
|
8
|
+
* @constant
|
|
9
|
+
*/
|
|
10
|
+
export const ServiceServiceDefinition = defineService('service');
|
|
11
|
+
/**
|
|
12
|
+
* Implementation of the Service service that manages reactive service data.
|
|
13
|
+
* This service provides signals for service data, loading state, and error handling,
|
|
14
|
+
* along with methods to dynamically load services.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { ServiceService, ServiceServiceDefinition } from '@wix/services/services';
|
|
19
|
+
* import { useService } from '@wix/services-manager-react';
|
|
20
|
+
*
|
|
21
|
+
* function ServiceComponent({ serviceConfig }) {
|
|
22
|
+
* return (
|
|
23
|
+
* <ServiceProvider services={createServicesMap([
|
|
24
|
+
* [ServiceServiceDefinition, ServiceService.withConfig(serviceConfig)]
|
|
25
|
+
* ])}>
|
|
26
|
+
* <ServiceDisplay />
|
|
27
|
+
* </ServiceProvider>
|
|
28
|
+
* );
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* function ServiceDisplay() {
|
|
32
|
+
* const serviceService = useService(ServiceServiceDefinition);
|
|
33
|
+
* const service = serviceService.service.get();
|
|
34
|
+
* const isLoading = serviceService.isLoading.get();
|
|
35
|
+
* const error = serviceService.error.get();
|
|
36
|
+
*
|
|
37
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
38
|
+
* if (error) return <div>Error: {error}</div>;
|
|
39
|
+
*
|
|
40
|
+
* return <h1>{service.name}</h1>;
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const ServiceService = implementService.withConfig()(ServiceServiceDefinition, ({ getService, config }) => {
|
|
45
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
46
|
+
const service = signalsService.signal(config.service);
|
|
47
|
+
const isLoading = signalsService.signal(!!config.serviceId);
|
|
48
|
+
const error = signalsService.signal(null);
|
|
49
|
+
const loadService = async (id) => {
|
|
50
|
+
isLoading.set(true);
|
|
51
|
+
const serviceResponse = await loadServiceById(id);
|
|
52
|
+
if (!serviceResponse.service) {
|
|
53
|
+
error.set('Service not found');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
service.set(serviceResponse.service);
|
|
57
|
+
error.set(null);
|
|
58
|
+
}
|
|
59
|
+
isLoading.set(false);
|
|
60
|
+
};
|
|
61
|
+
if (config.serviceId) {
|
|
62
|
+
loadService(config.serviceId);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
service,
|
|
66
|
+
isLoading,
|
|
67
|
+
error,
|
|
68
|
+
loadService,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Internal helper function to load a service by its ID from the Wix Services API.
|
|
73
|
+
* Fetches comprehensive service data including description, categories, media, etc.
|
|
74
|
+
*
|
|
75
|
+
* @private
|
|
76
|
+
* @param {string} id - The service ID to load
|
|
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)
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```astro
|
|
99
|
+
* ---
|
|
100
|
+
* // Astro page example - pages/service/[id].astro
|
|
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;
|
|
106
|
+
*
|
|
107
|
+
* // Load service data during SSR
|
|
108
|
+
* const serviceResult = await loadServiceServiceConfig(id);
|
|
109
|
+
*
|
|
110
|
+
* // Handle not found case
|
|
111
|
+
* if (serviceResult.type === 'notFound') {
|
|
112
|
+
* return Astro.redirect('/404');
|
|
113
|
+
* }
|
|
114
|
+
* ---
|
|
115
|
+
*
|
|
116
|
+
* <Service.Root serviceConfig={serviceResult.config}>
|
|
117
|
+
* <Service.Name>
|
|
118
|
+
* {({ name }) => <h1>{name}</h1>}
|
|
119
|
+
* </Service.Name>
|
|
120
|
+
* </Service.Root>
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export async function loadServiceServiceConfig(serviceId) {
|
|
124
|
+
try {
|
|
125
|
+
const serviceResponse = await loadServiceById(serviceId);
|
|
126
|
+
if (!serviceResponse.service) {
|
|
127
|
+
return { type: 'notFound' };
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
type: 'success',
|
|
131
|
+
config: {
|
|
132
|
+
service: serviceResponse.service,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.error(`Failed to load service for id "${serviceId}":`, error);
|
|
138
|
+
return { type: 'notFound' };
|
|
139
|
+
}
|
|
140
|
+
}
|