@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,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
|
+
}
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ServicesListServiceConfig } from '../services/services-list-service.js';
|
|
3
|
+
import { services } from '@wix/bookings';
|
|
4
|
+
/**
|
|
5
|
+
* Props for the ServiceList root component following the documented API
|
|
6
|
+
*/
|
|
7
|
+
export interface ServiceListRootProps {
|
|
8
|
+
children: ((props: {
|
|
9
|
+
services: services.Service[];
|
|
10
|
+
}) => React.ReactNode) | React.ReactNode;
|
|
11
|
+
services?: services.Service[];
|
|
12
|
+
servicesListConfig?: ServicesListServiceConfig;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Root component that provides the ServiceList context for rendering service lists.
|
|
17
|
+
* This component manages the service data and provides it to child components through context.
|
|
18
|
+
*/
|
|
19
|
+
export declare const List: React.ForwardRefExoticComponent<ServiceListRootProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
export interface ServiceOptionsProps {
|
|
21
|
+
children: ((props: {
|
|
22
|
+
services: services.Service[];
|
|
23
|
+
}) => React.ReactNode) | React.ReactNode;
|
|
24
|
+
emptyState?: React.ReactNode;
|
|
25
|
+
infiniteScroll?: boolean;
|
|
26
|
+
pageSize?: number;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare const Options: React.ForwardRefExoticComponent<ServiceOptionsProps & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
+
export interface ServiceRepeaterProps {
|
|
31
|
+
children: ((props: {
|
|
32
|
+
service: services.Service;
|
|
33
|
+
}) => React.ReactNode) | React.ReactNode;
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const ServiceRepeater: React.ForwardRefExoticComponent<ServiceRepeaterProps & React.RefAttributes<HTMLDivElement>>;
|
|
37
|
+
export interface RawProps {
|
|
38
|
+
children: ((props: {
|
|
39
|
+
totalServices: number;
|
|
40
|
+
displayedServices: number;
|
|
41
|
+
isFiltered: boolean;
|
|
42
|
+
}) => React.ReactNode) | React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
export declare const Raw: React.ForwardRefExoticComponent<RawProps & React.RefAttributes<HTMLDivElement>>;
|
|
45
|
+
export interface ErrorProps {
|
|
46
|
+
asChild?: boolean;
|
|
47
|
+
children?: React.ReactNode;
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare const Error: React.ForwardRefExoticComponent<ErrorProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useService } from '@wix/services-manager-react';
|
|
4
|
+
import { TestIds } from './test-ids.js';
|
|
5
|
+
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
6
|
+
import { Root as CoreServiceListRoot, Error as CoreServiceListError, } from './core/ServiceList.js';
|
|
7
|
+
import { Root as CoreServiceRoot } from './core/Service.js';
|
|
8
|
+
import { ServicesListServiceDefinition, } from '../services/services-list-service.js';
|
|
9
|
+
/**
|
|
10
|
+
* Root component that provides the ServiceList context for rendering service lists.
|
|
11
|
+
* This component manages the service data and provides it to child components through context.
|
|
12
|
+
*/
|
|
13
|
+
export const List = React.forwardRef((props, ref) => {
|
|
14
|
+
const { children, services = [], servicesListConfig, className } = props;
|
|
15
|
+
const serviceConfig = servicesListConfig || {
|
|
16
|
+
services: services,
|
|
17
|
+
searchOptions: {
|
|
18
|
+
cursorPaging: { limit: 10 },
|
|
19
|
+
},
|
|
20
|
+
pagingMetadata: {
|
|
21
|
+
count: services?.length || 0,
|
|
22
|
+
},
|
|
23
|
+
aggregations: {
|
|
24
|
+
results: [],
|
|
25
|
+
},
|
|
26
|
+
customizations: [],
|
|
27
|
+
};
|
|
28
|
+
return (_jsx(CoreServiceListRoot, { servicesListConfig: serviceConfig, children: _jsx(ListContent, { children: children, className: className, ref: ref }) }));
|
|
29
|
+
});
|
|
30
|
+
List.displayName = 'Services.List';
|
|
31
|
+
const ListContent = React.forwardRef((props, ref) => {
|
|
32
|
+
const { children, className } = props;
|
|
33
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
34
|
+
const services = servicesListService.services.get();
|
|
35
|
+
const pagingMetadata = servicesListService.pagingMetadata.get();
|
|
36
|
+
const displayedServices = services.length;
|
|
37
|
+
const totalServices = pagingMetadata?.count || services.length;
|
|
38
|
+
const isFiltered = Object.keys(servicesListService.filters.get()).length > 0;
|
|
39
|
+
const attributes = {
|
|
40
|
+
'data-testid': TestIds.servicesList,
|
|
41
|
+
'data-total-services': totalServices,
|
|
42
|
+
'data-displayed-services': displayedServices,
|
|
43
|
+
'data-filtered': isFiltered,
|
|
44
|
+
className,
|
|
45
|
+
};
|
|
46
|
+
return (_jsx("div", { ...attributes, ref: ref, children: typeof children === 'function' ? children({ services }) : children }));
|
|
47
|
+
});
|
|
48
|
+
export const Options = React.forwardRef((props, ref) => {
|
|
49
|
+
const { children, emptyState, infiniteScroll = true, pageSize = 0, className, } = props;
|
|
50
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
51
|
+
const services = servicesListService.services.get();
|
|
52
|
+
const hasServices = services.length > 0;
|
|
53
|
+
if (!hasServices) {
|
|
54
|
+
return emptyState || null;
|
|
55
|
+
}
|
|
56
|
+
const attributes = {
|
|
57
|
+
'data-testid': TestIds.servicesOptions,
|
|
58
|
+
'data-empty': !hasServices,
|
|
59
|
+
'data-infinite-scroll': infiniteScroll,
|
|
60
|
+
'data-page-size': pageSize,
|
|
61
|
+
className,
|
|
62
|
+
};
|
|
63
|
+
return (_jsx("div", { ...attributes, ref: ref, children: typeof children === 'function' ? children({ services }) : children }));
|
|
64
|
+
});
|
|
65
|
+
Options.displayName = 'Services.Options';
|
|
66
|
+
export const ServiceRepeater = React.forwardRef((props, _ref) => {
|
|
67
|
+
const { children, className } = props;
|
|
68
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
69
|
+
const services = servicesListService.services.get();
|
|
70
|
+
const hasServices = services.length > 0;
|
|
71
|
+
if (!hasServices)
|
|
72
|
+
return null;
|
|
73
|
+
return (_jsx(_Fragment, { children: services.map((service) => (_jsx(CoreServiceRoot, { serviceConfig: { service }, "data-testid": TestIds.serviceRepeater, "data-service-id": service._id, className: className, children: typeof children === 'function' ? children({ service }) : children }, service._id))) }));
|
|
74
|
+
});
|
|
75
|
+
ServiceRepeater.displayName = 'Services.ServiceRepeater';
|
|
76
|
+
export const Raw = React.forwardRef((props, ref) => {
|
|
77
|
+
const { children } = props;
|
|
78
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
79
|
+
const services = servicesListService.services.get();
|
|
80
|
+
const pagingMetadata = servicesListService.pagingMetadata.get();
|
|
81
|
+
const displayedServices = services.length;
|
|
82
|
+
const totalServices = pagingMetadata?.count || services.length;
|
|
83
|
+
const isFiltered = Object.keys(servicesListService.filters.get()).length > 0;
|
|
84
|
+
return (_jsx("div", { ref: ref, children: typeof children === 'function'
|
|
85
|
+
? children({ totalServices, displayedServices, isFiltered })
|
|
86
|
+
: children }));
|
|
87
|
+
});
|
|
88
|
+
Raw.displayName = 'Services.Raw';
|
|
89
|
+
export const Error = React.forwardRef((props, ref) => {
|
|
90
|
+
const { asChild, children, className, ...otherProps } = props;
|
|
91
|
+
return (_jsx(CoreServiceListError, { children: ({ error }) => {
|
|
92
|
+
if (!error) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.serviceError, "data-error": error, customElement: children, customElementProps: {
|
|
96
|
+
error,
|
|
97
|
+
}, content: error, ...otherProps, children: _jsx("div", { className: "text-status-error text-sm sm:text-base", children: error }) }));
|
|
98
|
+
} }));
|
|
99
|
+
});
|
|
100
|
+
Error.displayName = 'Services.Error';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Sort as SortPrimitive } from '@wix/headless-components/react';
|
|
3
|
+
export interface ServiceListSortProps {
|
|
4
|
+
children: (props: {
|
|
5
|
+
currentSort: {
|
|
6
|
+
fieldName: string;
|
|
7
|
+
order: 'ASC' | 'DESC';
|
|
8
|
+
}[];
|
|
9
|
+
sortOptions: SortPrimitive.SortOption[];
|
|
10
|
+
setSort: (sort: {
|
|
11
|
+
fieldName: string;
|
|
12
|
+
order: 'ASC' | 'DESC';
|
|
13
|
+
}[]) => void;
|
|
14
|
+
}) => React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export declare const ServiceListSort: (props: ServiceListSortProps) => React.ReactNode;
|
|
17
|
+
export interface ServiceListSeparateSortProps {
|
|
18
|
+
children: (props: {
|
|
19
|
+
currentSort: {
|
|
20
|
+
fieldName: string;
|
|
21
|
+
order: 'ASC' | 'DESC';
|
|
22
|
+
}[];
|
|
23
|
+
sortFieldOptions: Array<{
|
|
24
|
+
fieldName: string;
|
|
25
|
+
label: string;
|
|
26
|
+
}>;
|
|
27
|
+
sortOrderOptions: Array<{
|
|
28
|
+
order: 'ASC' | 'DESC';
|
|
29
|
+
label: string;
|
|
30
|
+
}>;
|
|
31
|
+
setSort: (sort: {
|
|
32
|
+
fieldName: string;
|
|
33
|
+
order: 'ASC' | 'DESC';
|
|
34
|
+
}[]) => void;
|
|
35
|
+
}) => React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
export declare function ServiceListSeparateSort(props: ServiceListSeparateSortProps): React.ReactNode;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useService } from '@wix/services-manager-react';
|
|
2
|
+
import { ServicesListServiceDefinition } from '../services/services-list-service.js';
|
|
3
|
+
export const ServiceListSort = (props) => {
|
|
4
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
5
|
+
const currentSort = servicesListService.sort.get();
|
|
6
|
+
// Define sort options
|
|
7
|
+
const sortOptions = [
|
|
8
|
+
{ fieldName: 'name', order: 'ASC', label: 'Name (A-Z)' },
|
|
9
|
+
{ fieldName: 'name', order: 'DESC', label: 'Name (Z-A)' },
|
|
10
|
+
];
|
|
11
|
+
return props.children({
|
|
12
|
+
currentSort,
|
|
13
|
+
sortOptions,
|
|
14
|
+
setSort: (sort) => {
|
|
15
|
+
servicesListService.setSort(sort);
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
export function ServiceListSeparateSort(props) {
|
|
20
|
+
const servicesListService = useService(ServicesListServiceDefinition);
|
|
21
|
+
const currentSort = servicesListService.sort.get();
|
|
22
|
+
const sortFieldOptions = [{ fieldName: 'name', label: 'Name' }];
|
|
23
|
+
const sortOrderOptions = [
|
|
24
|
+
{ order: 'ASC', label: 'Ascending' },
|
|
25
|
+
{ order: 'DESC', label: 'Descending' },
|
|
26
|
+
];
|
|
27
|
+
return props.children({
|
|
28
|
+
currentSort,
|
|
29
|
+
sortFieldOptions,
|
|
30
|
+
sortOrderOptions,
|
|
31
|
+
setSort: (sort) => {
|
|
32
|
+
servicesListService.setSort(sort);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { services } from '@wix/bookings';
|
|
3
|
+
import { type ServiceServiceConfig } from '../../services/service-service.js';
|
|
4
|
+
export interface RootProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
serviceConfig: ServiceServiceConfig;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ServiceNameProps {
|
|
10
|
+
children: (props: ServiceNameRenderProps) => React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export interface ServiceNameRenderProps {
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ServiceDescriptionProps {
|
|
16
|
+
children: (props: ServiceDescriptionRenderProps) => React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export interface ServiceDescriptionRenderProps {
|
|
19
|
+
description: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface ServicePriceProps {
|
|
22
|
+
children: (props: ServicePriceRenderProps) => React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export interface ServicePriceRenderProps {
|
|
25
|
+
price: {
|
|
26
|
+
value: number;
|
|
27
|
+
currency: string;
|
|
28
|
+
} | null;
|
|
29
|
+
}
|
|
30
|
+
export interface ServiceImageRenderProps {
|
|
31
|
+
image: string | null;
|
|
32
|
+
alt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ServiceCategoryProps {
|
|
35
|
+
children: (props: ServiceCategoryRenderProps) => React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
export interface ServiceCategoryRenderProps {
|
|
38
|
+
category: {
|
|
39
|
+
name: string;
|
|
40
|
+
} | null;
|
|
41
|
+
}
|
|
42
|
+
export interface ServiceLoadingProps {
|
|
43
|
+
children: (props: ServiceLoadingRenderProps) => React.ReactNode;
|
|
44
|
+
}
|
|
45
|
+
export interface ServiceLoadingRenderProps {
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ServiceContentProps {
|
|
49
|
+
children: (props: ServiceContentRenderProps) => React.ReactNode;
|
|
50
|
+
}
|
|
51
|
+
export interface ServiceContentRenderProps {
|
|
52
|
+
service: services.Service;
|
|
53
|
+
}
|
|
54
|
+
declare function Content(props: ServiceContentProps): React.ReactNode;
|
|
55
|
+
declare namespace Content {
|
|
56
|
+
var displayName: string;
|
|
57
|
+
}
|
|
58
|
+
declare function Loading(props: ServiceLoadingProps): React.ReactNode;
|
|
59
|
+
declare namespace Loading {
|
|
60
|
+
var displayName: string;
|
|
61
|
+
}
|
|
62
|
+
export declare function Name(props: ServiceNameProps): React.ReactNode;
|
|
63
|
+
export declare namespace Name {
|
|
64
|
+
var displayName: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function Description(props: ServiceDescriptionProps): React.ReactNode;
|
|
67
|
+
export declare namespace Description {
|
|
68
|
+
var displayName: string;
|
|
69
|
+
}
|
|
70
|
+
export declare function Price(props: ServicePriceProps): React.ReactNode;
|
|
71
|
+
export declare namespace Price {
|
|
72
|
+
var displayName: string;
|
|
73
|
+
}
|
|
74
|
+
export declare function Image(): import("react/jsx-runtime").JSX.Element | null;
|
|
75
|
+
export declare namespace Image {
|
|
76
|
+
var displayName: string;
|
|
77
|
+
}
|
|
78
|
+
export declare function Root(props: RootProps): import("react/jsx-runtime").JSX.Element;
|
|
79
|
+
export declare namespace Root {
|
|
80
|
+
var displayName: string;
|
|
81
|
+
}
|
|
82
|
+
export declare const Service: {
|
|
83
|
+
Root: typeof Root;
|
|
84
|
+
Content: typeof Content;
|
|
85
|
+
Loading: typeof Loading;
|
|
86
|
+
Name: typeof Name;
|
|
87
|
+
Description: typeof Description;
|
|
88
|
+
Price: typeof Price;
|
|
89
|
+
Image: typeof Image;
|
|
90
|
+
};
|
|
91
|
+
export {};
|