useCalendar
Composable for the whole calendar state: current month, days, time slots of the selected day, navigation and selection.
import { useCalendar } from "@zaptime/core";
const calendar = useCalendar(calendarId?);Init
Initializes the calendar: computes the localized weekday headers, fetches the days of the current month and preselects the first available day. When the current month has no availability it advances to the next month automatically. Requires setConfig and loadDateFnsConfig to have run first; see Getting started.
const { init } = useCalendar();
await init();Get days
Refetches the days of the currently displayed month. Call it after changing the timezone or after a SlotNoLongerAvailableError.
const { getDays } = useCalendar();
await getDays();Day clicked
Selects a day and loads its time slots into state.timeSlots. Clears the previously selected time slot.
const { dayClicked } = useCalendar();
dayClicked(day);Select time slot
Marks a time slot as selected. The selection is shared with useSelectedTimeSlot and used by book, reserve and reschedule.
const { selectTimeSlot } = useCalendar();
selectTimeSlot(timeSlot);Next / previous month
Move the calendar by one month and refetch its days. nextDisabled and prevDisabled are computed from min and max in the config (months backwards and forwards the visitor may navigate).
const { next, prev, nextDisabled, prevDisabled } = useCalendar();Day has time slot
Returns true when the given day has at least one available time slot.
const { dayHasTimeSlot } = useCalendar();
dayHasTimeSlot(day);Is selected / is selected day
const { isSelected, isSelectedDay } = useCalendar();
isSelected(timeSlot); // true when the time slot is the selected one
isSelectedDay(day); // true when the day is the selected oneMonth name and year
Localized month name and the year of the displayed month.
const { monthName, currentYear } = useCalendar();Config
The merged config for this calendar, same as useConfig().config.
State
state is a reactive object (not a ref). Read its properties directly in templates and do not destructure it, otherwise reactivity is lost.
const { state } = useCalendar();
state.date; // Date of the displayed month
state.days; // Day[] for the month grid, including padding days
state.timeSlots; // TimeSlot[] of the selected day
state.selectedDay; // Day | null
state.loading; // true while days are being fetched
state.headers; // string[] localized weekday labels, in startDayOfWeek order
state.monthHasTimeSlots; // false when the whole month is empty
state.initLoaded; // true once init() finishedDay
interface Day {
label: string; // day number as text
date?: Date; // undefined for padding days from the previous month
isPast?: boolean;
isToday?: boolean;
isCurrentMonth?: boolean;
timeSlots?: TimeSlot[]; // undefined when the day has no availability
}Render a day as disabled when !day.date || day.isPast || !dayHasTimeSlot(day).
TimeSlot
interface TimeSlot {
start: string; // ISO 8601
end: string; // ISO 8601
seats: number; // remaining seats (group events)
calendarId: number;
title: string;
readableType: string;
}Format start and end with useDateFormatters; they are UTC strings and the formatter applies the selected timezone.
Empty month
When state.monthHasTimeSlots is false, show the locale.texts.noTimeSlotAvailable text and a button that calls next() labeled with locale.texts.showNextMonth.
