반응형
윅스 (Wix) 코딩 강의 중급 (Intermediate) - 예약시스템 만들기 (Quick Book and Pending Appointments) - 윅스 예약시스템 (Wix Bookings)
강의 내용 요약
다음의 예제는 Wix 윅스 무료 홈페이지 만들기의 자바스크립트 (Javascript) 코딩 기능을 활용할 수 있는 Corvid by Wix (윅스 코딩 - 콜비드) 를 활용하여 만듭니다.
웹사이트 내에 예약 기능을 활용하여 사이트 방문자들이 예약을 빠르게 할 수 있도록 하고 예약이 승인이 되었는지 혹은 예약이 불가한지에 대해서 확인할 수 있는 기능을 만듭니다.
강의 내용 만드는법
만들고자 하는 윅스 사이트에 다음과 같은 구성 요소들이 필요합니다.
- 데이터베이스 컬렉션 (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
Corvid by Wix (윅스 코딩 - 콜비드) 개발자 모드/도구 활성화하는 방법
윅스 (Wix) 코딩 - 개발자 도구를 활성화하기 (Wix Code: How to Enable Developer Tools)
연관된 토픽)
윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 페이지 (Service Page) - 윅스 예약시스템 (Wix Bookings)
윅스 홈페이지 만들기 101
윅스 (Wix) 홈페이지 만들기 101 - E-Book - Index
출처 :
콜비드 - 윅스 코딩 (Corvid - Wix coding)
반응형
댓글