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

윅스 (Wix) 코딩 강의 고급 (Advanced) - 예약시간표 만들기 (Timetable) - 윅스 예약시스템 (Wix Bookings)

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

윅스 (Wix) 코딩 강의 고급 (Advanced) - 예약시간표 만들기 (Timetable) - 윅스 예약시스템 (Wix Bookings)

윅스 (Wix) 코딩 강의 고급 (Advanced) - 예약시간표 만들기 (Timetable) - 윅스 예약시스템 (Wix Bookings)

강의 내용 요약

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

 

웹사이트 내에 예약 시간표를 만들어 방문자들이 예약할 수 있는 기능을 만듭니다.

 

예제 보러가기 (View Example)

 

Schedule | Time Table

No Classes Today. Try another day.

www.wix.com

 

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

 

Log In | Wix

Login to Wix.com

users.wix.com

 

 

강의 내용 만드는법

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

  • 데이터베이스 컬렉션
  • 반복레이아웃 /리피터
  • 버튼
  • 텍스트

 

코드 (Code)

Schedule

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

// Import the wix-data module for working with queries.
import wixData from "wix-data";
// Import the wix-bookings module for getting available service slots.
import wixBookings from "wix-bookings";
// Import the wix-window module for determining the type of device the site is being viewed on.
import wixWindow from "wix-window";
// Import session storage to pass information between pages.
import { session } from "wix-storage";

//-------------Global Variables-------------//

// The selected day.
let activeDay;
// Map of staff members.
let staffMap = {};
// Map of services.
let servicesMap = {};
// List of services.
let services = [];
// Whether the site is being viewed on a mobile device.
let isMobile;

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

$w.onReady(function () {
	// Get whether the the site is being viewed on a mobile device.
	isMobile = wixWindow.formFactor === "Mobile";
	handleLoaders(true);
	initializeSlots();
});

function handleLoaders(show = true) {
	if (show === true && isMobile) {
		$w("#slotsLoaderMobile").show()
		$w("#slotsLoader").hide()
		$w("#toolbarLoaderMobile").show()
		$w("#toolbarLoader").hide()
	}
	else if (show === true && !isMobile) {
		$w("#slotsLoaderMobile").hide()
		$w("#slotsLoader").show()
		$w("#toolbarLoaderMobile").hide()
		$w("#toolbarLoader").show()
	}
	else if (show === false) {
		$w("#slotsLoaderMobile").hide()
		$w("#slotsLoader").hide()
		$w("#toolbarLoaderMobile").hide()
		$w("#toolbarLoader").hide()
	}
}

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

	// Get all the staff from the Staff collection.
	const staff = await getAllStaff();
	// Put the staff members in a map for easy access by ID.
	staff.forEach(member => staffMap[member._id] = member);

	// Set the selected day to today's date.
	setActiveDay(new Date());

	// Set up the days toolbar functionality and show relevant dates.
	setupDaysToolbar();

}

// Set up the days toolbar functionality and show relevant dates.
function setupDaysToolbar() {
	// Set the first day as the global active day.
	let firstDay = activeDay;
	// Populate the day toolbar, starting from the global active day.
	populateDaysToolbar(firstDay);
	// If the site is being viewed on a mobile device:
	if (isMobile) {
		// Set the back button to go back one day when clicked.
		$w("#backButton").onClick(() => {
			setActiveDay(getPreviousMidnight(activeDay));
			firstDay = activeDay;
			populateDaysToolbar(firstDay);
		});
		// Set the forward button to go forward one day when clicked.
		$w("#forwardButton").onClick(() => {
			setActiveDay(getNextMidnight(activeDay));
			firstDay = activeDay;
			populateDaysToolbar(firstDay);
		});
	}
	// If the site is not being viewed on a mobile device:
	else {
		// Set the back button to go back one week when clicked.
		$w("#backButton").onClick(() => {
			firstDay = getDatePreviousWeek(firstDay);
			populateDaysToolbar(firstDay);
		});
		// Set the forward button to go forward one week when clicked.
		$w("#forwardButton").onClick(() => {
			firstDay = getDateNextWeek(firstDay);
			populateDaysToolbar(firstDay);
		});
	}
	handleLoaders(false);
	$w("#daysToolbar").show();
}

// Populate the day toolbar, starting from the given date.
function populateDaysToolbar(startDate) {
	// Reset the repeater's data to an empty array.
	$w("#daysToolbar").data = [];
	// If the site is being viewed on a mobile device set the repeater's data to the global active day.
	// If not, set the repeater's data to a week's worth of days starting with the given start date.
	$w("#daysToolbar").data = isMobile ? [{ _id: "day", date: activeDay }] : getWeekDays(startDate);
}

//-------------Update Page for Active Day-------------//

// Set the given date to the selected day in the days toolbar and populate
// the services list with the slots available on the selected day.
function setActiveDay(date) {
	// Set the global active day to the given date.
	activeDay = date;
	// Get a date range spanning the given date.
	const dayRange = getDayRange(date);
	// Populate the slots repeater with the slots available for the services in the global services list during the given date range.
	populateServicesSlots(dayRange.startDateTime, dayRange.endDateTime);
	// For each day in the days toolbar:
	$w("#daysToolbar").forEachItem(($item, itemData, index) => {
		// If the site is not being viewed on a mobile device:
		if (!isMobile) {
			// If the newly selected day is the same as the already selected day.
			if (isSameDay(itemData.date, activeDay)) {
				// Disable the day selection button because it is already selected.
				$item("#dayPickerButton").disable();
			}
			// If the newly selected day is not the same as the already selected day.
			else {
				// Enable the day selection button so this day can be selected.
				$item("#dayPickerButton").enable();
			}
		}
	});
}

// Populate the slots repeater with the slots available for the services in the global services list during the given date range.
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("#slotRepeater").data = availableSlots;
	// Hide the slots loader image.
	$w("#slotsLoader").hide();

	// If there is at least one available slot:
	if (availableSlots.length > 0) {
		// Hide the no services message.
		$w("#noServices").hide();
		// Show the slots repeater.
		$w("#slotRepeater").show();
	}
	// If there are no available slots:
	else {
		// Show the no services message.
		$w("#noServices").show();
		// Hide the slots repeater.
		$w("#slotRepeater").hide();
	}
}

//-------------Repeaters Setup-------------//

// Set up each item in the days toolbar repeater as it is loaded.
export function daysToolbar_itemReady($item, itemData, index) {
	// Populate the day field with the item's day of the week (e.g. Tue).
	$item("#day").text = daysOfTheWeek[itemData.date.getDay()];
	// Populate the date field with the item's date (e.g. 18/12).
	$item("#date").text = getMonthDay(itemData.date);

	// For mobile devices, there is no day selection button because only one day is shown at a time.
	// If the site is not being viewed on a mobile device:
	if (!isMobile) {
		// If the current item's day is the same as the already selected day.
		if (isSameDay(itemData.date, activeDay)) {
			// Disable the day selection button because it is already selected.
			$item("#dayPickerButton").disable();
		}
		// If the current item's day is not the same as the already selected day.
		else {
			// Enable the day selection button because it is already selected.
			$item("#dayPickerButton").enable();
		}

		// Set the day selection button to change the selected day and the displayed services when clicked.
		$item("#dayPickerButton").onClick(() => {
			setActiveDay(itemData.date);
		});
	}
}

// Set up each item in the slot repeater as it is loaded.
export function slotRepeater_itemReady($item, itemData, index) {
	// Get the duration of the slot from the item's start and end dates (e.g. 1 hr 30 min).
	const duration = getDuration(itemData.startDateTime, itemData.endDateTime);
	// Get the slot's service name from the global service map using the item's service ID.
	const serviceName = servicesMap[itemData.serviceId].serviceName;
	// Get the slot's staff member name from the global staff map using the item's staff member ID.
	const staffMember = staffMap[itemData.staffMemberId].name;
	// Get the service's form fields from the global services map using the item's service ID.
	const form = servicesMap[itemData.serviceId].form;

	// Populate the item's display fields.
	$item("#time").text = getTimeOfDay(itemData.startDateTime);
	$item("#duration").text = duration;
	$item("#spots").text = itemData.remainingSpots + " spots left";
	$item("#serviceName").text = serviceName;
	$item("#staffMember").text = staffMember;

	// If the slot's start time has already passed:
	if (itemData.startDateTime < Date.now()) {
		// Disable the book button.
		$item("#bookButton").disable();
		// Change the book button's label to say "Passed".
		$item("#bookButton").label = "Passed";
	}
	// If the slot's start time has not passed yet:
	else {
		// If there are no spots remaining in the slot:
		if (itemData.remainingSpots === 0) {
			// Disable the book button. 
			$item("#bookButton").disable();
			// Change the book button's label to say "Full".
			$item("#bookButton").label = "Full";
		}
		// If there are remaining spots in the slot: 
		else {
			// Enable the book button. 
			$item("#bookButton").enable();
			// Change the book button's label to say "Book Now".
			$item("#bookButton").label = "Book Now";
			// Set the book button to open the booking form, passing relevant data to the form, when clicked.
			$item("#bookButton").onClick(event => {
				wixWindow.openLightbox("Booking Form", {
					slot: itemData,
					form: servicesMap[itemData.serviceId].form
				});
			});
		}
	}
}

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

// Get all the staff members from the Staff collection.
async function getAllStaff() {
	const data = await wixData.query("Bookings/Staff").find();
	return data.items;
}

// 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;
}

//-------------Date and Time Helpers-------------//

// Map of the days of the week for display purposes.
const daysOfTheWeek = {
	0: "SUN",
	1: "MON",
	2: "TUE",
	3: "WED",
	4: "THU",
	5: "FRI",
	6: "SAT"
};

// 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;
}

// Gets a date range object where the start is the midnight at the beginning of the given date
// and the end is the midnight at the end of the given date.
function getDayRange(date) {
	// Get the date's starting midnight.
	const startDateTime = getMidnight(date);
	// Get the date's ending midnight.
	const endDateTime = getNextMidnight(date);
	// Return the range.
	return {
		startDateTime,
		endDateTime
	}
}

// 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 midnight that starts the day before the given date.
function getPreviousMidnight(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 midnight that starts the previous day.
	midnight.setHours(-24, 0, 0, 0);
	// Return the new date.
	return midnight;
}

// Get a duration text from a given date range (e.g. 1 hr 30 min).
function getDuration(start, end) {
	// Calculate the duration in milliseconds.
	let diff = Math.abs(start - end);
	// Calculate the number of milliseconds in a minute.
	const minute = 1000 * 60;
	// Calculate the duration in minutes.
	const total_minutes = Math.floor(diff / minute);
	// Calculate how many hours are in the duration.
	const hours = Math.floor(total_minutes / 60);
	// Calculate how many minutes are left over.       
	const minutes = total_minutes % 60;
	// Create the hours text.
	const hoursOutput = hours === 0 ? `` : hours === 1 ? `1 hr` : `${hours} hrs`;
	// Create the minutes text.
	const minutesOutput = minutes === 0 ? `` : `${minutes} min`;
	// Return the hours and minutes texts.
	return `${hoursOutput} ${minutesOutput}`;
}

// Check if two dates are the same day.
function isSameDay(date1, date2) {
	return getMidnight(date1).getTime() === getMidnight(date2).getTime();
}

// 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();
}

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

const hoursInAWeek = 24 * 7;

// Get the date one week from the given date.
function getDateNextWeek(date) {
	let nextWeek = new Date(date);
	nextWeek.setHours(hoursInAWeek);
	return nextWeek;
}

// Get the date one week before the given date.
function getDatePreviousWeek(date) {
	let prevWeek = new Date(date);
	prevWeek.setHours(-hoursInAWeek);
	return prevWeek;
}

 

Thank You

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

// Import session storage to pass information between pages.
import {session} from "wix-storage";

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

$w.onReady(async function () {
	// Get the booked service data from session storage.
	const bookedStart = new Date(session.getItem("bookedStart"));
	const bookedEnd = new Date(session.getItem("bookedEnd"));
	const serviceId = session.getItem("serviceId");
	

	// Clear session storage.
	session.removeItem("bookedStart");
	session.removeItem("bookedEnd");
	session.removeItem("serviceId");
	
	// Populate the page with the booking details.
	$w("#bookedDate").text = getFullDate(bookedStart);
	$w("#bookedTime").text = `${getTimeOfDay(bookedStart)} - ${getTimeOfDay(bookedEnd)}`;
});

//-------------Date and Time Helpers-------------//

// Get the give date formated as Day, Mon dd yyyyy (e.g. Tue, Dec 18 2018).
function getFullDate(date) {
	return date.toLocaleDateString([], { weekday: "long", year: "numeric", month: "long", day: "numeric" });
}

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

 

 

API

Wix Data API

Wix Bookings API

Wix Window API

Wix Storage 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 List) - 윅스 예약시스템 (Wix Bookings)

 

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 리스트 (Service List) - 윅스 예약시스템 (Wix Bookings)

윅스 (Wix) 코딩 강의 중급 (Intermediate) - 서비스 리스트 (Service List) - 윅스 예약시스템 (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)

 

Timetable | Corvid by Wix Examples | Wix.com

In this example, site visitors are presented with a schedule of upcoming classes. They navigate the class schedule by choosing a day and are then presented with all the available classes on that day.

www.wix.com

 

반응형

댓글