Quick book and pending requests

I followed the quick book from and pending requests page tutorials and check over the code to be exactly as it should be (obviously having altered the service id etc to match the correct info and elements for my site).
But I have two issues:

  1. The time and date from the quick book form don’t seem to be sending data anywhere, they are not showing up on the pendingAppointments collection or on the pending appointments repeater.

  2. The buttons on the pending appointments page don’t seem to be working at all
    I’m pretty new to this so apologies if it’s something super simple. I’d appreciate any help!

Hi Lmarie,
I’ve moved your post to the Community Discussion category. Thanks.

Are you using this Corvid example here from the Wix Bookings section.
https://www.wix.com/corvid/example/quick-book-and-pending-appointments

This example here can be opened up in your Wix Editor fully made up with all elements and code setup etc. There is also a video to walk you through it as well.

Or an older one like here.
https://www.wix.com/corvid/forum/tips-tutorials-examples/video-wix-bookings-api-how-to-create-a-quick-booking-form

How to Create a Quick-Booking Form with the Wix Bookings API (Part 1/2)
( March 2019 )
How to Create a Quick-Booking Form with the Wix Bookings API (Part 1/2)
(April 2019)

How to Create a an Admin Page to Manage Booking Requests (Part 2/2)
( March 2019 )
How to Create an Admin Page to Manage Booking Requests (Part 2/2)
(April 2019)

Just need to make sure that we are all talking about the same tutorial as we might be thinking about the latest one and you are using an older one.

Also, check the related posts box and give the forum a search for quick bookings or similar as well to give you a chance of finding a previous post that might have already had the issues that you are having now.

Yep, that’s the one. I followed it all through and then pasted the code from the example page adjusting it to my site elements and serviceId. I also tried to look through previous posts but I couldn’t really find anything that was helpful.

So you are using the latest one in the Corvid Forum examples.
https://www.wix.com/corvid/example/quick-book-and-pending-appointments

When you say…’ I followed it all through and then pasted the code from the example page adjusting it to my site elements and serviceId…

Did you actually copy and paste all of the required code and use it fully as used on the provided sample? Or have you used parts of it and not used bits of the code?

Did you create the pending appointments dataset as like on the example, making sure that you checked the dataset permissions and modes too?
https://support.wix.com/en/article/working-with-dataset-modes-and-collection-permissions

The best option when using an example is to make your own elements the same id names as the tutorial, that way you know that the code will be okay and you don’t need to go through changing any incorrect element id name.

Is your code as this albeit with the element id name changes and the service id changes.

Quick Book.

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

// Import the wix-data module for working with collections.
import wixData from "wix-data";
// Import the wix-bookings module for getting available service slots.
import wixBookings from "wix-bookings";
import {setVisitorId} from 'public/managevisitors.js'

//-------------Global Variables-------------//
let visitorId;
// The ID of the Free Consultation service from the Bookings/Services collection.
const serviceId = "371e7fc0-c04b-4a88-8c1b-d8abf5d4b493";
// Map of available slots.
let slotsMap = {};

//-------------Lightbox Setup-------------//

$w.onReady(function () {
	visitorId = setVisitorId();
	// Get today's date.
	let today = new Date();

	// List of the days of the week.
	const daysOfTheWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
	
	//-------------Dropdowns Setup-------------//

	// Get a list of the next 7 days of the week, starting from today. Use that list to create
	// another list with labels and values and use it to populate the dayPicker dropdown. 
	$w("#dayPicker").options = getWeekDays(today).map(day => {
		return {
			// Set the label to be the name of the day of the week and its formatted date (e.g Tue 18/12/2018).
			label: `${daysOfTheWeek[day.date.getDay()]} ${day.date.toLocaleDateString("en-GB")}`,
			// Set the value to be the ISO string representation of the date (e.g. 2018-12-17T22:00:00.000Z).
			value: day.date.toISOString()
		}
	});

	// When a day of the week is selected in the day dropdown, populate the time dropdown with the times of
	// slots that are available on the selected day.
	$w("#dayPicker").onChange((event, $w) => {
		const selectedDate = new Date(event.target.value);
		findAvailableSlots(selectedDate);
	});

	// When the submit button is clicked, check that all the fields are valid and then insert the requested slot's
	// information into the pendingAppointments collection. 
	$w("#submitButton").onClick(() => validateAndSubmitForm());
});

async function findAvailableSlots(dateString) {
	// Reset the slot map to be empty.
	slotsMap = {};
	// Get the beginning time of the selected date.
	const startDateTime = getMidnight(dateString);
	// Get the ending time of the selected date.
	const endDateTime = getNextMidnight(dateString);

	// Set the options object which contains the date restrictions.
	const options = {
		startDateTime,
		endDateTime
	};

	// Get all available slots which are not already pending approval for the selected day.
	const availableSlots = await getNonPendingAvailableSlots(serviceId, options);

	// If no available slots are found:
	if (availableSlots.length === 0) {
		// Reset the time dropdown.
		$w("#slotPicker").options = [];
		$w("#slotPicker").placeholder = "No sessions this day";
		$w("#slotPicker").selectedIndex = undefined;
		$w("#slotPicker").disable();
	}
	// Otherwise, when available slots are found:
	else {
		// Populate the time dropdown with the start time of the available slot and store the 
		// available slots in the slot map by ID.
		$w("#slotPicker").options = availableSlots.map(slot => {
			const uniqueId = new Date().getUTCMilliseconds().toString() // Generate a short unique ID to identify options in the slotPicker

			slotsMap[uniqueId] = slot;
			let startTime = slot.startDateTime;
			let timeString = getTimeOfDay(startTime);
			return {
				label: timeString,
				value: uniqueId
			}
		});
		// Reset the time dropdown's placeholder text.
		$w("#slotPicker").placeholder = "Pick a time";
		// Reset the time dropdown, so no item is selected.
		$w("#slotPicker").selectedIndex = undefined;
		$w("#slotPicker").enable();
	}
}

//-------------Form Submission-------------//

async function validateAndSubmitForm() {
	// Hide the error state.
	$w("#errorMessage").hide();
	$w("#submitButton").disable();

	// List of fields in the booking form.
	const formFields = ["nameInput", "emailInput", "ageInput", "dayPicker", "slotPicker", "agreementCheckbox"];

	// If all the fields have valid values:
	if (formFields.every(input => $w(`#${input}`).valid)) {
		// Get the selected slot object from the slot map.
		const slot = slotsMap[$w("#slotPicker").value];
		// Create a new request item to be inserted in the pendingAppointments collection containing the form field
		// values, the slot object, and set its status to pending.
		const newRequest = {
			name: $w("#nameInput").value,
			email: $w("#emailInput").value,
			age: $w("#ageInput").value,
			requestedSlot: slot,
			visitorId: visitorId,
			status: "PENDING"
		};
		// Insert the requested slot information into the pendingAppointments collection.
		await wixData.insert("pendingAppointments", newRequest);
		// Show the thank you state.
		$w("#formGroup").hide();
		$w("#thankYouText").show();
	}
	// If some of the fields have invalid values:
	else {
		// Show the error state.
		$w("#errorMessage").show();
		$w("#submitButton").enable();
	}
}

//-------------Slot Availability Determination-------------//

// Get all available slots which are not already pending approval.
async function getNonPendingAvailableSlots(requestedServiceId, options = {}) {
	// Get the IDs of all the appointments that have been requested but are still pending approval.
	const pending = (await getPendingAppointments()).map(appointment => appointment.requestedSlot._id);
	// Get all of the service's available slots during the given date range.
	let availableSlots = (await wixBookings.getServiceAvailability(requestedServiceId, options)).slots;
	// Filter out of the available slots all slots that are pending approval.
	availableSlots = availableSlots.filter(slot => !pending.includes(slot._id));
	// Return the filtered list.
	return availableSlots;
}

// Get the appointments that are pending from the pendingAppointments collection.
async function getPendingAppointments() {
	return (await wixData.query("pendingAppointments").find()).items.filter(item => item.status === "PENDING");
}

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

// Get a list of the next 7 days of the week, starting from a given date.
function getWeekDays(startDate) {
	// Create an empty list of days.
	let weekDays = [];
	// Get the midnight that started today's day.
	let current = getMidnight(startDate);

	// For 7 days:
	for (let i = 0; i < 7; i++) {
		// Add to the list of days an object with a running day ID and the day's date.
		weekDays.push({
			_id: "day" + i,
			date: current
		});
		// Get the midnight of the next day.
		current = getNextMidnight(current);
	}
	// Return the list of days.
	return weekDays;
}

// Get the midnight that started the given date's day.
function getMidnight(date) {
	// Create a new date which is a copy of the given date.
	let midnight = new Date(date);
	// Set the new date's time to the previous midnight.
	midnight.setHours(0, 0, 0, 0);
	// Return the new date.
	return midnight;
}

// Get the midnight that starts the day after the given date.
function getNextMidnight(date) {
	// Create a new date which is a copy of the given date.
	let midnight = new Date(date);
	// Set the new date's time to the next midnight.
	midnight.setHours(24, 0, 0, 0);
	// Return the new date.
	return midnight;
}

// Get the time of the given date formatted as HH:MM AM/PM.
function getTimeOfDay(date) {
	return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }).toLowerCase();
}

Pending Appointments,

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

// Import the wix-data module for working with collections.
import wixData from "wix-data";
// Import the wix-bookings module for booking appointments.
import wixBookings from "wix-bookings";
// Import the wix-location module for sending emails for dismissed appointments.
import wixLocation from "wix-location";

//-------------Page Setup-------------//

$w.onReady(function () {
	// When the pending requests dataset is ready:
	$w("#pendingRequestsDataset").onReady(() => {
		// If there are no pending requests:
		if ($w("#pendingRequestsDataset").getTotalCount() === 0) {
			// Show the no pending requests message.
			$w("#noPendingRequests").show();
		}
	});
});

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

// Set up each item in the requests repeater as it is loaded.
export function requestsRepeater_itemReady($item, itemData, index) {
	// Get the requested slot from the item's data.
	const slot = itemData.requestedSlot;
	// Get the requested slot's start date and time.
	const start = new Date(slot.startDateTime);
	// Populate the date field with the slot's start date.
	$item("#date").text = getDate(start);
	// Populate the time field with the slot's start time.
	$item("#time").text = getTimeOfDay(start);

	// Set the dismiss button to dismiss the appointment request when clicked.
	$item("#dismissButton").onClick(async () => {
		// Disable the dismiss and approve buttons.
		$item("#dismissButton").disable();
		$item("#approveButton").disable();
		// Dismiss the appointment request.
		await dismissRequest(itemData, index, $w);
	});

	// Set the approve button to approve the appointment request when clicked.
	$item("#approveButton").onClick(async () => {
		// Disable the dismiss and approve buttons.
		$item("#dismissButton").disable();
		$item("#approveButton").disable();
		// Approve the appointment request.
		await approveRequest(itemData, index);
	});
}

// Set up each item in the dismissed requests repeater as it is loaded.
export function dismissedRequests_itemReady($item, itemData, index) {
	// Set the contact button to create an email to the user whose request was dismissed.
	$item("#emailButton").onClick(() => {
		const subject = "Thanks For Getting in Touch";
		wixLocation.to(`mailto:${itemData.email}?subject=${subject}`);
	});
}

//-------------Request Dismissal-------------//

// Dismiss the requested appointment.
async function dismissRequest(pendingRequest, index, $w) {
	// Dismiss the requested appointment.
    // Set the requested appointment's status to dismissed.
	pendingRequest.status = "DISMISSED";
	// Update the requested appointment in the pendingAppointments collection.
    await wixData.update("pendingAppointments", pendingRequest);
	// Refresh the page's data and update page elements.
	refreshData();
}

//-------------Request Approval-------------//

// Approve the requested appointment.
async function approveRequest(pendingRequest, index) {
	// Get the requested appointment's slot object.
	const slot = pendingRequest.requestedSlot;
	// Get the requested appointment's service data.
	const service = await getService(slot.serviceId);
	// Create a form fields object with the values the user entered in the booking form.
	let formFields = [{
			// Set _id to the ID of the name field.
			_id: getFieldId(service, "Name"),
			// Set value to the name the user entered.
			value: pendingRequest.name
		},
		{
			// Set _id to the ID of the email field.
			_id: getFieldId(service, "Email"),
			// Set value to the email address the user entered.
			value: pendingRequest.email
		}
	];

	// Create the bookingInfo object needed when performing a booking. It consists of the
	// requested appointment's slot and the form field values entered in the booking form.
	const bookingInfo = {
		slot,
		formFields
	};

	try {
		// Perform the booking for the requested appointment.
		const bookingResponse = await wixBookings.checkoutBooking(bookingInfo);
		// If the booking is confirmed:
		if (bookingResponse.status === "Confirmed") {
			// Approve the requested appointment.
			// Set the requested appointment's status to approved.
			pendingRequest.status = "APPROVED";
			// Update the requested appointment in the pendingAppointments collection. 
			await wixData.update("pendingAppointments", pendingRequest);
			// Refresh the page's data and update page elements.
			refreshData();
		} 
		// If the booking is not confirmed:
		else {
			// Enable the approve button.
			$w("#approveButton").enable();
		}
	} 
	// If an error occurred in the booking process:
	catch (error) {
		// Enable the approve button.
		$w("#approveButton").enable();
	}
}

//-------------Service Helpers-------------//

// Get a service from the Services collection by ID.
async function getService(id) {
    return wixData.get("Bookings/Services", id);
}

// Get a field ID from a service for a given label.
function getFieldId(service, label) {
	return service.form.fields.filter(field => field.label === label)[0]._id;
}

//-------------Page Update-------------//

// Refresh the page's datasets and update all the elements that are connected to them.
function refreshData() {
	// Refresh the pending requests dataset and update all the elements that are connected to it.
	$w("#pendingRequestsDataset").refresh().then(() => {
		// If there are no pending requests:
		if ($w("#pendingRequestsDataset").getTotalCount() === 0) {
			// Show the no pending requests message.
			$w("#noPendingRequests").show();
		}
	});
	// Refresh the dismissed requests dataset and update all the elements that are connected to it.
	$w("#dismissedRequestsDataset").refresh();
}

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

// Get the time of the given date formatted as HH:MM am/pm.
function getTimeOfDay(date) {
	return date.toLocaleTimeString("en-GB", {hour: "2-digit", minute:"2-digit",  hour12: true});
}

// Get the date of the given date formatted as DD/MM/YYYY.
function getDate(date) {
	return  date.toLocaleDateString("en-GB", {day: "numeric", month: "numeric", year: "numeric" });
}

As for the buttons on the pending appointments page, note that they are in a repeater and the repeater itself needs to have onItemReady event handler function added to it through the properties panel for that repeater.

Just check that if you have not added it already, that when you do it does not add an axtra ‘_1’ to the end of ‘requestsRepeater’ as in the example.

As you should already have it in your code, if you have to add it again it will automatically assume that you are creating a new one and will add it like ‘requestsRepeater_1’ or similar and add the extra line of code for it at the bottom of your existing code.

For the request repeater above, it is in your code here.

// Set up each item in the requests repeater as it is loaded.
export function requestsRepeater_itemReady($item, itemData, index) {
 // Get the requested slot from the item's data.

So, if you do have to add it then make sure that you go to the end of the name and check and delete the extra _1 if it is there.

Double check any other elements like repeaters and buttons on the example to make sure that you are not missing out any other event function from the properties panel too.

You can read more here about working in the properties panel.
https://support.wix.com/en/article/corvid-working-with-the-properties-panel
https://support.wix.com/en/article/changing-your-database-collection-permissions

Also, just so that you are aware, you don;t always have to use the properties panel if you need to use an event handler function.

Take a button and the onClick event handler function.

You can write it in the code itself so that you don’t need to add anything to it like this here.

$w("#forgotPassword").onClick( (event) => {

However, where you have it written with an export function like with the requests repeater element, so for the forgot password button it would be like this…

export function forgotPassword_onclick(event) {

…you need to add the onClick event handler function through the properties panel as in the pic example for the request repeater and in the linked Wix Support page about the properties panel too.

Okay so I have been through everything again, copied the code from your comment and used that to replace what I had. I think it’s worked!

I had deleted the code related to email and age inputs because I didn’t feel I needed them for my form but I’ve now added them as elements and kept them in the code. I also added the onItemReady function via the properties panel as you suggested (this hadn’t been added, although it was showing in the code).

On the preview the dates are now showing! I don’t know whether it was because the email and age inputs are necessary and that’s why it wasn’t working or because of the onItemReady not being added or both… but thank you for your help!

I’m wondering if there’s a simple enough way to autofill the emailInput and age fields with the email address of the logged-in-user? I know there is logged-in-user filter in datasets sometimes but I’m not sure exactly how to get the users email and how I could make it work with this code without messing anything up…

Only other thing is that I’m now getting this error message in the preview code " Cannot find module ‘public/managevisitors.js’ in ‘public/pages/ldj5w.js’"

I know that the following import code wasn’t part of the code detailed in the tutorial video (but it does show up on the example code).

import {setVisitorId} from 'public/managevisitors.js'

I’m not sure what ‘public/managevisitors.js’ is but I wonder if this data doesn’t exist in my site for some reason?

Yes I was wondering about that managevisitors.js file myself as there is nothing in the public folder in the site structure.

Delete that line and see if it affects your page, in theory it shouldn’t as there is no file in public.

As for getting email etc, you can do that as shown in this Vorbly link here.
https://www.vorbly.com/Vorbly-Code/WIX-CODE-AUTO-FILL-FORM-WITH-USER-INPUTS

Easier for you to read and see examples, plus read the Wix API Reference pages about the functions too.
https://www.wix.com/corvid/reference/wix-dataset.Dataset.html#getCurrentItem
https://www.wix.com/corvid/reference/wix-dataset.Dataset.html#setFieldValue
https://www.wix.com/corvid/reference/wix-dataset.Dataset.html#setFieldValues

If you are using the Wix Members app then you can simply use a text box linked to the Members app collection for first name or email etc.
https://support.wix.com/en/article/corvid-wix-members-privatemembersdata-collection-fields

As the user is already logged in, then the text box that is connected to the dataset should only show that specific site members data.

If you have used another dataset for collecting members details like in this tutorial here, then simply contact the dataset links to that one instead.
https://support.wix.com/en/article/corvid-tutorial-building-your-own-members-area

You would still need to use the save function through code or a submit button for this to save the auto filled inputs.

Me again… :joy:

So I now have a lovely new issue with the pending appointments page.

On page load, everything is fine and showing as it should (like below):

But when I click the ‘approve’ or ‘dismiss’ buttons, they just grey out and disable and nothing happens at all. They don’t actually submit any information, nothing moves to the dismissed requests section and when I refresh the page it just goes back to how it was (I’m guessing the buttons are just disabling on click instead of doing what the code is telling them to do?).

This is the code I’m using:

import wixData from 'wix-data';
import wixBookings from 'wix-bookings';
import wixLocation from 'wix-location';



$w.onReady(function () {
 // When the pending requests dataset is ready:
    $w("#pendingRequestsDataset").onReady(() => {
 // If there are no pending requests:
 if ($w("#pendingRequestsDataset").getTotalCount() === 0) {
 // Show the no pending requests message.
            $w("#noPendingRequests").show();
        }
    });

});

export function requestsRepeater_itemReady($item, itemData, index) {
 // Get the requested slot from the item's data.
 const slot = itemData.requestedSlot;

 // Set the dismiss button to dismiss the appointment request when clicked.
    $item("#dismissButton").onClick(async () => {
 // Disable the dismiss and approve buttons.
        $item("#dismissButton").disable();
        $item("#approveButton").disable();
 // Dismiss the appointment request.
 await dismissRequest(itemData, index, $w);
    });

 // Set the approve button to approve the appointment request when clicked.
    $item("#approveButton").onClick(async () => {
 // Disable the dismiss and approve buttons.
        $item("#dismissButton").disable();
        $item("#approveButton").disable();
 // Approve the appointment request.
 await approveRequest(itemData, index);
    });
}

export function dismissedRequests_itemReady($item, itemData, index) {
 // Set the contact button to create an email to the user whose request was dismissed.
    $item("#emailButton").onClick(() => {
 const subject = "Thanks For Getting in Touch";
        wixLocation.to(`mailto:${itemData.email}?subject=${subject}`);
    });
}

//-------------Request Dismissal-------------//

// Dismiss the requested appointment.
async function dismissRequest(pendingRequest, index, $w) {
 // Dismiss the requested appointment.
 // Set the requested appointment's status to dismissed.
    pendingRequest.status = "DISMISSED";
 // Update the requested appointment in the pendingAppointments collection.
 await wixData.update("pendingAppointments", pendingRequest);
 // Refresh the page's data and update page elements.
    refreshData();
}

//-------------Request Approval-------------//

// Approve the requested appointment.
async function approveRequest(pendingRequest, index) {
 // Get the requested appointment's slot object.
 const slot = pendingRequest.requestedSlot;
 // Get the requested appointment's service data.
 const service = await getService(slot.serviceId);
 // Create a form fields object with the values the user entered in the booking form.
 let formFields = [{
 // Set _id to the ID of the name field.
            _id: getFieldId(service, "Name"),
 // Set value to the name the user entered.
            value: pendingRequest.name
        },
        {
 // Set _id to the ID of the email field.
            _id: getFieldId(service, "Email"),
 // Set value to the email address the user entered.
            value: pendingRequest.email
        }
    ];

 // Create the bookingInfo object needed when performing a booking. It consists of the
 // requested appointment's slot and the form field values entered in the booking form.
 const bookingInfo = {
        slot,
        formFields
    };

 try {
 // Perform the booking for the requested appointment.
 const bookingResponse = await wixBookings.checkoutBooking(bookingInfo);
 // If the booking is confirmed:
 if (bookingResponse.status === "Confirmed") {
 // Approve the requested appointment.
 // Set the requested appointment's status to approved.
            pendingRequest.status = "APPROVED";
 // Update the requested appointment in the pendingAppointments collection. 
 await wixData.update("pendingAppointments", pendingRequest);
 // Refresh the page's data and update page elements.
            refreshData();
        } 
 // If the booking is not confirmed:
 else {
 // Enable the approve button.
            $w("#approveButton").enable();
        }
    } 
 // If an error occurred in the booking process:
 catch (error) {
 // Enable the approve button.
        $w("#approveButton").enable();
    }
}

//-------------Service Helpers-------------//

// Get a service from the Services collection by ID.
async function getService(id) {
 return wixData.get("Bookings/Services", id);
}

// Get a field ID from a service for a given label.
function getFieldId(service, label) {
 return service.form.fields.filter(field => field.label === label)[0]._id;
}

//-------------Page Update-------------//

// Refresh the page's datasets and update all the elements that are connected to them.
function refreshData() {
 // Refresh the pending requests dataset and update all the elements that are connected to it.
    $w("#pendingRequestsDataset").refresh().then(() => {
 // If there are no pending requests:
 if ($w("#pendingRequestsDataset").getTotalCount() === 0) {
 // Show the no pending requests message.
            $w("#noPendingRequests").show();
        }
    });
 // Refresh the dismissed requests dataset and update all the elements that are connected to it.
    $w("#dismissedRequestsDataset").refresh();
}

I will take a look at this asap as only on here for a quick look and answer.
Post here if you manage to sort anything in the meanwhile.

You are missing code from two parts of your used code.

Here First…

Yours:

// Set up each item in the requests repeater as it is loaded.
export function requestsRepeater_itemReady($item, itemData, index) {
 // Get the requested slot from the item's data.
 const slot = itemData.requestedSlot;

 // Set the dismiss button to dismiss the appointment request when clicked.

Example:

// Set up each item in the requests repeater as it is loaded.
export function requestsRepeater_itemReady($item, itemData, index) {
	// Get the requested slot from the item's data.
	const slot = itemData.requestedSlot;
	// Get the requested slot's start date and time.
	const start = new Date(slot.startDateTime);
	// Populate the date field with the slot's start date.
	$item("#date").text = getDate(start);
	// Populate the time field with the slot's start time.
	$item("#time").text = getTimeOfDay(start);

	// Set the dismiss button to dismiss the appointment request when clicked.

Here Second…

Yours:

// Refresh the dismissed requests dataset and update all the elements that are connected to it.
    $w("#dismissedRequestsDataset").refresh();
}
//End of code//

Example:

// Refresh the dismissed requests dataset and update all the elements that are connected to it.
	$w("#dismissedRequestsDataset").refresh();
}

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

// Get the time of the given date formatted as HH:MM am/pm.
function getTimeOfDay(date) {
	return date.toLocaleTimeString("en-GB", {hour: "2-digit", minute:"2-digit",  hour12: true});
}

// Get the date of the given date formatted as DD/MM/YYYY.
function getDate(date) {
	return  date.toLocaleDateString("en-GB", {day: "numeric", month: "numeric", year: "numeric" });
}
//End of code//

instead of picking a day and a time, I need it to be a date

I’ve changed it all and added the two slot pickers as shown in the tutorial instead. Seems to work fine on preview mode but on the live site it’s not working…

The submit button just disables instead of submitting the form.

Here’s the code as it is now:

import wixUsers from 'wix-users';
import wixData from 'wix-data';
import wixBookings from 'wix-bookings';
import wixLocation from 'wix-location';

// The ID of the Free Consultation service from the Bookings/Services collection.
const serviceId = "a940f155-af5e-4c1c-b552-68ef0a9962b8";
// Map of available slots.
let slotsMap = {};

$w.onReady(function(){

 const user = wixUsers.currentUser;
  user.getRoles()
    .then(roles => {
 let firstRole = roles[0];
 let roleName = firstRole.name;
 let roleDescription = firstRole.description;
 if (roles[0].name === 'Artist') {
        $w('#section14').collapse();
        $w('#button4').enable();
      } else {
        $w('#section14').expand();
        $w('#button4').disable();
      }
    });

user.getEmail()
  .then( (email) => {
 let userEmail = email; // "user@something.com"
    $w("#emailInput").value = userEmail;
  } );

  wixData.query("Members/PrivateMembersData")
  .eq("_id", wixUsers.currentUser.id)
  .find()
  .then( (results) => {
    $w("#nameInput").value = results.items[0].name;
    $w("#usernameInput").value = results.items[0].slug; 
  } );

 // Get today's date.
 let today = new Date();

 // List of the days of the week.
 const daysOfTheWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
 
 //-------------Dropdowns Setup-------------//

 // Get a list of the next 7 days of the week, starting from today. Use that list to create
 // another list with labels and values and use it to populate the dayPicker dropdown. 
  $w("#dayPicker").options = getWeekDays(today).map(day => {
 return {
 // Set the label to be the name of the day of the week and its formatted date (e.g Tue 18/12/2018).
      label: `${daysOfTheWeek[day.date.getDay()]} ${day.date.toLocaleDateString("en-GB")}`,
 // Set the value to be the ISO string representation of the date (e.g. 2018-12-17T22:00:00.000Z).
      value: day.date.toISOString()
    }
  });

 // When a day of the week is selected in the day dropdown, populate the time dropdown with the times of
 // slots that are available on the selected day.
  $w("#dayPicker").onChange((event, $w) => {
 const selectedDate = new Date(event.target.value);
    findAvailableSlots(selectedDate);
  });

 // When the submit button is clicked, check that all the fields are valid and then insert the requested slot's
 // information into the pendingAppointments collection. 
  $w("#submitButton").onClick(() => validateAndSubmitForm());
});

async function findAvailableSlots(dateString) {
 // Reset the slot map to be empty.
  slotsMap = {};
 // Get the beginning time of the selected date.
 const startDateTime = getMidnight(dateString);
 // Get the ending time of the selected date.
 const endDateTime = getNextMidnight(dateString);

 // Set the options object which contains the date restrictions.
 const options = {
    startDateTime,
    endDateTime
  };

 // Get all available slots which are not already pending approval for the selected day.
 const availableSlots = await getNonPendingAvailableSlots(serviceId, options);

 // If no available slots are found:
 if (availableSlots.length === 0) {
 // Reset the time dropdown.
    $w("#slotPicker").options = [];
    $w("#slotPicker").placeholder = "No sessions this day";
    $w("#slotPicker").selectedIndex = undefined;
    $w("#slotPicker").disable();
  }
 // Otherwise, when available slots are found:
 else {
 // Populate the time dropdown with the start time of the available slot and store the 
 // available slots in the slot map by ID.
    $w("#slotPicker").options = availableSlots.map(slot => {
 const uniqueId = new Date().getUTCMilliseconds().toString() // Generate a short unique ID to identify options in the slotPicker

      slotsMap[uniqueId] = slot;
 let startTime = slot.startDateTime;
 let timeString = getTimeOfDay(startTime);
 return {
        label: timeString,
        value: uniqueId
      }
    });
 // Reset the time dropdown's placeholder text.
    $w("#slotPicker").placeholder = "Pick a time";
 // Reset the time dropdown, so no item is selected.
    $w("#slotPicker").selectedIndex = undefined;
    $w("#slotPicker").enable();
  }
}


 //-------------Setlist Form Submission-------------//

async function validateAndSubmitForm() {
 // Hide the error state.
  $w("#errorMessage").hide();
  $w("#submitButton").disable();

 // List of fields in the booking form.
 const formFields = ["nameInput", "emailInput", "ageInput", "dayPicker", "slotPicker", "agreementCheckbox", "conductCheckbox"];

 // If all the fields have valid values:
 if (formFields.every(input => $w(`#${input}`).valid)) {
 // Create a new request item to be inserted in the pendingAppointments collection containing the form field
 // values, and set its status to pending.// Get the selected slot object from the slot map.
 const slot = slotsMap[$w("#slotPicker").value];
 // Create a new request item to be inserted in the pendingAppointments collection containing the form field
 // values, the slot object, and set its status to pending.

 const newRequest = {
      name: $w("#nameInput").value,
      email: $w("#emailInput").value,
      age: $w("#ageInput").value,
      username: $w("#usernameInput").value,
      requestedSlot: slot,
      status: "PENDING"
    };
 // Insert the requested slot information into the pendingAppointments collection.
 await wixData.insert("pendingAppointments", newRequest);
 // Show the thank you state.
    $w("#formGroup").hide();
    $w("#thankYouText").show();
  }
 // If some of the fields have invalid values:
 else {
 // Show the error state.
    $w("#errorMessage").show();
    $w("#submitButton").enable();
  }
}

//-------------Slot Availability Determination-------------//

// Get all available slots which are not already pending approval.
async function getNonPendingAvailableSlots(requestedServiceId, options = {}) {
 // Get the IDs of all the appointments that have been requested but are still pending approval.
 const pending = (await getPendingAppointments()).map(appointment => appointment.requestedSlot._id);
 // Get all of the service's available slots during the given date range.
 let availableSlots = (await wixBookings.getServiceAvailability(requestedServiceId, options)).slots;
 // Filter out of the available slots all slots that are pending approval.
  availableSlots = availableSlots.filter(slot => !pending.includes(slot._id));
 // Return the filtered list.
 return availableSlots;
}

// Get the appointments that are pending from the pendingAppointments collection.
async function getPendingAppointments() {
 return (await wixData.query("pendingAppointments").find()).items.filter(item => item.status === "PENDING");
}

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

// Get a list of the next 7 days of the week, starting from a given date.
function getWeekDays(startDate) {
 // Create an empty list of days.
 let weekDays = [];
 // Get the midnight that started today's day.
 let current = getMidnight(startDate);

 // For 7 days:
 for (let i = 0; i < 7; i++) {
 // Add to the list of days an object with a running day ID and the day's date.
    weekDays.push({
      _id: "day" + i,
      date: current
    });
 // Get the midnight of the next day.
    current = getNextMidnight(current);
  }
 // Return the list of days.
 return weekDays;
}

// Get the midnight that started the given date's day.
function getMidnight(date) {
 // Create a new date which is a copy of the given date.
 let midnight = new Date(date);
 // Set the new date's time to the previous midnight.
  midnight.setHours(0, 0, 0, 0);
 // Return the new date.
 return midnight;
}

// Get the midnight that starts the day after the given date.
function getNextMidnight(date) {
 // Create a new date which is a copy of the given date.
 let midnight = new Date(date);
 // Set the new date's time to the next midnight.
  midnight.setHours(24, 0, 0, 0);
 // Return the new date.
 return midnight;
}

// Get the time of the given date formatted as HH:MM AM/PM.
function getTimeOfDay(date) {
 return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }).toLowerCase();
}



export function button4_click(event) {
 const user = wixUsers.currentUser;
  user.getRoles()
    .then(roles => {
 let firstRole = roles[0];
 let roleName = firstRole.name;
 let roleDescription = firstRole.description;
 if (user.loggedIn && roles[0].name === 'Artist') {
        $w('#section14').collapse();
        $w('#setlistSignupSection').expand();
      } else {
        $w('#section14').expand();
      }
    })
}

export function button3_click(event) {
  $w('#section4').expand(); 
}

wixUsers.onLogin(() => {
 const user = wixUsers.currentUser;
  user.getRoles()
    .then(roles => {
 let firstRole = roles[0];
 let roleName = firstRole.name;
 let roleDescription = firstRole.description;
 if (roles[0].name === 'Artist') {
        $w('#section14').collapse();
        $w('#button4').enable();
      } else {
        $w('#section14').expand();
        $w('#button4').disable();
      }
    });
});

https://lm1223.editorx.io/responsive/blank-1

There’s the page the form is on, you’d need to log in to view the form. If you’d like to check it the you can use this test login: test@test.com password: testing