> Portal Navigation: > > - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version. > - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages). > - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`). > - Top-level index of all portals: https://dev.wix.com/docs/llms.txt > - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt ## Resource: Tutorial | Create a Staff Vacation Management Interface ## Article: Tutorial | Create a Staff Vacation Management Interface ## Article Link: https://dev.wix.com/docs/develop-websites-sdk/get-started/tutorials/bookings/tutorial-create-a-staff-vacation-management-interface.md ## Article Content: # Tutorial | Create a Staff Vacation Management Interface Using the [Bookings APIs](https://dev.wix.com/docs/api-reference/business-solutions/bookings/services/introduction.md) and [Calendar APIs](https://dev.wix.com/docs/api-reference/business-management/calendar/introduction.md), you can create a backend interface where [staff members](https://support.wix.com/en/article/about-staff-members-in-wix-bookings) can block their vacation time. This tutorial shows you how to build a [dashboard page](https://dev.wix.com/docs/develop-websites-sdk/code-your-site/build-a-custom-dashboard/about-dashboard-pages.md) where [site collaborators](https://support.wix.com/en/article/inviting-people-to-contribute-to-your-site) select a staff member, choose vacation dates, and block that time in the [Bookings calendar](https://support.wix.com/en/article/wix-bookings-about-the-wix-booking-calendar). During those periods, the staff member is unavailable for bookings. ## How staff members, resources, and schedules interact To schedule staff vacations, you need to understand how Wix Bookings manages staff members, resources, and calendars. Wix Bookings automatically creates and manages an associated [resource](https://dev.wix.com/docs/api-reference/business-solutions/bookings/resources/resources-v2/introduction.md) for each staff member. Each resource has an associated [schedule](https://dev.wix.com/docs/api-reference/business-management/calendar/schedules-v3/introduction.md), which Wix Bookings uses to manage that resource's availability. The entries on the schedule are [events](https://dev.wix.com/docs/api-reference/business-management/calendar/events-v3/introduction.md), during which the resource can't be booked. Therefore, to schedule a staff member's vacation time, you need the full resource object associated with that staff member, which contains the ID of the events schedule associated with that resource. To [create the vacation event](https://dev.wix.com/docs/api-reference/business-management/calendar/events-v3/create-event.md), you must specify that schedule ID. Learn more about [scheduling and availability in Wix Bookings](https://dev.wix.com/docs/api-reference/business-solutions/bookings/introduction.md#scheduling-and-availability) and how [Wix Bookings uses the Calendar APIs](https://dev.wix.com/docs/api-reference/business-management/calendar/wix-bookings-integration.md). ## What you'll build By the end of this tutorial, you'll have a [dashboard page](https://dev.wix.com/docs/develop-websites-sdk/code-your-site/build-a-custom-dashboard/about-dashboard-pages.md) that: - Displays a dropdown list of all staff members. - Lets site collaborators choose vacation start and end dates. - Creates blocked time events on the staff member's calendar. - Automatically prevents bookings during blocked vacation periods. > The code in this article was written using the following module versions: > > - @wix/bookings (v1.0.1167) > - @wix/web-methods (v1.0.0) > - @wix/calendar (v1.0.185) > - @wix/essentials (v1.0.0) > > Learn how to install npm packages [in the editor](https://dev.wix.com/docs/develop-websites/articles/coding-with-velo/packages/work-with-npm-packages-in-the-editor.md) or [using the CLI](https://dev.wix.com/docs/develop-websites/articles/coding-with-velo/packages/work-with-npm-packages-with-the-wix-cli.md). Use the following steps to build the functionality: 1. [Create backend methods for staff availability management.](#step-1--create-backend-methods-for-staff-availability-management) 2. [Create the frontend interface.](#step-2--create-the-frontend-interface) ## Before you begin It's important to note the following points before starting to code: - The Wix user must install the [Wix Bookings](https://www.wix.com/app-market/web-solution/bookings) app on their site. - The user must [add at least one staff member](https://support.wix.com/en/article/wix-bookings-adding-staff-members) in their Wix Bookings settings. ## Step 1 | Create backend methods for staff availability management Create backend methods to query staff members and create vacation events on their schedules: 1. In your site's [backend folder](https://dev.wix.com/docs/develop-websites-sdk/code-your-site/build-a-custom-backend/about-the-site-backend.md), create a new file called `staff-management.web.js`. 2. Add the following import statements: ```javascript import { Permissions, webMethod } from "@wix/web-methods"; import { staffMembers } from "@wix/bookings"; ``` 3. Create a [web method](https://dev.wix.com/docs/sdk/core-modules/web-methods/introduction.md) to query all staff members. Specify `RESOURCE_DETAILS` in the optional `fields` array to retrieve the full resource object. It contains the schedule ID needed to create vacation events: ```javascript export const queryStaff = webMethod(Permissions.SiteMember, async () => { try { const { items } = await staffMembers .queryStaffMembers({ options: { fields: ["RESOURCE_DETAILS"] } }); return items; } catch (error) { console.error("Failed to query staff members:", error); throw error; } }); ``` 4. Create a second backend file called `event-management.web.js` to manage vacation events. 5. Add the following import statements to this file: ```javascript import { Permissions, webMethod } from "@wix/web-methods"; import { events } from "@wix/calendar"; import { auth } from "@wix/essentials"; ``` 6. Create a web method to set up a staff member's vacation. This method receives the staff member details and date range, constructs an event object, and creates a blocked calendar event: ```javascript export const createVacationEvent = webMethod( Permissions.SiteMember, async (member, startDate, endDate) => { // Use the schedule ID from the staff member's associated resource to create the vacation event const vacationEvent = { scheduleId: member.resource.eventsSchedule._id, title: `${member.name} is on holiday!`, start: { localDate: `${startDate}T00:00:00`, }, end: { localDate: `${endDate}T23:59:59`, }, resource: [member.resource], }; try { const elevatedCreateEvent = auth.elevate(events.createEvent); const createdEvent = await elevatedCreateEvent(vacationEvent); return createdEvent; } catch (error) { console.error( `Failed to create vacation event for ${member.name}:`, error ); throw new Error(`Failed to create vacation: ${error.message}`); } } ); ``` These backend methods allow site members to query staff and create vacation events on their schedules. ## Step 2 | Create the frontend interface This step creates a dashboard page interface that allows site collaborators to select a staff member, choose vacation dates, and create blocked time events. To build the frontend interface: 1. [Add a dashboard page](https://dev.wix.com/docs/develop-websites-sdk/code-your-site/build-a-custom-dashboard/add-a-dashboard-page.md) to your site. 2. Add the following elements to the dashboard page: - A dropdown element with ID **staffDropdown** for selecting staff members. - A date picker with ID **datePickerStart** for selecting the vacation start date. - A date picker with ID **datePickerEnd** for selecting the vacation end date. - A button with ID **setupButton** to trigger the vacation setup. - A text element with ID **statusText** to display status messages. Your dashboard page should look like this: ![Staff members dashboard page](https://wixmp-833713b177cebf373f611808.wixmp.com/images/defe7cdf4b85a969da1ad6b20c8fee1f.png) 3. In your dashboard page's code editor, add the following code to import the backend methods and initialize a variable to store the queried staff members: ```javascript import { queryStaff } from "backend/staff-management.web.js"; import { createVacationEvent } from "backend/event-management.web.js"; let staffMembers; ``` 4. Add methods to format dates and set up the details of the vacation event: ```javascript // Helper method to format dates into YYYY-MM-DD format required by the Wix Calendar API function formatDate(dateObj) { const date = String(dateObj.getDate()).padStart(2, "0"); const month = String(dateObj.getMonth() + 1).padStart(2, "0"); const year = dateObj.getFullYear(); return `${year}-${month}-${date}`; } async function setUpVacation(startDateObj, endDateObj) { try { await $w("#setupButton").disable(); const selectedIndex = $w("#staffDropdown").selectedIndex; const staffName = $w("#staffDropdown").options[selectedIndex].label; $w("#statusText").text = `Setting up vacation for ${staffName}...`; // Find the selected staff member const selectedMemberId = $w("#staffDropdown").options[selectedIndex].value; const selectedMember = staffMembers.find( (member) => member._id === selectedMemberId ); // Format the selected dates const startDate = formatDate(startDateObj); const endDate = formatDate(endDateObj); // Create vacation event await createVacationEvent(selectedMember, startDate, endDate); $w("#statusText").text = `${staffName} has scheduled their vacation.`; await $w("#setupButton").enable(); } catch (error) { console.error("Failed to setup vacation: ", error); $w("#statusText").text = "Failed to schedule vacation."; await $w("#setupButton").enable(); } } ``` 5. Add a method to query staff members and populate the dropdown menu: ```javascript async function populateStaffDropdown() { try { staffMembers = await queryStaff(); const staffOptions = staffMembers.map((member) => ({ label: member.name, value: member._id, })); $w("#staffDropdown").options = staffOptions; $w("#staffDropdown").selectedIndex = 0; $w("#statusText").text = "Select vacation dates and click Set Up Vacation"; await $w("#setupButton").enable(); } catch (error) { console.error("Failed to load staff members: ", error); $w("#statusText").text = "Failed to load staff members"; } } ``` 6. Set up the dashboard page interface: ```javascript async function setUpPage() { let startDate; let endDate; // Set up date pickers $w("#datePickerStart").dateFormat = "YYYY/MM/DD"; $w("#datePickerStart").value = new Date(); $w("#datePickerEnd").dateFormat = "YYYY/MM/DD"; $w("#datePickerEnd").value = new Date(); // Register event handlers $w("#datePickerStart").onChange(async (event) => { await $w("#setupButton").enable(); startDate = event.target.value; }); $w("#datePickerEnd").onChange(async (event) => { await $w("#setupButton").enable(); endDate = event.target.value; }); // Set up the setup button $w("#setupButton").onClick(() => { setUpVacation(startDate, endDate); }); $w("#staffDropdown").onChange(async () => { await $w("#setupButton").enable(); }); // Disable setup button until dropdown is populated await $w("#setupButton").disable(); // Populate the dropdown menu with staff members populateStaffDropdown(); } ``` 7. In the page's [`onReady()`](https://dev.wix.com/docs/velo/velo-only-apis/$w/on-ready.md) method, set up the dashboard page: ```js $w.onReady(function () { setUpPage(); }); ``` When a site collaborator chooses vacation dates and clicks the setup button, the code creates a blocked event in the Bookings Calendar. ![Blocked Vacation Time on Bookings Calendar](https://wixmp-833713b177cebf373f611808.wixmp.com/images/36ad82b0449d7d628aa9bd76164188f4.png) ## Complete code Here is the complete tutorial code: ### Backend code Here are the complete backend files: #### staff-management.web.js ```javascript import { Permissions, webMethod } from "@wix/web-methods"; import { staffMembers } from "@wix/bookings"; export const queryStaff = webMethod(Permissions.SiteMember, async () => { try { const { items } = await staffMembers .queryStaffMembers({ options: { fields: ["RESOURCE_DETAILS"] } }); if (!items || items.length === 0) { throw new Error("No staff members found"); } return items; } catch (error) { console.error("Failed to query staff members:", error); throw error; } }); ``` #### event-management.web.js ```javascript import { Permissions, webMethod } from "@wix/web-methods"; import { events } from "@wix/calendar"; import { auth } from "@wix/essentials"; export const createVacationEvent = webMethod( Permissions.SiteMember, async (member, startDate, endDate) => { const vacationEvent = { scheduleId: member.resource.eventsSchedule._id, title: `${member.name} is on holiday!`, start: { localDate: `${startDate}T00:00:00`, }, end: { localDate: `${endDate}T23:59:59`, }, resource: [member.resource], }; try { const elevatedCreateEvent = auth.elevate(events.createEvent); const createdEvent = await elevatedCreateEvent(vacationEvent); return createdEvent; } catch (error) { console.error(`Failed to create vacation event:`, error); throw new Error(`Failed to create vacation: ${error.message}`); } } ); ``` ### Dashboard page code Here's the complete dashboard page code: ```javascript import { queryStaff } from "backend/staff-management.web.js"; import { createVacationEvent } from "backend/event-management.web.js"; let staffMembers; // Helper method to format dates into YYYY-MM-DD format required by the Wix Calendar API function formatDate(dateObj) { const date = String(dateObj.getDate()).padStart(2, "0"); const month = String(dateObj.getMonth() + 1).padStart(2, "0"); const year = dateObj.getFullYear(); return `${year}-${month}-${date}`; } async function setUpVacation(startDateObj, endDateObj) { try { await $w("#setupButton").disable(); const selectedIndex = $w("#staffDropdown").selectedIndex; const staffName = $w("#staffDropdown").options[selectedIndex].label; $w("#statusText").text = `Setting up vacation for ${staffName}...`; // Find the selected staff member const selectedMemberId = $w("#staffDropdown").options[selectedIndex].value; const selectedMember = staffMembers.find( (member) => member._id === selectedMemberId ); // Format the selected dates const startDate = formatDate(startDateObj); const endDate = formatDate(endDateObj); // Create vacation event await createVacationEvent(selectedMember, startDate, endDate); $w("#statusText").text = `${staffName} has scheduled their vacation.`; await $w("#setupButton").enable(); } catch (error) { console.error("Failed to setup vacation: ", error); $w("#statusText").text = "Failed to schedule vacation."; await $w("#setupButton").enable(); } } async function populateStaffDropdown() { try { staffMembers = await queryStaff(); const staffOptions = staffMembers.map((member) => ({ label: member.name, value: member._id, })); $w("#staffDropdown").options = staffOptions; $w("#staffDropdown").selectedIndex = 0; $w("#statusText").text = "Select vacation dates and click Set Up Vacation"; await $w("#setupButton").enable(); } catch (error) { console.error("Failed to load staff members: ", error); $w("#statusText").text = "Failed to load staff members."; } } async function setUpPage() { let startDate; let endDate; $w("#datePickerStart").dateFormat = "YYYY/MM/DD"; $w("#datePickerStart").value = new Date(); $w("#datePickerEnd").dateFormat = "YYYY/MM/DD"; $w("#datePickerEnd").value = new Date(); $w("#datePickerStart").onChange(async (event) => { await $w("#setupButton").enable(); startDate = event.target.value; }); $w("#datePickerEnd").onChange(async (event) => { await $w("#setupButton").enable(); endDate = event.target.value; }); $w("#setupButton").onClick(() => { setUpVacation(startDate, endDate); }); $w("#staffDropdown").onChange(async () => { await $w("#setupButton").enable(); }); await $w("#setupButton").disable(); populateStaffDropdown(); } $w.onReady(function () { setUpPage(); }); ``` ## See also - [About in Wix Bookings APIs](https://dev.wix.com/docs/api-reference/business-solutions/bookings/introduction.md) - [Bookings: Staff Members API](https://dev.wix.com/docs/api-reference/business-solutions/bookings/staff-members/staff-members/introduction.md) - [Bookings: Resources API](https://dev.wix.com/docs/api-reference/business-solutions/bookings/resources/resources-v2/introduction.md) - [Calendar Events API](https://dev.wix.com/docs/api-reference/business-management/calendar/events-v3/introduction.md) - [About Dashboard Pages](https://dev.wix.com/docs/develop-websites-sdk/code-your-site/build-a-custom-dashboard/about-dashboard-pages.md) - [Tutorial: Block Off Time in the Bookings Calendar](https://dev.wix.com/docs/develop-websites-sdk/get-started/tutorials/bookings/tutorial-block-off-time-in-the-bookings-calendar.md)