@wix/headless-bookings 0.0.11 → 0.0.12

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.
@@ -3,7 +3,7 @@
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, type ServiceSelection } from '../../../services/booking/booking.js';
6
+ import { type BookingServiceConfig, type BookingSelection } from '../../../services/booking/booking.js';
7
7
  import type { availabilityTimeSlots } from '@wix/bookings';
8
8
  /**
9
9
  * Props for Booking.Root component
@@ -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: ServiceSelection[];
36
+ bookingSelections: BookingSelection[];
37
37
  selectedTimeSlot: availabilityTimeSlots.TimeSlot | null;
38
38
  }) => React.ReactNode;
39
39
  }
@@ -45,9 +45,9 @@ export interface DataProps {
45
45
  * @example
46
46
  * ```tsx
47
47
  * <Booking.Data>
48
- * {({ selectedServices }) => (
49
- * selectedServices.length > 0 ? (
50
- * <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
48
+ * {({ bookingSelections }) => (
49
+ * bookingSelections.length > 0 ? (
50
+ * <div>{bookingSelections.map(s => s.service.name).join(', ')}</div>
51
51
  * ) : (
52
52
  * <div>No services selected</div>
53
53
  * )
@@ -28,9 +28,9 @@ export function Root(props) {
28
28
  * @example
29
29
  * ```tsx
30
30
  * <Booking.Data>
31
- * {({ selectedServices }) => (
32
- * selectedServices.length > 0 ? (
33
- * <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
31
+ * {({ bookingSelections }) => (
32
+ * bookingSelections.length > 0 ? (
33
+ * <div>{bookingSelections.map(s => s.service.name).join(', ')}</div>
34
34
  * ) : (
35
35
  * <div>No services selected</div>
36
36
  * )
@@ -41,10 +41,10 @@ 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.services.get();
44
+ const bookingSelections = bookingService.bookingSelections.get();
45
45
  const selectedTimeSlot = bookingService.timeSlot.get();
46
46
  return children({
47
- selectedServices,
47
+ bookingSelections,
48
48
  selectedTimeSlot,
49
49
  });
50
50
  }
@@ -7,12 +7,16 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
7
7
  import type { services, availabilityTimeSlots } from '@wix/bookings';
8
8
  import type { FormValues } from '@wix/form-public';
9
9
  /**
10
- * ServiceSelection contains the service AND its related selections
10
+ * BookingSelection contains the service AND its related selections
11
11
  */
12
- export interface ServiceSelection {
12
+ export interface BookingSelection {
13
+ /** Unique identifier for this booking instance (allows same service multiple times) */
14
+ instanceId: string;
13
15
  service: services.Service;
14
16
  /** Selected resources (staff members, rooms, etc.) */
15
- resources?: availabilityTimeSlots.Resource[];
17
+ staff?: availabilityTimeSlots.Resource;
18
+ /** Per-service slot data from nested slots (for multi-service bookings) */
19
+ nestedSlotData?: availabilityTimeSlots.NestedTimeSlot;
16
20
  }
17
21
  export interface Location {
18
22
  id: string;
@@ -22,10 +26,14 @@ export interface Location {
22
26
  * BookingService actions - setters only, no API calls
23
27
  */
24
28
  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
+ /** Clears all booking selections and sets a single service (instanceId is auto-generated) */
30
+ setService(service: Omit<BookingSelection, 'instanceId'>): string;
31
+ /** Adds a service and returns the generated instanceId */
32
+ addService(service: Omit<BookingSelection, 'instanceId'>): string;
33
+ /** Updates a booking selection by instanceId */
34
+ updateServiceByInstanceId(instanceId: string, updates: Partial<Omit<BookingSelection, 'instanceId'>>): void;
35
+ /** Removes a service selection by instanceId. If no instanceId provided, removes the first service. */
36
+ removeServiceByInstanceId(instanceId?: string): void;
29
37
  clearServices(): void;
30
38
  setTimeSlot(slot: availabilityTimeSlots.TimeSlot | null): void;
31
39
  clearTimeSlot(): void;
@@ -40,8 +48,8 @@ export interface BookingServiceActions {
40
48
  * Pure state management - no API calls
41
49
  */
42
50
  export interface BookingService {
43
- /** Signal containing the currently selected services with their selections */
44
- services: Signal<ServiceSelection[]>;
51
+ /** Signal containing the booking selections (services with their related data) */
52
+ bookingSelections: Signal<BookingSelection[]>;
45
53
  /** Signal containing the currently selected time slot */
46
54
  timeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
47
55
  /** Signal containing the selected location (derived from timeSlot) */
@@ -64,8 +72,8 @@ export declare const BookingServiceDefinition: string & {
64
72
  * Note: location is NOT in config - it's derived internally from timeSlot
65
73
  */
66
74
  export interface BookingServiceConfig {
67
- /** Optional initial services to pre-populate */
68
- initialServices?: ServiceSelection[];
75
+ /** Optional initial booking selections to pre-populate */
76
+ initialBookingSelections?: BookingSelection[];
69
77
  /** Optional initial time slot to pre-populate */
70
78
  initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
71
79
  /** Optional initial form values */
@@ -5,6 +5,15 @@
5
5
  */
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
+ // ============================================================================
9
+ // Types
10
+ // ============================================================================
11
+ /**
12
+ * Generates a unique instance ID for service selections
13
+ */
14
+ function generateInstanceId() {
15
+ return crypto.randomUUID();
16
+ }
8
17
  /**
9
18
  * Service definition for Booking
10
19
  */
@@ -39,7 +48,12 @@ export const BookingServiceDefinition = defineService('booking');
39
48
  export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
40
49
  const signalsService = getService(SignalsServiceDefinition);
41
50
  // Initialize signals with config values
42
- const servicesSignal = signalsService.signal(config.initialServices || []);
51
+ // Ensure all initial booking selections have instanceIds
52
+ const initialSelectionsWithIds = (config.initialBookingSelections || []).map((s) => ({
53
+ ...s,
54
+ instanceId: s.instanceId || generateInstanceId(),
55
+ }));
56
+ const bookingSelectionsSignal = signalsService.signal(initialSelectionsWithIds);
43
57
  const timeSlotSignal = signalsService.signal(config.initialTimeSlot || null);
44
58
  // Location is derived internally - initialize as null
45
59
  const locationSignal = signalsService.signal(null);
@@ -49,25 +63,43 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
49
63
  // ========================================================================
50
64
  const actions = {
51
65
  // Services actions
52
- setServices(newServices) {
53
- servicesSignal.set(newServices);
66
+ setService(service) {
67
+ const instanceId = generateInstanceId();
68
+ const newSelection = {
69
+ ...service,
70
+ instanceId,
71
+ };
72
+ bookingSelectionsSignal.set([newSelection]);
73
+ return instanceId;
54
74
  },
55
75
  addService(service) {
56
- const current = servicesSignal.get();
57
- servicesSignal.set([...current, service]);
76
+ const instanceId = generateInstanceId();
77
+ const current = bookingSelectionsSignal.get();
78
+ const newSelection = {
79
+ ...service,
80
+ instanceId,
81
+ };
82
+ bookingSelectionsSignal.set([...current, newSelection]);
83
+ return instanceId;
58
84
  },
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);
85
+ updateServiceByInstanceId(instanceId, updates) {
86
+ const current = bookingSelectionsSignal.get();
87
+ const updated = current.map((s) => s.instanceId === instanceId ? { ...s, ...updates } : s);
88
+ bookingSelectionsSignal.set(updated);
63
89
  },
64
- removeService(serviceId) {
65
- const current = servicesSignal.get();
66
- const filtered = current.filter((s) => s.service._id !== serviceId);
67
- servicesSignal.set(filtered);
90
+ removeServiceByInstanceId(instanceId) {
91
+ const current = bookingSelectionsSignal.get();
92
+ if (!instanceId) {
93
+ // Remove first selection if no instanceId provided
94
+ bookingSelectionsSignal.set(current.slice(1));
95
+ }
96
+ else {
97
+ const filtered = current.filter((s) => s.instanceId !== instanceId);
98
+ bookingSelectionsSignal.set(filtered);
99
+ }
68
100
  },
69
101
  clearServices() {
70
- servicesSignal.set([]);
102
+ bookingSelectionsSignal.set([]);
71
103
  },
72
104
  // Time Slot actions
73
105
  setTimeSlot(slot) {
@@ -92,14 +124,14 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
92
124
  },
93
125
  // Clear all
94
126
  clearAll() {
95
- servicesSignal.set([]);
127
+ bookingSelectionsSignal.set([]);
96
128
  timeSlotSignal.set(null);
97
129
  locationSignal.set(null);
98
130
  formValuesSignal.set(null);
99
131
  },
100
132
  };
101
133
  return {
102
- services: servicesSignal,
134
+ bookingSelections: bookingSelectionsSignal,
103
135
  timeSlot: timeSlotSignal,
104
136
  location: locationSignal,
105
137
  formValues: formValuesSignal,
@@ -3,5 +3,5 @@
3
3
  * Main export file for all service definitions and implementations
4
4
  */
5
5
  export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, type ServiceActions, type ServicePaymentData, loadServiceServiceInitialData, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
6
- export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type ServiceSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
6
+ export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
7
7
  export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
@@ -6,7 +6,7 @@ import { defineService, implementService } from '@wix/services-definitions';
6
6
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
7
7
  import { services } from '@wix/bookings';
8
8
  import { getServiceById, getServiceBySlug, } from '../../api/query-services/index.js';
9
- import { BookingServiceDefinition, } from '../booking/booking.js';
9
+ import { BookingServiceDefinition } from '../booking/booking.js';
10
10
  import { convertToMoneyData } from '../../utils/money.js';
11
11
  /**
12
12
  * Booking app ID constant
@@ -81,8 +81,8 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
81
81
  const currentService = serviceSignal.get();
82
82
  if (!currentService._id)
83
83
  return false;
84
- const services = bookingService.services.get();
85
- return services.some((selection) => selection.service._id === currentService._id);
84
+ const selections = bookingService.bookingSelections.get();
85
+ return selections.some((selection) => selection.service._id === currentService._id);
86
86
  });
87
87
  // requiresAvailability signal - true for APPOINTMENT and CLASS types
88
88
  const requiresAvailabilitySignal = signalsService.computed(() => {
@@ -185,27 +185,26 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
185
185
  if (!bookableSignal.get() || !bookingService)
186
186
  return;
187
187
  const currentService = serviceSignal.get();
188
- const selection = {
189
- service: currentService,
190
- };
191
- bookingService.actions.setServices([selection]);
188
+ bookingService.actions.setService({ service: currentService });
192
189
  },
193
190
  add: () => {
194
191
  if (!bookableSignal.get() || !bookingService)
195
192
  return;
196
193
  const currentService = serviceSignal.get();
197
- const selection = {
198
- service: currentService,
199
- };
200
- bookingService.actions.addService(selection);
194
+ bookingService.actions.addService({ service: currentService });
201
195
  },
202
196
  remove: () => {
203
197
  if (!bookableSignal.get() || !bookingService)
204
198
  return;
205
199
  const currentService = serviceSignal.get();
206
- if (currentService._id) {
207
- bookingService.actions.removeService(currentService._id);
208
- }
200
+ // Remove all instances of this service (by serviceId)
201
+ const selections = bookingService.bookingSelections.get();
202
+ const instancesToRemove = selections
203
+ .filter((s) => s.service._id === currentService._id)
204
+ .map((s) => s.instanceId);
205
+ instancesToRemove.forEach((instanceId) => {
206
+ bookingService.actions.removeServiceByInstanceId(instanceId);
207
+ });
209
208
  },
210
209
  };
211
210
  return {
@@ -3,7 +3,7 @@
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, type ServiceSelection } from '../../../services/booking/booking.js';
6
+ import { type BookingServiceConfig, type BookingSelection } from '../../../services/booking/booking.js';
7
7
  import type { availabilityTimeSlots } from '@wix/bookings';
8
8
  /**
9
9
  * Props for Booking.Root component
@@ -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: ServiceSelection[];
36
+ bookingSelections: BookingSelection[];
37
37
  selectedTimeSlot: availabilityTimeSlots.TimeSlot | null;
38
38
  }) => React.ReactNode;
39
39
  }
@@ -45,9 +45,9 @@ export interface DataProps {
45
45
  * @example
46
46
  * ```tsx
47
47
  * <Booking.Data>
48
- * {({ selectedServices }) => (
49
- * selectedServices.length > 0 ? (
50
- * <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
48
+ * {({ bookingSelections }) => (
49
+ * bookingSelections.length > 0 ? (
50
+ * <div>{bookingSelections.map(s => s.service.name).join(', ')}</div>
51
51
  * ) : (
52
52
  * <div>No services selected</div>
53
53
  * )
@@ -28,9 +28,9 @@ export function Root(props) {
28
28
  * @example
29
29
  * ```tsx
30
30
  * <Booking.Data>
31
- * {({ selectedServices }) => (
32
- * selectedServices.length > 0 ? (
33
- * <div>{selectedServices.map(s => s.service.name).join(', ')}</div>
31
+ * {({ bookingSelections }) => (
32
+ * bookingSelections.length > 0 ? (
33
+ * <div>{bookingSelections.map(s => s.service.name).join(', ')}</div>
34
34
  * ) : (
35
35
  * <div>No services selected</div>
36
36
  * )
@@ -41,10 +41,10 @@ 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.services.get();
44
+ const bookingSelections = bookingService.bookingSelections.get();
45
45
  const selectedTimeSlot = bookingService.timeSlot.get();
46
46
  return children({
47
- selectedServices,
47
+ bookingSelections,
48
48
  selectedTimeSlot,
49
49
  });
50
50
  }
@@ -7,12 +7,16 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
7
7
  import type { services, availabilityTimeSlots } from '@wix/bookings';
8
8
  import type { FormValues } from '@wix/form-public';
9
9
  /**
10
- * ServiceSelection contains the service AND its related selections
10
+ * BookingSelection contains the service AND its related selections
11
11
  */
12
- export interface ServiceSelection {
12
+ export interface BookingSelection {
13
+ /** Unique identifier for this booking instance (allows same service multiple times) */
14
+ instanceId: string;
13
15
  service: services.Service;
14
16
  /** Selected resources (staff members, rooms, etc.) */
15
- resources?: availabilityTimeSlots.Resource[];
17
+ staff?: availabilityTimeSlots.Resource;
18
+ /** Per-service slot data from nested slots (for multi-service bookings) */
19
+ nestedSlotData?: availabilityTimeSlots.NestedTimeSlot;
16
20
  }
17
21
  export interface Location {
18
22
  id: string;
@@ -22,10 +26,14 @@ export interface Location {
22
26
  * BookingService actions - setters only, no API calls
23
27
  */
24
28
  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
+ /** Clears all booking selections and sets a single service (instanceId is auto-generated) */
30
+ setService(service: Omit<BookingSelection, 'instanceId'>): string;
31
+ /** Adds a service and returns the generated instanceId */
32
+ addService(service: Omit<BookingSelection, 'instanceId'>): string;
33
+ /** Updates a booking selection by instanceId */
34
+ updateServiceByInstanceId(instanceId: string, updates: Partial<Omit<BookingSelection, 'instanceId'>>): void;
35
+ /** Removes a service selection by instanceId. If no instanceId provided, removes the first service. */
36
+ removeServiceByInstanceId(instanceId?: string): void;
29
37
  clearServices(): void;
30
38
  setTimeSlot(slot: availabilityTimeSlots.TimeSlot | null): void;
31
39
  clearTimeSlot(): void;
@@ -40,8 +48,8 @@ export interface BookingServiceActions {
40
48
  * Pure state management - no API calls
41
49
  */
42
50
  export interface BookingService {
43
- /** Signal containing the currently selected services with their selections */
44
- services: Signal<ServiceSelection[]>;
51
+ /** Signal containing the booking selections (services with their related data) */
52
+ bookingSelections: Signal<BookingSelection[]>;
45
53
  /** Signal containing the currently selected time slot */
46
54
  timeSlot: Signal<availabilityTimeSlots.TimeSlot | null>;
47
55
  /** Signal containing the selected location (derived from timeSlot) */
@@ -64,8 +72,8 @@ export declare const BookingServiceDefinition: string & {
64
72
  * Note: location is NOT in config - it's derived internally from timeSlot
65
73
  */
66
74
  export interface BookingServiceConfig {
67
- /** Optional initial services to pre-populate */
68
- initialServices?: ServiceSelection[];
75
+ /** Optional initial booking selections to pre-populate */
76
+ initialBookingSelections?: BookingSelection[];
69
77
  /** Optional initial time slot to pre-populate */
70
78
  initialTimeSlot?: availabilityTimeSlots.TimeSlot | null;
71
79
  /** Optional initial form values */
@@ -5,6 +5,15 @@
5
5
  */
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
+ // ============================================================================
9
+ // Types
10
+ // ============================================================================
11
+ /**
12
+ * Generates a unique instance ID for service selections
13
+ */
14
+ function generateInstanceId() {
15
+ return crypto.randomUUID();
16
+ }
8
17
  /**
9
18
  * Service definition for Booking
10
19
  */
@@ -39,7 +48,12 @@ export const BookingServiceDefinition = defineService('booking');
39
48
  export const BookingService = implementService.withConfig()(BookingServiceDefinition, ({ getService, config }) => {
40
49
  const signalsService = getService(SignalsServiceDefinition);
41
50
  // Initialize signals with config values
42
- const servicesSignal = signalsService.signal(config.initialServices || []);
51
+ // Ensure all initial booking selections have instanceIds
52
+ const initialSelectionsWithIds = (config.initialBookingSelections || []).map((s) => ({
53
+ ...s,
54
+ instanceId: s.instanceId || generateInstanceId(),
55
+ }));
56
+ const bookingSelectionsSignal = signalsService.signal(initialSelectionsWithIds);
43
57
  const timeSlotSignal = signalsService.signal(config.initialTimeSlot || null);
44
58
  // Location is derived internally - initialize as null
45
59
  const locationSignal = signalsService.signal(null);
@@ -49,25 +63,43 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
49
63
  // ========================================================================
50
64
  const actions = {
51
65
  // Services actions
52
- setServices(newServices) {
53
- servicesSignal.set(newServices);
66
+ setService(service) {
67
+ const instanceId = generateInstanceId();
68
+ const newSelection = {
69
+ ...service,
70
+ instanceId,
71
+ };
72
+ bookingSelectionsSignal.set([newSelection]);
73
+ return instanceId;
54
74
  },
55
75
  addService(service) {
56
- const current = servicesSignal.get();
57
- servicesSignal.set([...current, service]);
76
+ const instanceId = generateInstanceId();
77
+ const current = bookingSelectionsSignal.get();
78
+ const newSelection = {
79
+ ...service,
80
+ instanceId,
81
+ };
82
+ bookingSelectionsSignal.set([...current, newSelection]);
83
+ return instanceId;
58
84
  },
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);
85
+ updateServiceByInstanceId(instanceId, updates) {
86
+ const current = bookingSelectionsSignal.get();
87
+ const updated = current.map((s) => s.instanceId === instanceId ? { ...s, ...updates } : s);
88
+ bookingSelectionsSignal.set(updated);
63
89
  },
64
- removeService(serviceId) {
65
- const current = servicesSignal.get();
66
- const filtered = current.filter((s) => s.service._id !== serviceId);
67
- servicesSignal.set(filtered);
90
+ removeServiceByInstanceId(instanceId) {
91
+ const current = bookingSelectionsSignal.get();
92
+ if (!instanceId) {
93
+ // Remove first selection if no instanceId provided
94
+ bookingSelectionsSignal.set(current.slice(1));
95
+ }
96
+ else {
97
+ const filtered = current.filter((s) => s.instanceId !== instanceId);
98
+ bookingSelectionsSignal.set(filtered);
99
+ }
68
100
  },
69
101
  clearServices() {
70
- servicesSignal.set([]);
102
+ bookingSelectionsSignal.set([]);
71
103
  },
72
104
  // Time Slot actions
73
105
  setTimeSlot(slot) {
@@ -92,14 +124,14 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
92
124
  },
93
125
  // Clear all
94
126
  clearAll() {
95
- servicesSignal.set([]);
127
+ bookingSelectionsSignal.set([]);
96
128
  timeSlotSignal.set(null);
97
129
  locationSignal.set(null);
98
130
  formValuesSignal.set(null);
99
131
  },
100
132
  };
101
133
  return {
102
- services: servicesSignal,
134
+ bookingSelections: bookingSelectionsSignal,
103
135
  timeSlot: timeSlotSignal,
104
136
  location: locationSignal,
105
137
  formValues: formValuesSignal,
@@ -3,5 +3,5 @@
3
3
  * Main export file for all service definitions and implementations
4
4
  */
5
5
  export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type ServiceServiceConfig, type ServiceActions, type ServicePaymentData, loadServiceServiceInitialData, type SuccessServiceServiceConfigResult, type NotFoundServiceServiceConfigResult, } from './service/service.js';
6
- export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type ServiceSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
6
+ export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type BookingSelection, type Location, type BookingServiceActions, } from './booking/booking.js';
7
7
  export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
@@ -6,7 +6,7 @@ import { defineService, implementService } from '@wix/services-definitions';
6
6
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
7
7
  import { services } from '@wix/bookings';
8
8
  import { getServiceById, getServiceBySlug, } from '../../api/query-services/index.js';
9
- import { BookingServiceDefinition, } from '../booking/booking.js';
9
+ import { BookingServiceDefinition } from '../booking/booking.js';
10
10
  import { convertToMoneyData } from '../../utils/money.js';
11
11
  /**
12
12
  * Booking app ID constant
@@ -81,8 +81,8 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
81
81
  const currentService = serviceSignal.get();
82
82
  if (!currentService._id)
83
83
  return false;
84
- const services = bookingService.services.get();
85
- return services.some((selection) => selection.service._id === currentService._id);
84
+ const selections = bookingService.bookingSelections.get();
85
+ return selections.some((selection) => selection.service._id === currentService._id);
86
86
  });
87
87
  // requiresAvailability signal - true for APPOINTMENT and CLASS types
88
88
  const requiresAvailabilitySignal = signalsService.computed(() => {
@@ -185,27 +185,26 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
185
185
  if (!bookableSignal.get() || !bookingService)
186
186
  return;
187
187
  const currentService = serviceSignal.get();
188
- const selection = {
189
- service: currentService,
190
- };
191
- bookingService.actions.setServices([selection]);
188
+ bookingService.actions.setService({ service: currentService });
192
189
  },
193
190
  add: () => {
194
191
  if (!bookableSignal.get() || !bookingService)
195
192
  return;
196
193
  const currentService = serviceSignal.get();
197
- const selection = {
198
- service: currentService,
199
- };
200
- bookingService.actions.addService(selection);
194
+ bookingService.actions.addService({ service: currentService });
201
195
  },
202
196
  remove: () => {
203
197
  if (!bookableSignal.get() || !bookingService)
204
198
  return;
205
199
  const currentService = serviceSignal.get();
206
- if (currentService._id) {
207
- bookingService.actions.removeService(currentService._id);
208
- }
200
+ // Remove all instances of this service (by serviceId)
201
+ const selections = bookingService.bookingSelections.get();
202
+ const instancesToRemove = selections
203
+ .filter((s) => s.service._id === currentService._id)
204
+ .map((s) => s.instanceId);
205
+ instancesToRemove.forEach((instanceId) => {
206
+ bookingService.actions.removeServiceByInstanceId(instanceId);
207
+ });
209
208
  },
210
209
  };
211
210
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -68,5 +68,5 @@
68
68
  "groupId": "com.wixpress.headless-components"
69
69
  }
70
70
  },
71
- "falconPackageHash": "2996fdf77f39e0cde0bf4bb18bd8bd0dd2630b3aa839f47d67059ca2"
71
+ "falconPackageHash": "1ac24364dad5e7cd40939f468503e6a086b769e8398d3070b79d7ae2"
72
72
  }