npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue2-booking-calendar

v1.2.0

Published

A customizable booking calendar component for Vue 2 with service, specialist, and customer management

Readme

vue2-booking-calendar

A customizable booking calendar component for Vue 2 with service, specialist, and customer management.

Features

  • Month, week, and day views
  • Booking creation with bidirectional cascading dropdowns (brand ↔ branch ↔ service ↔ specialist ↔ customer)
  • Select any field first — all other dropdowns filter automatically
  • View booking details with full customer info (name, email, phone, address, notes)
  • No-show and cancel booking with confirmation dialogs
  • Specialist availability side panel with booked slot detection
  • New customer inline creation from booking form
  • Per-service duration with auto-computed end times
  • Customizable business hours (standard, 24h, and overnight schedules)
  • Event callbacks with custom function editors and live log
  • Full JSON configuration for dropdown options and sample events
  • Drag and drop events
  • SVG icons throughout
  • Fully customizable via slots

Installation

npm install vue2-booking-calendar

Quick Start

import Vue from 'vue'
import Vuex from 'vuex'
import BookingCalendar, { storeConfig } from 'vue2-booking-calendar'
import 'vue2-booking-calendar/dist/style.css'

Vue.use(Vuex)
Vue.use(BookingCalendar)

const store = new Vuex.Store(storeConfig)

new Vue({
  store,
  template: '<BookingCalendar />'
}).$mount('#app')

Configuration

All configuration is managed through the Vuex store config object. You can override defaults before creating the store:

const store = new Vuex.Store({
  ...storeConfig,
  state() {
    const state = storeConfig.state()
    // Override config
    state.config.businessHoursStart = 9
    state.config.businessHoursEnd = 17
    state.config.timeFormat = '24h'
    state.config.showLogo = false
    return state
  }
})

Config Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | slotDuration | number | 60 | Time slot duration in minutes (15, 30, 60) | | businessHoursStart | number | 8 | Business hours start (0-23) | | businessHoursEnd | number | 18 | Business hours end (0-23) | | is24HourOperation | boolean | false | Enable 24-hour operation (disables business hours filtering) | | timeFormat | string | '12h' | Time display format ('12h' or '24h') | | firstDayOfWeek | number | 0 | First day of week (0 = Sunday, 1 = Monday) | | showWeekends | boolean | true | Show weekend columns | | maxVisibleEvents | number | 3 | Max events visible per day in month view | | defaultEventDuration | number | 60 | Fallback duration when service has no duration | | sidebarPosition | string | 'left' | Mini calendar sidebar position ('left', 'right', 'none') | | showHeader | boolean | true | Show calendar navigation header | | showLogo | boolean | true | Show the logo header bar | | showCustomizationPanel | boolean | true | Show the customization settings panel | | showCurrentTime | boolean | true | Show current time indicator line | | highlightToday | boolean | true | Highlight today's column | | eventBorderRadius | string | 'rounded' | Event card style ('rounded' or 'square') | | dayStartHour | number | 0 | Hour to start the day view from |

Booking Field Visibility

Control which fields appear in the booking form and view modal:

bookingFields: {
  brand: true,       // Show in create/edit form
  branch: true,
  service: true,
  date: true,
  time: true,
  specialist: true,
  customer: true,
  color: true
}

viewFields: {
  brand: true,       // Show in view booking modal
  branch: true,
  service: true,
  date: true,
  time: true,
  specialist: true,
  customer: true
}

Business Hours

Standard schedule (e.g. 8 AM – 6 PM):

businessHoursStart: 8,
businessHoursEnd: 18,
is24HourOperation: false

Overnight schedule (e.g. 8 PM – 5 AM):

businessHoursStart: 20,
businessHoursEnd: 5,
is24HourOperation: false

24-hour operation:

is24HourOperation: true

Dropdown Data Formats

Brand

{ "uuid": "b1a2c3d4-...", "name": "RUSH Salon" }

Branch

{
  "uuid": "br1-0001-...",
  "brand_uuid": "b1a2c3d4-...",
  "name": "Downtown"
}

Service

{
  "uuid": "sv-0001",
  "name": "Haircut",
  "duration": 60,
  "brands": ["b1a2c3d4-..."],
  "branches": ["br1-0001-...", "br1-0002-..."],
  "specialists": ["sp-0001", "sp-0002"]
}
  • duration — service duration in minutes, used to auto-compute booking end time
  • brands — list of brand UUIDs that offer this service
  • branches — list of branch UUIDs where this service is available
  • specialists — list of specialist UUIDs who can perform this service

Specialist

{
  "uuid": "sp-0001",
  "name": "Maria Santos",
  "services": ["sv-0001", "sv-0002"],
  "brands": ["b1a2c3d4-..."],
  "branch_uuid": "br1-0001-...",
  "availability": {
    "monday": ["09:00", "09:30", "10:00", "10:30", "11:00"],
    "tuesday": ["09:00", "09:30", "10:00"],
    "wednesday": [],
    "thursday": ["14:00", "14:30", "15:00"],
    "friday": ["09:00", "09:30", "10:00", "10:30"],
    "saturday": [],
    "sunday": []
  }
}
  • branch_uuid — single branch the specialist is assigned to
  • availability — time slots per day of week (used by the availability side panel)
  • When a specialist + date are selected, the availability panel shows available/booked slots

Customer

{
  "uuid": "cu-0001",
  "name": "John Doe",
  "email": "[email protected]",
  "phone": "+1 (555) 100-2001",
  "gender": "Male",
  "address": "123 Main St, New York, NY 10001",
  "notes": "Prefers short fade on sides"
}

All customer details are displayed in the view booking modal. New customers can be created inline from the booking form.

Time Slots

["09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "12:00", ...]

Time slots outside business hours are automatically disabled in the booking form.

Event Data Format

{
  "id": "s1",
  "title": "Haircut",
  "brand": "b1a2c3d4-...",
  "branch": "br1-0001-...",
  "service": "sv-0001",
  "specialist": "sp-0001",
  "customer": "cu-0001",
  "start": "2025-01-10T09:00:00.000Z",
  "end": "2025-01-10T10:00:00.000Z",
  "color": "#FF6B00"
}

Callbacks

All callbacks can be toggled on/off and have customizable function bodies:

| Callback | Fires When | Payload | |----------|-----------|---------| | onEventCreate | New booking saved | { id, title, start, end } | | onEventUpdate | Booking edited | { id, title, start, end } | | onEventDelete | Booking deleted | { id } | | onEventClick | Booking clicked/viewed | { id, title } | | onDateChange | Calendar navigated | { date, direction } | | onViewChange | View switched | { view } | | onSlotClick | Empty slot clicked | { date, hour } | | onEventDrop | Event drag & dropped | { id, from, to } | | onSpecialistScheduleCheck | Availability panel loads | { specialist_uuid, specialist_name, date, day, available_slots, booked_slots, total_available, total_booked } |

Custom Callback Functions

Each callback has an editable function body that receives a payload argument:

callbackFns: {
  onEventCreate: 'console.log("Event created:", payload)',
  onSpecialistScheduleCheck: `
    // Fetch real availability from API
    fetch('/api/availability?specialist=' + payload.specialist_uuid + '&date=' + payload.date)
      .then(r => r.json())
      .then(data => console.log(data))
  `
}

Callback Examples

onEventCreate — Send new booking to API

callbackFns: {
  onEventCreate: `
    fetch('/api/bookings', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })
    .then(r => r.json())
    .then(data => console.log('Booking saved:', data.id))
    .catch(err => console.error('Failed to save:', err))
  `
}

onEventUpdate — Sync changes to backend

callbackFns: {
  onEventUpdate: `
    fetch('/api/bookings/' + payload.id, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })
    .then(() => console.log('Booking updated:', payload.id))
  `
}

onEventDelete — Delete from backend with confirmation log

callbackFns: {
  onEventDelete: `
    fetch('/api/bookings/' + payload.id, { method: 'DELETE' })
      .then(() => console.log('Booking deleted:', payload.id))
  `
}

onEventClick — Track booking views in analytics

callbackFns: {
  onEventClick: `
    if (window.gtag) {
      gtag('event', 'view_booking', {
        booking_id: payload.id,
        booking_title: payload.title
      })
    }
    console.log('Viewed booking:', payload.title)
  `
}

onDateChange — Load events for the new date range

callbackFns: {
  onDateChange: `
    console.log('Calendar navigated:', payload.direction, 'to', payload.date)
    // Fetch events for the new visible range
    // fetch('/api/bookings?date=' + payload.date)
    //   .then(r => r.json())
    //   .then(events => store.commit('SET_EVENTS', events))
  `
}

onViewChange — Persist user's preferred view

callbackFns: {
  onViewChange: `
    localStorage.setItem('calendarView', payload.view)
    console.log('View changed to:', payload.view)
  `
}

onSlotClick — Pre-fill booking from clicked slot

callbackFns: {
  onSlotClick: `
    console.log('Slot clicked:', payload.date, 'at', payload.hour + ':00')
  `
}

onEventDrop — Update booking after drag & drop

callbackFns: {
  onEventDrop: `
    fetch('/api/bookings/' + payload.id + '/reschedule', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ from: payload.from, to: payload.to })
    })
    .then(() => console.log('Booking rescheduled:', payload.id))
  `
}

onSpecialistScheduleCheck — Fetch real-time availability from API

callbackFns: {
  onSpecialistScheduleCheck: `
    console.log('Checking schedule for', payload.specialist_name, 'on', payload.date)
    console.log('Day:', payload.day)
    console.log('Available slots:', payload.total_available)
    console.log('Booked slots:', payload.total_booked)
    console.log('Available times:', payload.available_slots.join(', '))
    console.log('Booked times:', payload.booked_slots.join(', '))

    // Example: Fetch real availability from your API
    // fetch('/api/specialists/' + payload.specialist_uuid + '/availability?date=' + payload.date)
    //   .then(r => r.json())
    //   .then(data => {
    //     // Update specialist availability dynamically
    //     console.log('Real availability:', data)
    //   })
  `
}

Disabling Specific Callbacks

Toggle individual callbacks on/off:

// Via config
callbacks: {
  onEventCreate: true,     // enabled
  onEventUpdate: true,     // enabled
  onEventDelete: false,    // disabled
  onEventClick: false,     // disabled
  onDateChange: true,      // enabled
  onViewChange: false,     // disabled
  onSlotClick: false,      // disabled
  onEventDrop: true,       // enabled
  onSpecialistScheduleCheck: true  // enabled
}

// Or at runtime
store.commit('SET_CONFIG', { key: 'callbacks.onEventDelete', value: false })
store.commit('SET_CONFIG', { key: 'callbacks.onEventDrop', value: true })

Updating Callback Functions at Runtime

// Update a callback function body
store.commit('SET_CONFIG', {
  key: 'callbackFns.onEventCreate',
  value: 'fetch("/api/bookings", { method: "POST", body: JSON.stringify(payload) })'
})

// Reset to default
store.commit('SET_CONFIG', {
  key: 'callbackFns.onEventCreate',
  value: 'console.log("Event created:", payload)'
})

Vuex Store API

Mutations

| Mutation | Payload | Description | |----------|---------|-------------| | SET_DATE | Date | Set current calendar date | | SET_VIEW | string | Set view ('month', 'week', 'day') | | SET_EVENTS | array | Replace all events | | ADD_EVENT | object | Add a single event | | UPDATE_EVENT | object | Update event by id | | DELETE_EVENT | string | Delete event by id | | SET_CONFIG | { key, value } | Update config (supports dot notation: 'bookingFields.brand') | | SHOW_EVENT_MODAL | boolean | Show/hide create/edit modal | | SHOW_VIEW_MODAL | boolean | Show/hide view modal |

Actions

| Action | Payload | Description | |--------|---------|-------------| | next | — | Navigate to next period | | prev | — | Navigate to previous period | | today | — | Navigate to today | | changeView | string | Switch view with callback | | addEvent | object | Add event with callback | | updateEvent | object | Update event with callback | | deleteEvent | string | Delete event with callback | | openCreateModal | slot? | Open create booking modal | | openEditModal | event | Open edit booking modal | | openViewModal | event | Open view booking modal | | moveEvent | { id, newDate, newHour } | Move event (drag & drop) | | clearAllEvents | — | Remove all events | | resetEvents | — | Reset to sample data |

Programmatic Config Updates

Update any config at runtime:

// Simple value
store.commit('SET_CONFIG', { key: 'timeFormat', value: '24h' })

// Nested value
store.commit('SET_CONFIG', { key: 'bookingFields.color', value: false })

// Replace dropdown options
store.commit('SET_CONFIG', {
  key: 'dropdownOptions.brand',
  value: [
    { uuid: 'b1', name: 'My Brand' },
    { uuid: 'b2', name: 'Other Brand' }
  ]
})

// Replace all events
store.commit('SET_EVENTS', myEventsArray)

License

MIT