@wix/headless-bookings 0.0.0
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 +70 -0
- package/react/package.json +4 -0
- package/services/package.json +4 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { type Signal, type ReadOnlySignal } from '@wix/services-definitions/core-services/signals';
|
|
2
|
+
import { services } from '@wix/bookings';
|
|
3
|
+
export declare const DEFAULT_QUERY_LIMIT = 100;
|
|
4
|
+
/**
|
|
5
|
+
* Configuration interface for the Services List service.
|
|
6
|
+
* Contains the initial services data, search options, and metadata.
|
|
7
|
+
*
|
|
8
|
+
* @interface ServicesListServiceConfig
|
|
9
|
+
*/
|
|
10
|
+
export interface ServicesListServiceConfig {
|
|
11
|
+
/** Array of service objects to initialize the service with */
|
|
12
|
+
services: services.Service[];
|
|
13
|
+
/** Search options used to fetch the services */
|
|
14
|
+
searchOptions?: {
|
|
15
|
+
cursorPaging?: {
|
|
16
|
+
limit: number;
|
|
17
|
+
};
|
|
18
|
+
filter?: Record<string, any>;
|
|
19
|
+
sort?: Array<{
|
|
20
|
+
fieldName: string;
|
|
21
|
+
order: 'ASC' | 'DESC';
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
/** Pagination metadata from the search response */
|
|
25
|
+
pagingMetadata?: {
|
|
26
|
+
count: number;
|
|
27
|
+
cursors?: {
|
|
28
|
+
next?: () => Promise<services.ServicesQueryResult>;
|
|
29
|
+
prev?: () => Promise<services.ServicesQueryResult>;
|
|
30
|
+
};
|
|
31
|
+
hasNext?: boolean;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Service definition for the Services List service.
|
|
36
|
+
* This defines the reactive API contract for managing a list of services with search, pagination, and filtering capabilities.
|
|
37
|
+
*
|
|
38
|
+
* @constant
|
|
39
|
+
*/
|
|
40
|
+
export declare const ServicesListServiceDefinition: string & {
|
|
41
|
+
__api: {
|
|
42
|
+
/** Reactive signal containing the list of services */
|
|
43
|
+
services: Signal<services.Service[]>;
|
|
44
|
+
/** Reactive signal containing pagination metadata */
|
|
45
|
+
pagingMetadata: Signal<ServicesListServiceConfig["pagingMetadata"]>;
|
|
46
|
+
/** Reactive signal indicating if services are currently being loaded */
|
|
47
|
+
isLoading: Signal<boolean>;
|
|
48
|
+
/** Reactive signal containing any error message, or null if no error*/
|
|
49
|
+
error: Signal<string | null>;
|
|
50
|
+
/** Reactive signal containing the current sort configuration */
|
|
51
|
+
sort: Signal<{
|
|
52
|
+
fieldName: string;
|
|
53
|
+
order: "ASC" | "DESC";
|
|
54
|
+
}[]>;
|
|
55
|
+
/** Reactive signal containing the current filter configuration */
|
|
56
|
+
filters: Signal<Record<string, any>>;
|
|
57
|
+
/** Function to update sort configuration */
|
|
58
|
+
setSort: (sort: {
|
|
59
|
+
fieldName: string;
|
|
60
|
+
order: "ASC" | "DESC";
|
|
61
|
+
}[]) => void;
|
|
62
|
+
/** Function to update filter configuration */
|
|
63
|
+
setFilter: (filter: Record<string, any>) => void;
|
|
64
|
+
/** Function to reset filter configuration */
|
|
65
|
+
resetFilter: () => void;
|
|
66
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
67
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
68
|
+
/** Function to load more services */
|
|
69
|
+
loadMore: (count: number) => void;
|
|
70
|
+
/** Reactive signal indicating if there are more services to load */
|
|
71
|
+
hasMoreServices: ReadOnlySignal<boolean>;
|
|
72
|
+
};
|
|
73
|
+
__config: ServicesListServiceConfig;
|
|
74
|
+
isServiceDefinition?: boolean;
|
|
75
|
+
} & {
|
|
76
|
+
/** Reactive signal containing the list of services */
|
|
77
|
+
services: Signal<services.Service[]>;
|
|
78
|
+
/** Reactive signal containing pagination metadata */
|
|
79
|
+
pagingMetadata: Signal<ServicesListServiceConfig["pagingMetadata"]>;
|
|
80
|
+
/** Reactive signal indicating if services are currently being loaded */
|
|
81
|
+
isLoading: Signal<boolean>;
|
|
82
|
+
/** Reactive signal containing any error message, or null if no error*/
|
|
83
|
+
error: Signal<string | null>;
|
|
84
|
+
/** Reactive signal containing the current sort configuration */
|
|
85
|
+
sort: Signal<{
|
|
86
|
+
fieldName: string;
|
|
87
|
+
order: "ASC" | "DESC";
|
|
88
|
+
}[]>;
|
|
89
|
+
/** Reactive signal containing the current filter configuration */
|
|
90
|
+
filters: Signal<Record<string, any>>;
|
|
91
|
+
/** Function to update sort configuration */
|
|
92
|
+
setSort: (sort: {
|
|
93
|
+
fieldName: string;
|
|
94
|
+
order: "ASC" | "DESC";
|
|
95
|
+
}[]) => void;
|
|
96
|
+
/** Function to update filter configuration */
|
|
97
|
+
setFilter: (filter: Record<string, any>) => void;
|
|
98
|
+
/** Function to reset filter configuration */
|
|
99
|
+
resetFilter: () => void;
|
|
100
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
101
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
102
|
+
/** Function to load more services */
|
|
103
|
+
loadMore: (count: number) => void;
|
|
104
|
+
/** Reactive signal indicating if there are more services to load */
|
|
105
|
+
hasMoreServices: ReadOnlySignal<boolean>;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Implementation of the Services List service that manages reactive services data.
|
|
109
|
+
* This service provides signals for services data, search options, pagination,
|
|
110
|
+
* loading state, and error handling.
|
|
111
|
+
*/
|
|
112
|
+
export declare const ServicesListService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
113
|
+
__api: {
|
|
114
|
+
/** Reactive signal containing the list of services */
|
|
115
|
+
services: Signal<services.Service[]>;
|
|
116
|
+
/** Reactive signal containing pagination metadata */
|
|
117
|
+
pagingMetadata: Signal<ServicesListServiceConfig["pagingMetadata"]>;
|
|
118
|
+
/** Reactive signal indicating if services are currently being loaded */
|
|
119
|
+
isLoading: Signal<boolean>;
|
|
120
|
+
/** Reactive signal containing any error message, or null if no error*/
|
|
121
|
+
error: Signal<string | null>;
|
|
122
|
+
/** Reactive signal containing the current sort configuration */
|
|
123
|
+
sort: Signal<{
|
|
124
|
+
fieldName: string;
|
|
125
|
+
order: "ASC" | "DESC";
|
|
126
|
+
}[]>;
|
|
127
|
+
/** Reactive signal containing the current filter configuration */
|
|
128
|
+
filters: Signal<Record<string, any>>;
|
|
129
|
+
/** Function to update sort configuration */
|
|
130
|
+
setSort: (sort: {
|
|
131
|
+
fieldName: string;
|
|
132
|
+
order: "ASC" | "DESC";
|
|
133
|
+
}[]) => void;
|
|
134
|
+
/** Function to update filter configuration */
|
|
135
|
+
setFilter: (filter: Record<string, any>) => void;
|
|
136
|
+
/** Function to reset filter configuration */
|
|
137
|
+
resetFilter: () => void;
|
|
138
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
139
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
140
|
+
/** Function to load more services */
|
|
141
|
+
loadMore: (count: number) => void;
|
|
142
|
+
/** Reactive signal indicating if there are more services to load */
|
|
143
|
+
hasMoreServices: ReadOnlySignal<boolean>;
|
|
144
|
+
};
|
|
145
|
+
__config: ServicesListServiceConfig;
|
|
146
|
+
isServiceDefinition?: boolean;
|
|
147
|
+
} & {
|
|
148
|
+
/** Reactive signal containing the list of services */
|
|
149
|
+
services: Signal<services.Service[]>;
|
|
150
|
+
/** Reactive signal containing pagination metadata */
|
|
151
|
+
pagingMetadata: Signal<ServicesListServiceConfig["pagingMetadata"]>;
|
|
152
|
+
/** Reactive signal indicating if services are currently being loaded */
|
|
153
|
+
isLoading: Signal<boolean>;
|
|
154
|
+
/** Reactive signal containing any error message, or null if no error*/
|
|
155
|
+
error: Signal<string | null>;
|
|
156
|
+
/** Reactive signal containing the current sort configuration */
|
|
157
|
+
sort: Signal<{
|
|
158
|
+
fieldName: string;
|
|
159
|
+
order: "ASC" | "DESC";
|
|
160
|
+
}[]>;
|
|
161
|
+
/** Reactive signal containing the current filter configuration */
|
|
162
|
+
filters: Signal<Record<string, any>>;
|
|
163
|
+
/** Function to update sort configuration */
|
|
164
|
+
setSort: (sort: {
|
|
165
|
+
fieldName: string;
|
|
166
|
+
order: "ASC" | "DESC";
|
|
167
|
+
}[]) => void;
|
|
168
|
+
/** Function to update filter configuration */
|
|
169
|
+
setFilter: (filter: Record<string, any>) => void;
|
|
170
|
+
/** Function to reset filter configuration */
|
|
171
|
+
resetFilter: () => void;
|
|
172
|
+
/** Reactive signal indicating if any filters are currently applied */
|
|
173
|
+
isFiltered: () => ReadOnlySignal<boolean>;
|
|
174
|
+
/** Function to load more services */
|
|
175
|
+
loadMore: (count: number) => void;
|
|
176
|
+
/** Reactive signal indicating if there are more services to load */
|
|
177
|
+
hasMoreServices: ReadOnlySignal<boolean>;
|
|
178
|
+
}, ServicesListServiceConfig>;
|
|
179
|
+
/**
|
|
180
|
+
* Loads services list service configuration from the Wix Bookings API for SSR initialization.
|
|
181
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
182
|
+
* a list of services based on search criteria.
|
|
183
|
+
*/
|
|
184
|
+
export declare function loadServicesListServiceConfig(searchOptions?: ServicesListServiceConfig['searchOptions']): Promise<ServicesListServiceConfig>;
|
|
@@ -0,0 +1,168 @@
|
|
|
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
|
+
export const DEFAULT_QUERY_LIMIT = 100;
|
|
5
|
+
/**
|
|
6
|
+
* Fetches services using the Wix Bookings API.
|
|
7
|
+
* This function handles pagination and returns both services and metadata.
|
|
8
|
+
*
|
|
9
|
+
* @param searchOptions - The search options for querying services
|
|
10
|
+
* @returns Promise that resolves to the search result
|
|
11
|
+
*/
|
|
12
|
+
const fetchServices = async (searchOptions = {}) => {
|
|
13
|
+
try {
|
|
14
|
+
let query = services.queryServices();
|
|
15
|
+
// Apply pagination
|
|
16
|
+
if (searchOptions.cursorPaging?.limit) {
|
|
17
|
+
query = query.limit(searchOptions.cursorPaging.limit);
|
|
18
|
+
}
|
|
19
|
+
// Apply sorting
|
|
20
|
+
if (searchOptions.sort?.length) {
|
|
21
|
+
const { order, fieldName } = searchOptions.sort[0];
|
|
22
|
+
if (order === 'ASC') {
|
|
23
|
+
query = query.ascending(fieldName);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
query = query.descending(fieldName);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const result = await query.find();
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error('Error fetching services:', error);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Service definition for the Services List service.
|
|
39
|
+
* This defines the reactive API contract for managing a list of services with search, pagination, and filtering capabilities.
|
|
40
|
+
*
|
|
41
|
+
* @constant
|
|
42
|
+
*/
|
|
43
|
+
export const ServicesListServiceDefinition = defineService('services-list');
|
|
44
|
+
/**
|
|
45
|
+
* Implementation of the Services List service that manages reactive services data.
|
|
46
|
+
* This service provides signals for services data, search options, pagination,
|
|
47
|
+
* loading state, and error handling.
|
|
48
|
+
*/
|
|
49
|
+
export const ServicesListService = implementService.withConfig()(ServicesListServiceDefinition, ({ getService, config }) => {
|
|
50
|
+
let firstRun = true;
|
|
51
|
+
const signalsService = getService(SignalsServiceDefinition);
|
|
52
|
+
const servicesSignal = signalsService.signal(config.services);
|
|
53
|
+
const pagingMetadataSignal = signalsService.signal(config.pagingMetadata || { count: 0 });
|
|
54
|
+
const isLoadingSignal = signalsService.signal(false);
|
|
55
|
+
const errorSignal = signalsService.signal(null);
|
|
56
|
+
const sortSignal = signalsService.signal(config.searchOptions?.sort || []);
|
|
57
|
+
const filtersSignal = signalsService.signal(config.searchOptions?.filter || {});
|
|
58
|
+
if (typeof window !== 'undefined') {
|
|
59
|
+
signalsService.effect(async () => {
|
|
60
|
+
// Read signals to establish dependencies
|
|
61
|
+
const sort = sortSignal.get();
|
|
62
|
+
const filters = filtersSignal.get();
|
|
63
|
+
if (firstRun) {
|
|
64
|
+
firstRun = false;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
isLoadingSignal.set(true);
|
|
69
|
+
const result = await fetchServices({
|
|
70
|
+
cursorPaging: { limit: DEFAULT_QUERY_LIMIT },
|
|
71
|
+
sort,
|
|
72
|
+
filter: filters,
|
|
73
|
+
});
|
|
74
|
+
servicesSignal.set(result.items);
|
|
75
|
+
pagingMetadataSignal.set({
|
|
76
|
+
count: result.totalCount || 0,
|
|
77
|
+
cursors: {
|
|
78
|
+
next: result.next,
|
|
79
|
+
prev: result.prev,
|
|
80
|
+
},
|
|
81
|
+
hasNext: result.hasNext(),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
errorSignal.set(error instanceof Error ? error.message : 'Unknown error');
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
isLoadingSignal.set(false);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
firstRun = false;
|
|
93
|
+
const loadMoreServices = async () => {
|
|
94
|
+
try {
|
|
95
|
+
isLoadingSignal.set(true);
|
|
96
|
+
const result = await pagingMetadataSignal?.peek()?.cursors?.next?.();
|
|
97
|
+
servicesSignal.set([
|
|
98
|
+
...servicesSignal.peek(),
|
|
99
|
+
...(result?.items ?? []),
|
|
100
|
+
]);
|
|
101
|
+
pagingMetadataSignal.set({
|
|
102
|
+
count: result?.totalCount || 0,
|
|
103
|
+
cursors: {
|
|
104
|
+
next: result?.next,
|
|
105
|
+
prev: result?.prev,
|
|
106
|
+
},
|
|
107
|
+
hasNext: result?.hasNext(),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
errorSignal.set(error instanceof Error ? error.message : 'Unknown error');
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
isLoadingSignal.set(false);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
services: servicesSignal,
|
|
119
|
+
pagingMetadata: pagingMetadataSignal,
|
|
120
|
+
isLoading: isLoadingSignal,
|
|
121
|
+
error: errorSignal,
|
|
122
|
+
sort: sortSignal,
|
|
123
|
+
filters: filtersSignal,
|
|
124
|
+
setSort: (sort) => {
|
|
125
|
+
sortSignal.set(sort);
|
|
126
|
+
},
|
|
127
|
+
setFilter: (filter) => {
|
|
128
|
+
filtersSignal.set(filter);
|
|
129
|
+
},
|
|
130
|
+
resetFilter: () => {
|
|
131
|
+
filtersSignal.set({});
|
|
132
|
+
},
|
|
133
|
+
isFiltered: () => {
|
|
134
|
+
return signalsService.computed(() => {
|
|
135
|
+
const filters = filtersSignal.peek();
|
|
136
|
+
return Object.keys(filters).length > 0;
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
loadMore: loadMoreServices,
|
|
140
|
+
hasMoreServices: signalsService.computed(() => pagingMetadataSignal.get()?.hasNext ?? false),
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
/**
|
|
144
|
+
* Loads services list service configuration from the Wix Bookings API for SSR initialization.
|
|
145
|
+
* This function is designed to be used during Server-Side Rendering (SSR) to preload
|
|
146
|
+
* a list of services based on search criteria.
|
|
147
|
+
*/
|
|
148
|
+
export async function loadServicesListServiceConfig(searchOptions) {
|
|
149
|
+
try {
|
|
150
|
+
const result = await fetchServices(searchOptions);
|
|
151
|
+
return {
|
|
152
|
+
services: result.items ?? [],
|
|
153
|
+
searchOptions,
|
|
154
|
+
pagingMetadata: {
|
|
155
|
+
count: result.totalCount ?? 0,
|
|
156
|
+
cursors: {
|
|
157
|
+
next: result.next,
|
|
158
|
+
prev: result.prev,
|
|
159
|
+
},
|
|
160
|
+
hasNext: result.hasNext(),
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
console.error('Error loading services configuration:', error);
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|