본문 바로가기
윅스 (Wix) 홈페이지 만들기/Corvid by Wix (윅스 코딩 - 콜비드) 강의

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 예약시스템 만들기 (Quick Book and Pending Appointments) - 윅스 예약시스템 (Wix Bookings)

by 라임쥬서(Lime Juicer) 2020. 5. 11.
반응형

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 예약시스템 만들기 (Quick Book and Pending Appointments) - 윅스 예약시스템 (Wix Bookings)

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 예약시스템 만들기 (Quick Book and Pending Appointments) - 윅스 예약시스템 (Wix Bookings)

강의 내용 요약

다음의 예제는 Wix 윅스 무료 홈페이지 만들기의 자바스크립트 (Javascript) 코딩 기능을 활용할 수 있는 Corvid by Wix (윅스 코딩 - 콜비드) 를 활용하여 만듭니다.

 

웹사이트 내에 예약 기능을 활용하여 사이트 방문자들이 예약을 빠르게 할 수 있도록 하고 예약이 승인이 되었는지 혹은 예약이 불가한지에 대해서 확인할 수 있는 기능을 만듭니다.

 

 

 

예제 보러가기 (View Example)

 

Home | Quick Book & Pending

FREE ACUPUNCTURE CONSULTATION Follow your path to personal wellness and leave any headaches, joint pain, and allergies behind. Consult LEVEL’s licensed acupuncturist to create a personalized treatment plan.

www.wix.com

 

예제 에디터 확인하기 (Edit Now)

 

Log In | Wix

Login to Wix.com

users.wix.com

 

 

강의 내용 만드는법

만들고자 하는 윅스 사이트에 다음과 같은 구성 요소들이 필요합니다.

  • 데이터베이스 컬렉션 (pendingAppointments)
  • 버튼
  • 라이트박스
  • 입력란 

 

 

코드 (Code)

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" });
}

 

Home

// This page does not contain any code.
// It contains a short description of a service and a button site visitors can click to open the Quick Book lightbox.

 

API

Wix Data API

Wix Bookings API

Wix Location API

 

Corvid by Wix (윅스 코딩 - 콜비드) 개발자 모드/도구 활성화하는 방법

윅스 (Wix) 코딩 - 개발자 도구를 활성화하기 (Wix Code: How to Enable Developer Tools)

 

윅스 (Wix) 코딩 - 개발자 도구를 활성화하기 (Wix Code: How to Enable Developer Tools)

윅스 (Wix) 코딩 - 개발자 도구를 활성화하기 (Wix Code: How to Enable Developer Tools) 설명) 개발자 도구를 활성화하기 위해서는 1. 에디터를 엽니다. 에디터 맨 위 상단 메뉴에서 코드를 클릭한 다음 개발�

limejuicer.tistory.com

 

 

연관된 토픽)

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 페이지 (Service Page) - 윅스 예약시스템 (Wix Bookings)

 

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 페이지 (Service Page) - 윅스 예약시스템 (Wix Bookings)

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 페이지 (Service Page) - 윅스 예약시스템 (Wix Bookings) 강의 내용 요약 다음의 예제는 Wix 윅스 무료 홈페이지 만들기의 자바스크립트 (Javascript) 코딩..

limejuicer.tistory.com

 

윅스 홈페이지 만들기 101

윅스 (Wix) 홈페이지 만들기 101 - E-Book - Index

 

윅스 (Wix) 홈페이지 만들기 101 - E-Book - Index

윅스 (Wix) 홈페이지 만들기 101 - E-Book - Index 윅스 (Wix.com) 윅스 ADI & 템플릿 (Wix ADI & 템플릿) 윅스 웹에디터 (Wix Editor) 윅스 코딩 (Wix Code - Corvid) 윅스 해커톤 (Wix Hackathon)

limejuicer.tistory.com

 

출처 :

콜비드 - 윅스 코딩 (Corvid - Wix coding)

 

Quick Book and Pending Appointments | Corvid by Wix Examples | Wix.com

In this example, a site visitor can request a service booking using a simple quick book form. An admin can view all of the requested bookings and decide which ones to approve and which ones to decline.

www.wix.com

 

반응형

댓글