# rn-time-slot-scheduler URL: /docs/native/docyrus/time-slot-scheduler Calendly-style booking scheduler — generated slots with capacity, reservations and disabled reasons, a paged week view, a month view with availability dots, and a user / event / timezone summary card. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-time-slot-scheduler ``` **Dependencies:** - [date-fns](https://www.npmjs.com/package/date-fns) ## Usage ```tsx import { TimeSlotScheduler } from '@/components/docyrus-native/time-slot-scheduler'; import type { SlotSelectPayload, TimeSlotReservation } from '@/components/docyrus-native/time-slot-scheduler'; const reservations: TimeSlotReservation[] = [ { id: 'r1', name: 'Ayşe Demir', email: 'ayse@example.com', startTime: '2026-09-24T10:00:00.000Z', endTime: '2026-09-24T10:30:00.000Z' }, ]; const [slot, setSlot] = useState(null); ``` ### Multiple selection (native-only) ```tsx const [slots, setSlots] = useState([]); ``` ## Behavior - **Slot generation** — slots are generated from `startTime` → `endTime` in `slotSize` steps (shared logic with web: `lib/time-slot-utils.ts`). Each slot gets a status: `available`, `partial` (some capacity used), `full`, `unavailable` (inside an `unavailableSlots` range), `past`, or `disabled` (outside `minDate` / `maxDate`), plus a `disabledReason`. - **Columns mode** — the week (Monday start, weekends only when `showSaturday` / `showSunday`) as a horizontally paged day list: 3 day columns per page in portrait, 5 in landscape, or `columnsPerPage`. The header navigates week by week and has a **Today** button. - **Month mode** — the native [rn-mini-calendar](/docs/native/docyrus/mini-calendar) with a dot on every day that still has an available or partial slot, and the picked day's slot list below it. Month navigation is handled by the calendar itself. The list always shows a day (the anchor date until another day is picked), unlike web which shows a "select a day" prompt. - **Selecting** — tap an enabled slot to select it (`onSelect` with an ISO `SlotSelectPayload`). In `selectionMode="multiple"` a tap toggles the slot and `onSelectionChange` receives the full selection. - **Reservations** — with `showReservationDetail`, long-press a slot to open a bottom sheet listing its reservations (web: popover). Tapping a disabled slot opens the same sheet with the disabled reason (web: tooltip). - **Summary card** — `user`, `event` and `timezones` render in a collapsible header card (web: sidebar). The timezone select only reports the value (`onTimezoneChange`); slot times are not converted, same as web. - **Formatting** — slot times use `useDateFormat().formatTime` when a `DateFormatProvider` / `DocyrusTenantProvider` is mounted, otherwise the web `h:mm AM` format. All copy goes through `useUiTranslation()` with the web `ui.timeSlot.*` keys. ## API Reference | Prop | Type | Default | Description | |------|------|---------|-------------| | `startTime` | `string` | `'09:00'` | Start of the bookable day (`HH:mm`). | | `endTime` | `string` | `'17:00'` | End of the bookable day (`HH:mm`). | | `slotSize` | `number` | `30` | Slot length in minutes. | | `slotCapacity` | `number` | `1` | Bookings allowed per slot. When `> 1`, slots show a `count/capacity` indicator. | | `reservations` | `TimeSlotReservation[]` | `[]` | Existing bookings; a reservation counts against every slot it overlaps. | | `unavailableSlots` | `UnavailableRange[]` | `[]` | Blocked ranges per date or recurring weekday. | | `user` | `SchedulerUser` | — | Host shown in the summary card. | | `event` | `SchedulerEvent` | — | Bookable event shown in the summary card. | | `mode` | `'columns' \| 'month'` | — | Controlled view mode. | | `defaultMode` | `'columns' \| 'month'` | `'columns'` | Initial view mode (uncontrolled). | | `onModeChange` | `(mode: TimeSlotSchedulerMode) => void` | — | Fires when the view mode toggle changes. | | `defaultDate` | `Date` | `new Date()` | Initial anchor date. | | `minDate` | `Date` | — | Slots starting before this are `disabled` (`before-min-date`). | | `maxDate` | `Date` | — | Slots starting after this are `disabled` (`after-max-date`). | | `showSaturday` | `boolean` | `false` | Include Saturdays. | | `showSunday` | `boolean` | `false` | Include Sundays. | | `timezone` | `string` | — | Controlled timezone value. | | `defaultTimezone` | `string` | `''` | Initial timezone value (uncontrolled). | | `timezones` | `TimezoneOption[]` | `[]` | Options for the timezone select. The select is hidden when empty. | | `onTimezoneChange` | `(tz: string) => void` | — | Fires when the timezone changes. | | `showReservationDetail` | `boolean` | `false` | Long-press a slot to list its reservations in a bottom sheet. | | `selectedSlot` | `SlotSelectPayload \| null` | — | Controlled single selection. | | `defaultSelectedSlot` | `SlotSelectPayload \| null` | `null` | Initial single selection (uncontrolled). | | `onSelect` | `(payload: SlotSelectPayload) => void` | — | Fires when a slot is selected (in multiple mode: when a slot is toggled on). | | `selectionMode` | `'single' \| 'multiple'` | `'single'` | **Native-only.** `'multiple'` lets the user toggle several slots. | | `selectedSlots` | `SlotSelectPayload[]` | — | **Native-only.** Controlled multiple selection. | | `defaultSelectedSlots` | `SlotSelectPayload[]` | `[]` | **Native-only.** Initial multiple selection (uncontrolled). | | `onSelectionChange` | `(slots: SlotSelectPayload[]) => void` | — | **Native-only.** Fires with the full selection after every toggle. | | `columnsPerPage` | `number` | `3` portrait / `5` landscape | **Native-only.** Day columns visible per page in columns mode. | | `defaultSummaryOpen` | `boolean` | `false` | **Native-only.** Start the user / event summary card expanded. | | `className` | `string` | — | Additional classes for the root container. | ### TimeSlotReservation | Property | Type | Description | |----------|------|-------------| | `id` | `string` | Unique id. | | `name` | `string` | Person who booked. | | `email` | `string` | Optional email. | | `avatarUrl` | `string` | Optional avatar image. | | `startTime` | `string` | ISO date-time. | | `endTime` | `string` | ISO date-time. | ### UnavailableRange | Property | Type | Description | |----------|------|-------------| | `day` | `string` | `yyyy-MM-dd` for one date, or `'0'`–`'6'` (Sunday–Saturday) for a recurring weekday. | | `startTime` | `string` | `HH:mm`. | | `endTime` | `string` | `HH:mm`. | ### SchedulerUser | Property | Type | Description | |----------|------|-------------| | `fullName` | `string` | Host name (initials are used when there is no avatar). | | `email` | `string` | Optional email. | | `avatarUrl` | `string` | Optional avatar image. | ### SchedulerEvent | Property | Type | Description | |----------|------|-------------| | `subject` | `string` | Event title. | | `duration` | `string` | Display duration, e.g. `'30 min'`. | | `location` | `string` | Optional location. | | `description` | `string` | Optional description. | | `icon` | `ReactNode` | Optional icon element. | ### TimezoneOption | Property | Type | Description | |----------|------|-------------| | `value` | `string` | Timezone id, e.g. `'Europe/Istanbul'`. | | `label` | `string` | Display label. | | `offset` | `string` | Display offset, e.g. `'GMT+3'`. | ### SlotSelectPayload | Property | Type | Description | |----------|------|-------------| | `day` | `Date` | Day of the slot. | | `startTime` | `string` | `HH:mm`. | | `endTime` | `string` | `HH:mm`. | | `startISO` | `string` | ISO start. | | `endISO` | `string` | ISO end. | | `capacity` | `number` | Slot capacity. | | `reservationCount` | `number` | Overlapping reservations. | | `remainingCapacity` | `number` | `capacity - reservationCount` (min 0). | | `reservations` | `TimeSlotReservation[]` | Overlapping reservations. | ### TimeSlot / DaySlots `TimeSlot` is the generated slot (`id`, `day`, `startTime`, `endTime`, `startISO`, `endISO`, `status: SlotStatus`, `disabledReason?: DisabledReason`, `capacity`, `reservationCount`, `remainingCapacity`, `reservations`). `DaySlots` groups a day's slots (`date`, `dayLabel`, `dateLabel`, `fullLabel`, `isToday`, `isWeekend`, `slots`, `hasAvailability`). ## Translation keys `ui.timeSlot.previousWeek`, `ui.timeSlot.nextWeek`, `ui.common.today`, `ui.timeSlot.columnsView`, `ui.timeSlot.monthView`, `ui.timeSlot.duration`, `ui.timeSlot.location`, `ui.timeSlot.timezone`, `ui.timeSlot.selectTimezone`, `ui.timeSlot.noSlotsAvailable`, `ui.timeSlot.of`, `ui.timeSlot.booked`, `ui.timeSlot.pastSlot`, `ui.timeSlot.full`, `ui.timeSlot.unavailable`, `ui.timeSlot.beforeMinDate`, `ui.timeSlot.afterMaxDate` — the same keys as the web component. ## Type Exports | Type | Description | |------|-------------| | `TimeSlotSchedulerProps` | Props for `TimeSlotScheduler`. | | `TimeSlotSchedulerMode` | `'columns' \| 'month'`. | | `TimeSlotSelectionMode` | **Native-only.** `'single' \| 'multiple'`. | | `SlotStatus` | `'available' \| 'partial' \| 'full' \| 'unavailable' \| 'past' \| 'disabled'`. | | `DisabledReason` | `'past' \| 'full' \| 'unavailable' \| 'before-min-date' \| 'after-max-date'`. | | `TimeSlot` | A generated slot. | | `DaySlots` | A day with its slots. | | `TimeSlotReservation` | An existing booking. | | `UnavailableRange` | A blocked range. | | `SchedulerUser` | Host for the summary card. | | `SchedulerEvent` | Event for the summary card. | | `TimezoneOption` | Timezone select option. | | `SlotSelectPayload` | Payload passed to `onSelect` / `onSelectionChange`. |