@wix/headless-bookings 0.0.15 → 0.0.16

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.
@@ -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 selections = bookingService.bookingSelections.get();
85
- return selections.some((selection) => selection.service._id === currentService._id);
84
+ const bookingItems = bookingService.bookingItems.get();
85
+ return bookingItems.some(({ service }) => service._id === currentService._id);
86
86
  });
87
87
  // requiresAvailability signal - true for APPOINTMENT and CLASS types
88
88
  const requiresAvailabilitySignal = signalsService.computed(() => {
@@ -185,25 +185,28 @@ export const ServiceService = implementService.withConfig()(ServiceServiceDefini
185
185
  if (!bookableSignal.get() || !bookingService)
186
186
  return;
187
187
  const currentService = serviceSignal.get();
188
- bookingService.actions.setService({ service: currentService });
188
+ bookingService.actions.updateItem({ service: currentService });
189
189
  },
190
190
  add: () => {
191
191
  if (!bookableSignal.get() || !bookingService)
192
192
  return;
193
193
  const currentService = serviceSignal.get();
194
- bookingService.actions.addService({ service: currentService });
194
+ bookingService.actions.addItem({
195
+ service: currentService,
196
+ resources: [],
197
+ });
195
198
  },
196
199
  remove: () => {
197
200
  if (!bookableSignal.get() || !bookingService)
198
201
  return;
199
202
  const currentService = serviceSignal.get();
200
203
  // Remove all instances of this service (by serviceId)
201
- const selections = bookingService.bookingSelections.get();
202
- const instancesToRemove = selections
204
+ const bookingItems = bookingService.bookingItems.get();
205
+ const instancesToRemove = bookingItems
203
206
  .filter((s) => s.service._id === currentService._id)
204
207
  .map((s) => s.instanceId);
205
208
  instancesToRemove.forEach((instanceId) => {
206
- bookingService.actions.removeBookingSelection(instanceId);
209
+ bookingService.actions.removeItem(instanceId);
207
210
  });
208
211
  },
209
212
  };
@@ -6,7 +6,7 @@ import { implementService } from '@wix/services-definitions';
6
6
  import { SignalsServiceDefinition } from '@wix/services-definitions/core-services/signals';
7
7
  import { TimeSlotListServiceDefinition, ViewMode, } from './time-slot-list.def.js';
8
8
  import { fetchAvailability } from '../../api/time-slot-list/index.js';
9
- import { BookingServiceDefinition } from '../booking/booking.js';
9
+ import { BookingServiceDefinition, } from '../booking/booking.js';
10
10
  // ============================================================================
11
11
  // Helpers
12
12
  // ============================================================================
@@ -79,7 +79,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
79
79
  const getServices = () => {
80
80
  if (config.services?.length)
81
81
  return config.services;
82
- return bookingService.bookingSelections.get().map((s) => s.service);
82
+ return bookingService.bookingItems.get().map((s) => s.service);
83
83
  };
84
84
  /**
85
85
  * Fetch time slots from API
@@ -115,82 +115,139 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
115
115
  };
116
116
  /**
117
117
  * Action: Select a time slot
118
- * Only updates booking service if there's exactly one location and one resource
119
- * Otherwise, user must select location/resource before booking
118
+ * Auto-selects location/staff based on availability:
119
+ * - One location + one staff → auto-select both
120
+ * - One location + many staff → auto-select location only
121
+ * - Many locations + one staff → auto-select staff only
122
+ * - Many locations + many staff → don't auto-select anything
120
123
  */
121
124
  const selectSlot = (slot) => {
122
125
  const currentSelection = selectionSignal.get();
123
126
  if (currentSelection?.slot?.id === slot.id)
124
127
  return;
128
+ const timeSlot = {
129
+ startDate: slot.localStartDate,
130
+ endDate: slot.localEndDate,
131
+ totalCapacity: slot.totalCapacity ?? undefined,
132
+ remainingCapacity: slot.remainingCapacity ?? undefined,
133
+ scheduleId: slot.scheduleId ?? undefined,
134
+ eventInfo: slot.eventInfo ?? undefined,
135
+ };
125
136
  const hasOneLocation = slot.staffByLocation.length === 1;
126
- const hasOneResource = hasOneLocation && slot.staffByLocation[0].staffMembers.length === 1;
127
- if (hasOneLocation && hasOneResource) {
128
- const originalSlot = slot.originalSlots[0];
129
- const { location, staffMembers } = slot.staffByLocation[0];
130
- const staffMemberId = staffMembers[0].id;
131
- selectionSignal.set({
132
- slot,
133
- locationId: location.id,
134
- staffMemberId,
135
- });
136
- bookingService.actions.setTimeSlot(originalSlot);
137
- bookingService.actions.setLocation({
138
- id: location.id,
139
- name: location.name,
140
- });
141
- bookingService.actions.updateBookingSelection({
142
- staff: {
143
- _id: staffMemberId,
144
- name: staffMembers[0].name,
145
- },
137
+ // Collect all unique staff members across all locations
138
+ const allStaffMembers = slot.staffByLocation.flatMap((loc) => loc.staffMembers);
139
+ const uniqueStaffIds = new Set(allStaffMembers.map((s) => s.id));
140
+ const hasOneStaff = uniqueStaffIds.size === 1;
141
+ // Determine what to auto-select
142
+ let locationId = null;
143
+ let staffMemberId = null;
144
+ if (hasOneLocation) {
145
+ const { location } = slot.staffByLocation[0];
146
+ locationId = location.id;
147
+ bookingService.actions.setLocation(location);
148
+ }
149
+ else {
150
+ bookingService.actions.clearLocation();
151
+ }
152
+ if (hasOneStaff) {
153
+ const staffMember = allStaffMembers[0];
154
+ staffMemberId = staffMember.id;
155
+ bookingService.actions.updateItem({
156
+ timeSlot,
157
+ resources: [
158
+ {
159
+ _id: staffMemberId,
160
+ name: staffMember.name,
161
+ },
162
+ ],
146
163
  });
147
164
  }
148
165
  else {
149
- selectionSignal.set({
150
- slot,
151
- locationId: null,
152
- staffMemberId: null,
166
+ bookingService.actions.updateItem({
167
+ timeSlot,
168
+ resources: [],
153
169
  });
154
170
  }
171
+ selectionSignal.set({
172
+ slot,
173
+ locationId,
174
+ staffMemberId,
175
+ });
155
176
  };
156
177
  /**
157
178
  * Action: Select a location for the current slot
158
- * Updates the booking service with the correct original slot for this location
179
+ * Updates the booking service with the location
180
+ * If the location has only one staff member, auto-selects that staff member too
159
181
  */
160
182
  const selectLocation = (locationId) => {
161
183
  const currentSelections = selectionSignal.get();
162
184
  if (!currentSelections?.slot)
163
185
  return;
164
- selectionSignal.set({ ...currentSelections, locationId });
165
- const location = currentSelections.slot.originalSlots.find((s) => s.location?._id === locationId)?.location;
166
- if (location) {
167
- bookingService.actions.setLocation({
168
- id: location._id,
169
- name: location.name,
186
+ const slot = currentSelections.slot;
187
+ const locationEntry = slot.staffByLocation.find((loc) => loc.location.id === locationId);
188
+ if (!locationEntry)
189
+ return;
190
+ const { location, staffMembers } = locationEntry;
191
+ bookingService.actions.setLocation(location);
192
+ // If this location has only one staff member, auto-select them
193
+ const hasOneStaff = staffMembers.length === 1;
194
+ if (hasOneStaff) {
195
+ const staffMember = staffMembers[0];
196
+ selectionSignal.set({
197
+ ...currentSelections,
198
+ locationId,
199
+ staffMemberId: staffMember.id,
170
200
  });
201
+ bookingService.actions.updateItem({
202
+ resources: [
203
+ {
204
+ _id: staffMember.id,
205
+ name: staffMember.name,
206
+ },
207
+ ],
208
+ });
209
+ }
210
+ else {
211
+ selectionSignal.set({ ...currentSelections, locationId });
171
212
  }
172
213
  };
173
214
  /**
174
215
  * Action: Select a staff member for the current slot
175
- * Updates the booking service with the selected resource for the slot's service
216
+ * Updates the booking service with the selected resource
217
+ * If the staff member is only available at one location, auto-selects that location too
176
218
  */
177
219
  const selectStaffMember = (staffMemberId) => {
178
220
  const currentSelections = selectionSignal.get();
179
221
  if (!currentSelections?.slot)
180
222
  return;
181
- selectionSignal.set({ ...currentSelections, staffMemberId });
182
223
  const slot = currentSelections.slot;
183
- // Find the resource info from original slots
184
- for (const originalSlot of slot.originalSlots) {
185
- for (const resourceGroup of originalSlot.availableResources || []) {
186
- const staff = resourceGroup.resources?.find((r) => r._id === staffMemberId);
187
- if (staff) {
188
- bookingService.actions.updateBookingSelection({
189
- staff,
190
- });
191
- return;
192
- }
193
- }
224
+ // Find all locations that have this staff member
225
+ const locationsWithThisStaff = slot.staffByLocation.filter((loc) => loc.staffMembers.some((s) => s.id === staffMemberId));
226
+ // Find the staff member info
227
+ const staffMember = locationsWithThisStaff[0]?.staffMembers.find((s) => s.id === staffMemberId);
228
+ if (!staffMember)
229
+ return;
230
+ bookingService.actions.updateItem({
231
+ resources: [
232
+ {
233
+ _id: staffMember.id,
234
+ name: staffMember.name,
235
+ },
236
+ ],
237
+ });
238
+ // If this staff member is only at one location, auto-select that location
239
+ const hasOneLocation = locationsWithThisStaff.length === 1;
240
+ if (hasOneLocation) {
241
+ const location = locationsWithThisStaff[0].location;
242
+ selectionSignal.set({
243
+ ...currentSelections,
244
+ staffMemberId,
245
+ locationId: location.id,
246
+ });
247
+ bookingService.actions.setLocation(location);
248
+ }
249
+ else {
250
+ selectionSignal.set({ ...currentSelections, staffMemberId });
194
251
  }
195
252
  };
196
253
  /**
@@ -206,15 +263,11 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
206
263
  locationId: null,
207
264
  staffMemberId: null,
208
265
  });
209
- // Clear location in booking service
266
+ // Clear selections in booking service
210
267
  bookingService.actions.clearLocation();
211
- // Clear resources (staff) in booking service
212
- const serviceId = currentSelection.slot.serviceId;
213
- if (serviceId) {
214
- bookingService.actions.updateBookingSelection({
215
- staff: undefined,
216
- });
217
- }
268
+ bookingService.actions.updateItem({
269
+ resources: [],
270
+ });
218
271
  };
219
272
  /**
220
273
  * Action: Load more slots (pagination)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
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": "d56b9bfa88501c3f0e6edec7314578de67940d2a7e425c0c34fa3c3c"
71
+ "falconPackageHash": "9e70aba1e4a39f28a7d02fca86dcf92c71014635fbfc9208bf1569f4"
72
72
  }