Retrieve available spots from services

Hi there,

I’m trying to display the available spots of each service displayed in a repeater. Everything works, however the value returned for “available spots” is always “undefined” and I don’t understand why… Can anyone help me?

Here’s an example of the value returned:

Here is my code:

//-------------Imports-------------//

import wixData from "wix-data";
import wixBookings from "wix-bookings";

// Map of services.
let servicesMap = {};
// List of services.
let services = [];

$w.onReady(() => {
  setupRepeater();
  setupButtons();
  initializeSlots();
  const today = new Date();
  const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59);
  populateServicesSlots(today, endOfDay);
});

function showLoader(show = false) {
  if (show === false) {
    $w("#servicesLoader").hide();
  } else {
    $w("#servicesLoader").show();
  }
}

async function initializeSlots() {
  // Set the global services list to all the services of type class from the Services collection.
  services = await getAllClasses();
  // Put the services in a map for easy access by ID.
  services.forEach(service => (servicesMap[service._id] = service));
}

async function populateServicesSlots(startDateTime, endDateTime) {
  // Get the available slots from all the services for the given date range.
  let availableSlots = await getMultipleServicesAvailability(services, {
    startDateTime,
    endDateTime,
  });
  // Sort the available slots in ascending order by start time.
  availableSlots = availableSlots.sort((a, b) => a.startDateTime - b.startDateTime);
  // Set the slot repeater's data to the sorted available slots, thereby populating the repeater.
  $w("#servicesRepeater").data = availableSlots;
}

//-------------Bookings Data Retrieval-------------//

// Get all services of type class from the Services collection.
async function getAllClasses() {
  const data = await wixData.query("Bookings/Services").eq("serviceType", "CLASS").find();
  return data.items;
}

// Get the availability of multiple given services for the given date range. Optimize the service availability
// requests by batching all the service availability requests into one promise.
async function getMultipleServicesAvailability(requestedServices, availabilityOptions) {
  // Create an empty list of Promises.
  let slotsPromises = [];
  // Create an empty list of slots.
  let slots = [];
  // For each of the given requested services:
  requestedServices.forEach((requestedservice) => {
    // Make a call to get the service's available slots and store the function's returned Promise.
    const slotsPromise = wixBookings
      .getServiceAvailability(requestedservice._id, availabilityOptions)
      .then((result) => {
        // When the Promise is resolved, add the available slots to the global slot list.
        result.slots.forEach((slot) => slots.push(slot));
      });
    // Add the service availability Promise to the list of Promises.
    slotsPromises.push(slotsPromise);
  });
  // Wait for all the availability calls for all the services to finish.
  await Promise.all(slotsPromises);
  // Return the available slots found from all the services.
  return slots;
}

//-------------Repeater Setup-------------//

export function setupRepeater() {
  // Set up each item in the services repeater as it is loaded. Note that
  // most of the repeater elements are populated using a dataset.
  $w("#servicesRepeater").onItemReady(async ($item, itemData, index) => {
    if (index === 0) {
      showLoader(false);
    }
    // Get the item's service ID.
    const serviceId = itemData._id;
    // Retrieve the available slots for the item's service.
    const availability = await wixBookings.getServiceAvailability(serviceId);
    // Store the first available slot as the next available slot.
    const nextAvailableSlot = availability.slots[0];
    // If there is an available slot:
    if (nextAvailableSlot) {
      // Set the nextSlot text to the month and day of the next available slot.
      $item("#nextSlot").text = "Commence le " + getMonthDay(nextAvailableSlot.startDateTime);
      $item("#availableSpots").text = itemData.remainingSpots + " places restantes";
    }
    // If there are no available slots:
    else {
      // Set the nextSlot text to ???.
      $item("#nextSlot").text = "???";
    }
  });
}

//-------------Category Button Clicks-------------//
function setupButtons() {
  // Filter the displayed services using the "ALL" button.
  $w("#allButton").onClick((event) => {
    // Reset the filter to show all services
    const allQuery = wixData.filter();
    // Set the active category to "All"
    setActiveCategory("All", allQuery);
    // Scroll the page to the list of services.
    scrollToServiceStrip();
  });

  // Filter the displayed services using the "THERMO" button.
  $w("#thermoButton").onClick((event) => {
    // Create a filter that filters services by "Thermopompe murale" serviceName.
    const thermoQuery = wixData.filter().eq("serviceName", "Thermopompes murales");
    // Set the active category to "Thermopompe murale"
    setActiveCategory("Thermopompes murales", thermoQuery);
    // Scroll the page to the list of services.
    scrollToServiceStrip();
  });

  // Filter the displayed services using the "RESIDENTIAL" button.
  $w("#residentialButton").onClick((event) => {
    // Create a filter that filters services by "Systèmes et conduits résidentiels" serviceName.
    const residentialQuery = wixData.filter().eq("serviceName", "Systèmes et conduits résidentiels");
    // Set the active category to "Systèmes et conduits résidentiels"
    setActiveCategory("Systèmes et conduits résidentiels", residentialQuery);
    // Scroll the page to the list of services.
    scrollToServiceStrip();
  });

  // Filter the displayed services using the "COMMERCIAL" button.
  $w("#commercialButton").onClick((event) => {
    // Create a filter that filters services by "Systèmes et conduits commerciaux" serviceName.
    const commercialQuery = wixData.filter().eq("serviceName", "Systèmes et conduits commerciaux");
    // Set the active category to "Systèmes et conduits commerciaux"
    setActiveCategory("Systèmes et conduits commerciaux", commercialQuery);
    // Scroll the page to the list of services.
    scrollToServiceStrip();
  });
}

//-------------Change Category-------------//

// Set the category of services to display.
async function setActiveCategory(title, queryFilter) {
  $w("#servicesRepeater").data = [];
  // Populate the title text with the given title.
  $w("#stripTitle").text = title;
  showLoader(true);

  // Filter the dataset using the given filter.
  await $w("#dataset1").setFilter(queryFilter);
}

// Scroll down to the displayed services.
function scrollToServiceStrip() {
  $w("#servicesStrip").scrollTo();
}

//-------------Date Helpers-------------//

// Get the month and day of the given date formatted as DD/MM.
function getMonthDay(date) {
  return date.toLocaleDateString([], { day: "numeric", month: "numeric" });
}

Merci à l’avance pour votre aide ! :slight_smile: