@wix/headless-bookings 0.0.9 → 0.0.10
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/core/booking/Booking.d.ts +4 -4
- package/cjs/dist/react/core/booking/Booking.js +3 -3
- package/cjs/dist/services/booking/booking.d.ts +50 -33
- package/cjs/dist/services/booking/booking.js +72 -38
- package/cjs/dist/services/index.d.ts +1 -1
- package/cjs/dist/services/index.js +1 -1
- package/cjs/dist/services/service/service.js +9 -10
- package/dist/react/core/booking/Booking.d.ts +4 -4
- package/dist/react/core/booking/Booking.js +3 -3
- package/dist/services/booking/booking.d.ts +50 -33
- package/dist/services/booking/booking.js +72 -38
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/service/service.js +9 -10
- package/package.json +3 -2
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Provides low-level access to BookingService via render props and service setup
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react';
|
|
6
|
-
import { type BookingServiceConfig } from '../../../services/booking/booking.js';
|
|
7
|
-
import type {
|
|
6
|
+
import { type BookingServiceConfig, type ServiceSelection } from '../../../services/booking/booking.js';
|
|
7
|
+
import type { availabilityTimeSlots } from '@wix/bookings';
|
|
8
8
|
/**
|
|
9
9
|
* Props for Booking.Root component
|
|
10
10
|
*/
|
|
@@ -33,7 +33,7 @@ export declare function Root(props: RootProps): React.ReactNode;
|
|
|
33
33
|
*/
|
|
34
34
|
export interface DataProps {
|
|
35
35
|
children: (data: {
|
|
36
|
-
selectedServices:
|
|
36
|
+
selectedServices: ServiceSelection[];
|
|
37
37
|
selectedTimeSlot: availabilityTimeSlots.TimeSlot | null;
|
|
38
38
|
}) => React.ReactNode;
|
|
39
39
|
}
|
|
@@ -47,7 +47,7 @@ export interface DataProps {
|
|
|
47
47
|
* <Booking.Data>
|
|
48
48
|
* {({ selectedServices }) => (
|
|
49
49
|
* selectedServices.length > 0 ? (
|
|
50
|
-
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
50
|
+
* <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
|
|
51
51
|
* ) : (
|
|
52
52
|
* <div>No services selected</div>
|
|
53
53
|
* )
|
|
@@ -30,7 +30,7 @@ export function Root(props) {
|
|
|
30
30
|
* <Booking.Data>
|
|
31
31
|
* {({ selectedServices }) => (
|
|
32
32
|
* selectedServices.length > 0 ? (
|
|
33
|
-
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
33
|
+
* <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
|
|
34
34
|
* ) : (
|
|
35
35
|
* <div>No services selected</div>
|
|
36
36
|
* )
|
|
@@ -41,8 +41,8 @@ export function Root(props) {
|
|
|
41
41
|
export function Data(props) {
|
|
42
42
|
const { children } = props;
|
|
43
43
|
const bookingService = useService(BookingServiceDefinition);
|
|
44
|
-
const selectedServices = bookingService.
|
|
45
|
-
const selectedTimeSlot = bookingService.
|
|
44
|
+
const selectedServices = bookingService.services.get();
|
|
45
|
+
const selectedTimeSlot = bookingService.timeSlot.get();
|
|
46
46
|
return children({
|
|
47
47
|
selectedServices,
|
|
48
48
|
selectedTimeSlot,
|
|
@@ -1,19 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Booking Service - Global booking store
|
|
3
|
-
* Manages booking flow state (selected
|
|
3
|
+
* Manages booking flow state (selected services, time slot, location, form values)
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
7
7
|
import type { services, availabilityTimeSlots } from '@wix/bookings';
|
|
8
|
+
import type { FormValues } from '@wix/form-public';
|
|
9
|
+
/**
|
|
10
|
+
* ServiceSelection contains the service AND its related selections
|
|
11
|
+
*/
|
|
12
|
+
export interface ServiceSelection {
|
|
13
|
+
service: services.Service;
|
|
14
|
+
/** Selected resources (staff members, rooms, etc.) */
|
|
15
|
+
resources?: availabilityTimeSlots.Resource[];
|
|
16
|
+
}
|
|
17
|
+
export interface Location {
|
|
18
|
+
id: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* BookingService actions - setters only, no API calls
|
|
23
|
+
*/
|
|
24
|
+
export interface BookingServiceActions {
|
|
25
|
+
setServices(services: ServiceSelection[]): void;
|
|
26
|
+
addService(service: ServiceSelection): void;
|
|
27
|
+
updateService(serviceId: string, updates: Partial<ServiceSelection>): void;
|
|
28
|
+
removeService(serviceId: string): void;
|
|
29
|
+
clearServices(): void;
|
|
30
|
+
setTimeSlot(slot: availabilityTimeSlots.TimeSlot | null): void;
|
|
31
|
+
clearTimeSlot(): void;
|
|
32
|
+
setLocation(location: Location | null): void;
|
|
33
|
+
clearLocation(): void;
|
|
34
|
+
setFormValues(values: FormValues | null): void;
|
|
35
|
+
clearFormValues(): void;
|
|
36
|
+
clearAll(): void;
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* Booking Service interface
|
|
10
|
-
*
|
|
40
|
+
* Pure state management - no API calls
|
|
11
41
|
*/
|
|
12
42
|
export interface BookingService {
|
|
13
|
-
/** Signal containing the currently selected services
|
|
14
|
-
|
|
43
|
+
/** Signal containing the currently selected services with their selections */
|
|
44
|
+
services: Signal<ServiceSelection[]>;
|
|
15
45
|
/** Signal containing the currently selected time slot */
|
|
16
|
-
|
|
46
|
+
timeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
|
|
47
|
+
/** Signal containing the selected location (derived from timeSlot) */
|
|
48
|
+
location: Signal<Location | null>;
|
|
49
|
+
/** Signal containing the form values */
|
|
50
|
+
formValues: Signal<FormValues | null>;
|
|
51
|
+
/** Actions for modifying booking state */
|
|
52
|
+
actions: BookingServiceActions;
|
|
17
53
|
}
|
|
18
54
|
/**
|
|
19
55
|
* Service definition for Booking
|
|
@@ -25,12 +61,15 @@ export declare const BookingServiceDefinition: string & {
|
|
|
25
61
|
} & BookingService;
|
|
26
62
|
/**
|
|
27
63
|
* Configuration interface for BookingService
|
|
64
|
+
* Note: location is NOT in config - it's derived internally from timeSlot
|
|
28
65
|
*/
|
|
29
66
|
export interface BookingServiceConfig {
|
|
30
|
-
/** Optional initial services to pre-populate
|
|
31
|
-
initialServices?:
|
|
32
|
-
/** Optional initial time slot to pre-populate
|
|
67
|
+
/** Optional initial services to pre-populate */
|
|
68
|
+
initialServices?: ServiceSelection[];
|
|
69
|
+
/** Optional initial time slot to pre-populate */
|
|
33
70
|
initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
|
|
71
|
+
/** Optional initial form values */
|
|
72
|
+
initialFormValues?: FormValues | null;
|
|
34
73
|
}
|
|
35
74
|
/**
|
|
36
75
|
* Implementation of BookingService
|
|
@@ -44,20 +83,16 @@ export interface BookingServiceConfig {
|
|
|
44
83
|
* const bookingConfig = await loadBookingServiceConfig();
|
|
45
84
|
*
|
|
46
85
|
* // Wrap app with provider
|
|
47
|
-
* <Booking.Root
|
|
86
|
+
* <Booking.Root config={bookingConfig}>
|
|
48
87
|
* {children}
|
|
49
88
|
* </Booking.Root>
|
|
50
89
|
*
|
|
51
90
|
* // In any page - access booking data
|
|
52
91
|
* <Booking.Data>
|
|
53
|
-
* {({
|
|
54
|
-
* <div>{
|
|
92
|
+
* {({ services, timeSlot, location, formValues, actions }) => (
|
|
93
|
+
* <div>{services.map(s => s.service.name).join(', ')}</div>
|
|
55
94
|
* )}
|
|
56
95
|
* </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
96
|
* ```
|
|
62
97
|
*/
|
|
63
98
|
export declare const BookingService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
@@ -65,21 +100,3 @@ export declare const BookingService: import("@wix/services-definitions").Service
|
|
|
65
100
|
__config: {};
|
|
66
101
|
isServiceDefinition?: boolean;
|
|
67
102
|
} & 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>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Booking Service - Global booking store
|
|
3
|
-
* Manages booking flow state (selected
|
|
3
|
+
* Manages booking flow state (selected services, time slot, location, form values)
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
@@ -9,6 +9,9 @@ import { SignalsServiceDefinition, } from '@wix/services-definitions/core-servic
|
|
|
9
9
|
* Service definition for Booking
|
|
10
10
|
*/
|
|
11
11
|
export const BookingServiceDefinition = defineService('booking');
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Service Implementation
|
|
14
|
+
// ============================================================================
|
|
12
15
|
/**
|
|
13
16
|
* Implementation of BookingService
|
|
14
17
|
*
|
|
@@ -21,54 +24,85 @@ export const BookingServiceDefinition = defineService('booking');
|
|
|
21
24
|
* const bookingConfig = await loadBookingServiceConfig();
|
|
22
25
|
*
|
|
23
26
|
* // Wrap app with provider
|
|
24
|
-
* <Booking.Root
|
|
27
|
+
* <Booking.Root config={bookingConfig}>
|
|
25
28
|
* {children}
|
|
26
29
|
* </Booking.Root>
|
|
27
30
|
*
|
|
28
31
|
* // In any page - access booking data
|
|
29
32
|
* <Booking.Data>
|
|
30
|
-
* {({
|
|
31
|
-
* <div>{
|
|
33
|
+
* {({ services, timeSlot, location, formValues, actions }) => (
|
|
34
|
+
* <div>{services.map(s => s.service.name).join(', ')}</div>
|
|
32
35
|
* )}
|
|
33
36
|
* </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
37
|
* ```
|
|
39
38
|
*/
|
|
40
39
|
export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
|
|
41
40
|
const signalsService = getService(SignalsServiceDefinition);
|
|
42
|
-
// Initialize
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
// Initialize signals with config values
|
|
42
|
+
const servicesSignal = signalsService.signal(config.initialServices || []);
|
|
43
|
+
const timeSlotSignal = signalsService.signal(config.initialTimeSlot || null);
|
|
44
|
+
// Location is derived internally - initialize as null
|
|
45
|
+
const locationSignal = signalsService.signal(null);
|
|
46
|
+
const formValuesSignal = signalsService.signal(config.initialFormValues || null);
|
|
47
|
+
// ========================================================================
|
|
48
|
+
// Actions Implementation
|
|
49
|
+
// ========================================================================
|
|
50
|
+
const actions = {
|
|
51
|
+
// Services actions
|
|
52
|
+
setServices(newServices) {
|
|
53
|
+
servicesSignal.set(newServices);
|
|
54
|
+
},
|
|
55
|
+
addService(service) {
|
|
56
|
+
const current = servicesSignal.get();
|
|
57
|
+
servicesSignal.set([...current, service]);
|
|
58
|
+
},
|
|
59
|
+
updateService(serviceId, updates) {
|
|
60
|
+
const current = servicesSignal.get();
|
|
61
|
+
const updated = current.map((s) => s.service._id === serviceId ? { ...s, ...updates } : s);
|
|
62
|
+
servicesSignal.set(updated);
|
|
63
|
+
},
|
|
64
|
+
removeService(serviceId) {
|
|
65
|
+
const current = servicesSignal.get();
|
|
66
|
+
const filtered = current.filter((s) => s.service._id !== serviceId);
|
|
67
|
+
servicesSignal.set(filtered);
|
|
68
|
+
},
|
|
69
|
+
clearServices() {
|
|
70
|
+
servicesSignal.set([]);
|
|
71
|
+
},
|
|
72
|
+
// Time Slot actions
|
|
73
|
+
setTimeSlot(slot) {
|
|
74
|
+
timeSlotSignal.set(slot);
|
|
75
|
+
},
|
|
76
|
+
clearTimeSlot() {
|
|
77
|
+
timeSlotSignal.set(null);
|
|
78
|
+
},
|
|
79
|
+
// Location actions
|
|
80
|
+
setLocation(location) {
|
|
81
|
+
locationSignal.set(location);
|
|
82
|
+
},
|
|
83
|
+
clearLocation() {
|
|
84
|
+
locationSignal.set(null);
|
|
85
|
+
},
|
|
86
|
+
// Form Values actions
|
|
87
|
+
setFormValues(values) {
|
|
88
|
+
formValuesSignal.set(values);
|
|
89
|
+
},
|
|
90
|
+
clearFormValues() {
|
|
91
|
+
formValuesSignal.set(null);
|
|
92
|
+
},
|
|
93
|
+
// Clear all
|
|
94
|
+
clearAll() {
|
|
95
|
+
servicesSignal.set([]);
|
|
96
|
+
timeSlotSignal.set(null);
|
|
97
|
+
locationSignal.set(null);
|
|
98
|
+
formValuesSignal.set(null);
|
|
99
|
+
},
|
|
49
100
|
};
|
|
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
101
|
return {
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
services: servicesSignal,
|
|
103
|
+
timeSlot: timeSlotSignal,
|
|
104
|
+
location: locationSignal,
|
|
105
|
+
formValues: formValuesSignal,
|
|
106
|
+
actions,
|
|
73
107
|
};
|
|
74
|
-
}
|
|
108
|
+
});
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, loadServiceServiceConfig, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
|
-
export { BookingService, BookingServiceDefinition, type BookingServiceConfig,
|
|
6
|
+
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type ServiceSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, loadServiceServiceConfig, } from './service/service.js';
|
|
6
|
-
export { BookingService, BookingServiceDefinition,
|
|
6
|
+
export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
6
6
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
7
7
|
import { getServiceById, getServiceBySlug, } from '../../api/query-service/index.js';
|
|
8
|
-
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
8
|
+
import { BookingServiceDefinition, } from '../booking/booking.js';
|
|
9
9
|
/**
|
|
10
10
|
* Service definition for the Service service.
|
|
11
11
|
* This defines the contract that the ServiceService must implement.
|
|
@@ -73,21 +73,20 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
73
73
|
// Action methods for booking
|
|
74
74
|
const select = () => {
|
|
75
75
|
const currentService = service.get();
|
|
76
|
-
|
|
76
|
+
const selection = { service: currentService };
|
|
77
|
+
bookingService.services.set([selection]);
|
|
77
78
|
};
|
|
78
79
|
const add = () => {
|
|
79
80
|
const currentService = service.get();
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
currentService,
|
|
84
|
-
]);
|
|
81
|
+
const selections = bookingService.services.get();
|
|
82
|
+
const selection = { service: currentService };
|
|
83
|
+
bookingService.services.set([...selections, selection]);
|
|
85
84
|
};
|
|
86
85
|
const remove = () => {
|
|
87
86
|
const currentService = service.get();
|
|
88
|
-
const
|
|
89
|
-
const filtered =
|
|
90
|
-
bookingService.
|
|
87
|
+
const selections = bookingService.services.get();
|
|
88
|
+
const filtered = selections.filter((s) => s.service._id !== currentService._id);
|
|
89
|
+
bookingService.services.set(filtered);
|
|
91
90
|
};
|
|
92
91
|
return {
|
|
93
92
|
service,
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Provides low-level access to BookingService via render props and service setup
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react';
|
|
6
|
-
import { type BookingServiceConfig } from '../../../services/booking/booking.js';
|
|
7
|
-
import type {
|
|
6
|
+
import { type BookingServiceConfig, type ServiceSelection } from '../../../services/booking/booking.js';
|
|
7
|
+
import type { availabilityTimeSlots } from '@wix/bookings';
|
|
8
8
|
/**
|
|
9
9
|
* Props for Booking.Root component
|
|
10
10
|
*/
|
|
@@ -33,7 +33,7 @@ export declare function Root(props: RootProps): React.ReactNode;
|
|
|
33
33
|
*/
|
|
34
34
|
export interface DataProps {
|
|
35
35
|
children: (data: {
|
|
36
|
-
selectedServices:
|
|
36
|
+
selectedServices: ServiceSelection[];
|
|
37
37
|
selectedTimeSlot: availabilityTimeSlots.TimeSlot | null;
|
|
38
38
|
}) => React.ReactNode;
|
|
39
39
|
}
|
|
@@ -47,7 +47,7 @@ export interface DataProps {
|
|
|
47
47
|
* <Booking.Data>
|
|
48
48
|
* {({ selectedServices }) => (
|
|
49
49
|
* selectedServices.length > 0 ? (
|
|
50
|
-
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
50
|
+
* <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
|
|
51
51
|
* ) : (
|
|
52
52
|
* <div>No services selected</div>
|
|
53
53
|
* )
|
|
@@ -30,7 +30,7 @@ export function Root(props) {
|
|
|
30
30
|
* <Booking.Data>
|
|
31
31
|
* {({ selectedServices }) => (
|
|
32
32
|
* selectedServices.length > 0 ? (
|
|
33
|
-
* <div>{selectedServices.map(s => s.name).join(', ')}</div>
|
|
33
|
+
* <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
|
|
34
34
|
* ) : (
|
|
35
35
|
* <div>No services selected</div>
|
|
36
36
|
* )
|
|
@@ -41,8 +41,8 @@ export function Root(props) {
|
|
|
41
41
|
export function Data(props) {
|
|
42
42
|
const { children } = props;
|
|
43
43
|
const bookingService = useService(BookingServiceDefinition);
|
|
44
|
-
const selectedServices = bookingService.
|
|
45
|
-
const selectedTimeSlot = bookingService.
|
|
44
|
+
const selectedServices = bookingService.services.get();
|
|
45
|
+
const selectedTimeSlot = bookingService.timeSlot.get();
|
|
46
46
|
return children({
|
|
47
47
|
selectedServices,
|
|
48
48
|
selectedTimeSlot,
|
|
@@ -1,19 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Booking Service - Global booking store
|
|
3
|
-
* Manages booking flow state (selected
|
|
3
|
+
* Manages booking flow state (selected services, time slot, location, form values)
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { type Signal } from '@wix/services-definitions/core-services/signals';
|
|
7
7
|
import type { services, availabilityTimeSlots } from '@wix/bookings';
|
|
8
|
+
import type { FormValues } from '@wix/form-public';
|
|
9
|
+
/**
|
|
10
|
+
* ServiceSelection contains the service AND its related selections
|
|
11
|
+
*/
|
|
12
|
+
export interface ServiceSelection {
|
|
13
|
+
service: services.Service;
|
|
14
|
+
/** Selected resources (staff members, rooms, etc.) */
|
|
15
|
+
resources?: availabilityTimeSlots.Resource[];
|
|
16
|
+
}
|
|
17
|
+
export interface Location {
|
|
18
|
+
id: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* BookingService actions - setters only, no API calls
|
|
23
|
+
*/
|
|
24
|
+
export interface BookingServiceActions {
|
|
25
|
+
setServices(services: ServiceSelection[]): void;
|
|
26
|
+
addService(service: ServiceSelection): void;
|
|
27
|
+
updateService(serviceId: string, updates: Partial<ServiceSelection>): void;
|
|
28
|
+
removeService(serviceId: string): void;
|
|
29
|
+
clearServices(): void;
|
|
30
|
+
setTimeSlot(slot: availabilityTimeSlots.TimeSlot | null): void;
|
|
31
|
+
clearTimeSlot(): void;
|
|
32
|
+
setLocation(location: Location | null): void;
|
|
33
|
+
clearLocation(): void;
|
|
34
|
+
setFormValues(values: FormValues | null): void;
|
|
35
|
+
clearFormValues(): void;
|
|
36
|
+
clearAll(): void;
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* Booking Service interface
|
|
10
|
-
*
|
|
40
|
+
* Pure state management - no API calls
|
|
11
41
|
*/
|
|
12
42
|
export interface BookingService {
|
|
13
|
-
/** Signal containing the currently selected services
|
|
14
|
-
|
|
43
|
+
/** Signal containing the currently selected services with their selections */
|
|
44
|
+
services: Signal<ServiceSelection[]>;
|
|
15
45
|
/** Signal containing the currently selected time slot */
|
|
16
|
-
|
|
46
|
+
timeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
|
|
47
|
+
/** Signal containing the selected location (derived from timeSlot) */
|
|
48
|
+
location: Signal<Location | null>;
|
|
49
|
+
/** Signal containing the form values */
|
|
50
|
+
formValues: Signal<FormValues | null>;
|
|
51
|
+
/** Actions for modifying booking state */
|
|
52
|
+
actions: BookingServiceActions;
|
|
17
53
|
}
|
|
18
54
|
/**
|
|
19
55
|
* Service definition for Booking
|
|
@@ -25,12 +61,15 @@ export declare const BookingServiceDefinition: string & {
|
|
|
25
61
|
} & BookingService;
|
|
26
62
|
/**
|
|
27
63
|
* Configuration interface for BookingService
|
|
64
|
+
* Note: location is NOT in config - it's derived internally from timeSlot
|
|
28
65
|
*/
|
|
29
66
|
export interface BookingServiceConfig {
|
|
30
|
-
/** Optional initial services to pre-populate
|
|
31
|
-
initialServices?:
|
|
32
|
-
/** Optional initial time slot to pre-populate
|
|
67
|
+
/** Optional initial services to pre-populate */
|
|
68
|
+
initialServices?: ServiceSelection[];
|
|
69
|
+
/** Optional initial time slot to pre-populate */
|
|
33
70
|
initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
|
|
71
|
+
/** Optional initial form values */
|
|
72
|
+
initialFormValues?: FormValues | null;
|
|
34
73
|
}
|
|
35
74
|
/**
|
|
36
75
|
* Implementation of BookingService
|
|
@@ -44,20 +83,16 @@ export interface BookingServiceConfig {
|
|
|
44
83
|
* const bookingConfig = await loadBookingServiceConfig();
|
|
45
84
|
*
|
|
46
85
|
* // Wrap app with provider
|
|
47
|
-
* <Booking.Root
|
|
86
|
+
* <Booking.Root config={bookingConfig}>
|
|
48
87
|
* {children}
|
|
49
88
|
* </Booking.Root>
|
|
50
89
|
*
|
|
51
90
|
* // In any page - access booking data
|
|
52
91
|
* <Booking.Data>
|
|
53
|
-
* {({
|
|
54
|
-
* <div>{
|
|
92
|
+
* {({ services, timeSlot, location, formValues, actions }) => (
|
|
93
|
+
* <div>{services.map(s => s.service.name).join(', ')}</div>
|
|
55
94
|
* )}
|
|
56
95
|
* </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
96
|
* ```
|
|
62
97
|
*/
|
|
63
98
|
export declare const BookingService: import("@wix/services-definitions").ServiceFactory<string & {
|
|
@@ -65,21 +100,3 @@ export declare const BookingService: import("@wix/services-definitions").Service
|
|
|
65
100
|
__config: {};
|
|
66
101
|
isServiceDefinition?: boolean;
|
|
67
102
|
} & 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>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Booking Service - Global booking store
|
|
3
|
-
* Manages booking flow state (selected
|
|
3
|
+
* Manages booking flow state (selected services, time slot, location, form values)
|
|
4
4
|
* Persists across page navigation in SPA until page refresh
|
|
5
5
|
*/
|
|
6
6
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
@@ -9,6 +9,9 @@ import { SignalsServiceDefinition, } from '@wix/services-definitions/core-servic
|
|
|
9
9
|
* Service definition for Booking
|
|
10
10
|
*/
|
|
11
11
|
export const BookingServiceDefinition = defineService('booking');
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Service Implementation
|
|
14
|
+
// ============================================================================
|
|
12
15
|
/**
|
|
13
16
|
* Implementation of BookingService
|
|
14
17
|
*
|
|
@@ -21,54 +24,85 @@ export const BookingServiceDefinition = defineService('booking');
|
|
|
21
24
|
* const bookingConfig = await loadBookingServiceConfig();
|
|
22
25
|
*
|
|
23
26
|
* // Wrap app with provider
|
|
24
|
-
* <Booking.Root
|
|
27
|
+
* <Booking.Root config={bookingConfig}>
|
|
25
28
|
* {children}
|
|
26
29
|
* </Booking.Root>
|
|
27
30
|
*
|
|
28
31
|
* // In any page - access booking data
|
|
29
32
|
* <Booking.Data>
|
|
30
|
-
* {({
|
|
31
|
-
* <div>{
|
|
33
|
+
* {({ services, timeSlot, location, formValues, actions }) => (
|
|
34
|
+
* <div>{services.map(s => s.service.name).join(', ')}</div>
|
|
32
35
|
* )}
|
|
33
36
|
* </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
37
|
* ```
|
|
39
38
|
*/
|
|
40
39
|
export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
|
|
41
40
|
const signalsService = getService(SignalsServiceDefinition);
|
|
42
|
-
// Initialize
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
// Initialize signals with config values
|
|
42
|
+
const servicesSignal = signalsService.signal(config.initialServices || []);
|
|
43
|
+
const timeSlotSignal = signalsService.signal(config.initialTimeSlot || null);
|
|
44
|
+
// Location is derived internally - initialize as null
|
|
45
|
+
const locationSignal = signalsService.signal(null);
|
|
46
|
+
const formValuesSignal = signalsService.signal(config.initialFormValues || null);
|
|
47
|
+
// ========================================================================
|
|
48
|
+
// Actions Implementation
|
|
49
|
+
// ========================================================================
|
|
50
|
+
const actions = {
|
|
51
|
+
// Services actions
|
|
52
|
+
setServices(newServices) {
|
|
53
|
+
servicesSignal.set(newServices);
|
|
54
|
+
},
|
|
55
|
+
addService(service) {
|
|
56
|
+
const current = servicesSignal.get();
|
|
57
|
+
servicesSignal.set([...current, service]);
|
|
58
|
+
},
|
|
59
|
+
updateService(serviceId, updates) {
|
|
60
|
+
const current = servicesSignal.get();
|
|
61
|
+
const updated = current.map((s) => s.service._id === serviceId ? { ...s, ...updates } : s);
|
|
62
|
+
servicesSignal.set(updated);
|
|
63
|
+
},
|
|
64
|
+
removeService(serviceId) {
|
|
65
|
+
const current = servicesSignal.get();
|
|
66
|
+
const filtered = current.filter((s) => s.service._id !== serviceId);
|
|
67
|
+
servicesSignal.set(filtered);
|
|
68
|
+
},
|
|
69
|
+
clearServices() {
|
|
70
|
+
servicesSignal.set([]);
|
|
71
|
+
},
|
|
72
|
+
// Time Slot actions
|
|
73
|
+
setTimeSlot(slot) {
|
|
74
|
+
timeSlotSignal.set(slot);
|
|
75
|
+
},
|
|
76
|
+
clearTimeSlot() {
|
|
77
|
+
timeSlotSignal.set(null);
|
|
78
|
+
},
|
|
79
|
+
// Location actions
|
|
80
|
+
setLocation(location) {
|
|
81
|
+
locationSignal.set(location);
|
|
82
|
+
},
|
|
83
|
+
clearLocation() {
|
|
84
|
+
locationSignal.set(null);
|
|
85
|
+
},
|
|
86
|
+
// Form Values actions
|
|
87
|
+
setFormValues(values) {
|
|
88
|
+
formValuesSignal.set(values);
|
|
89
|
+
},
|
|
90
|
+
clearFormValues() {
|
|
91
|
+
formValuesSignal.set(null);
|
|
92
|
+
},
|
|
93
|
+
// Clear all
|
|
94
|
+
clearAll() {
|
|
95
|
+
servicesSignal.set([]);
|
|
96
|
+
timeSlotSignal.set(null);
|
|
97
|
+
locationSignal.set(null);
|
|
98
|
+
formValuesSignal.set(null);
|
|
99
|
+
},
|
|
49
100
|
};
|
|
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
101
|
return {
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
services: servicesSignal,
|
|
103
|
+
timeSlot: timeSlotSignal,
|
|
104
|
+
location: locationSignal,
|
|
105
|
+
formValues: formValuesSignal,
|
|
106
|
+
actions,
|
|
73
107
|
};
|
|
74
|
-
}
|
|
108
|
+
});
|
package/dist/services/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, loadServiceServiceConfig, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
|
|
6
|
-
export { BookingService, BookingServiceDefinition, type BookingServiceConfig,
|
|
6
|
+
export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type ServiceSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
|
package/dist/services/index.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Main export file for all service definitions and implementations
|
|
4
4
|
*/
|
|
5
5
|
export { ServiceService, ServiceServiceDefinition, loadServiceServiceConfig, } from './service/service.js';
|
|
6
|
-
export { BookingService, BookingServiceDefinition,
|
|
6
|
+
export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { defineService, implementService } from '@wix/services-definitions';
|
|
6
6
|
import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
|
|
7
7
|
import { getServiceById, getServiceBySlug, } from '../../api/query-service/index.js';
|
|
8
|
-
import { BookingServiceDefinition } from '../booking/booking.js';
|
|
8
|
+
import { BookingServiceDefinition, } from '../booking/booking.js';
|
|
9
9
|
/**
|
|
10
10
|
* Service definition for the Service service.
|
|
11
11
|
* This defines the contract that the ServiceService must implement.
|
|
@@ -73,21 +73,20 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
|
|
|
73
73
|
// Action methods for booking
|
|
74
74
|
const select = () => {
|
|
75
75
|
const currentService = service.get();
|
|
76
|
-
|
|
76
|
+
const selection = { service: currentService };
|
|
77
|
+
bookingService.services.set([selection]);
|
|
77
78
|
};
|
|
78
79
|
const add = () => {
|
|
79
80
|
const currentService = service.get();
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
currentService,
|
|
84
|
-
]);
|
|
81
|
+
const selections = bookingService.services.get();
|
|
82
|
+
const selection = { service: currentService };
|
|
83
|
+
bookingService.services.set([...selections, selection]);
|
|
85
84
|
};
|
|
86
85
|
const remove = () => {
|
|
87
86
|
const currentService = service.get();
|
|
88
|
-
const
|
|
89
|
-
const filtered =
|
|
90
|
-
bookingService.
|
|
87
|
+
const selections = bookingService.services.get();
|
|
88
|
+
const filtered = selections.filter((s) => s.service._id !== currentService._id);
|
|
89
|
+
bookingService.services.set(filtered);
|
|
91
90
|
};
|
|
92
91
|
return {
|
|
93
92
|
service,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-bookings",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@wix/bookings": "^1.0.122",
|
|
37
|
+
"@wix/form-public": "^0.64.0",
|
|
37
38
|
"@wix/headless-media": "0.0.18",
|
|
38
39
|
"@wix/headless-utils": "0.0.8",
|
|
39
40
|
"@wix/services-definitions": "^0.1.4",
|
|
@@ -67,5 +68,5 @@
|
|
|
67
68
|
"groupId": "com.wixpress.headless-components"
|
|
68
69
|
}
|
|
69
70
|
},
|
|
70
|
-
"falconPackageHash": "
|
|
71
|
+
"falconPackageHash": "3c91261634a562523b329f6e6e240b0e4e0e81b18b3d55fbcd7f53ff"
|
|
71
72
|
}
|