# Appointment book

A React block (a whole screen) in [Beamline](https://beamline.io/)'s [Clinic](https://beamline.io/components/apps/clinic) app. Live demo: https://beamline.io/components/appointment-book

The desk's day with the appointment editor beside it. The appointment being edited is a block on the day like any other, drawn in the accent while it is a draft: drag it or pull its end on the day, or set its date, start and length in the editor, and both follow. It carries its client or clients, the practitioner it belongs to apart from assisting staff, the service (recent ones first) and where it happens (rooms, or video when the service allows). If it lands on a person (as owner or assistant) or a room another appointment holds, both blocks take the warning role and the editor names that appointment and the time, with a free room and the next free start one tap away; Save waits until the clash is resolved. After a save succeeds, telling the client is offered as its own choice (Send email or Not now), and a refused save or email says why and keeps everything. At rest the side says who is in now (until when), who is up next today, and each practitioner's day from here (how many more, free now or from when), with their pictures.

## Use it for

- A practice's, studio's or salon's front desk booking and moving appointments on the day: who, whose, what, where and when, with rooms and staff that can't be double-booked.
- Any day-view booking where a move must show, where it lands, which person or room is already taken.

## Not for

- A client booking for themselves ([client-booking](https://beamline.io/components/client-booking)).
- A team's whole calendar app with calendars, navigation and time off ([team-calendar](https://beamline.io/components/team-calendar)).
- Setting up services and hours ([booking-setup](https://beamline.io/components/booking-setup)).

## Anatomy

- day: the practice's day (day, week or month), every appointment as a block with its clients, service, time, rooms or Video, and whose it is; quiet by default, the draft in the accent, what it collides with in the warning role; the now line; drag a block or pull its end, or drag across free time (or click it) to book
- at rest, the editor's room: how to open or book one, New appointment (at the next quarter hour), and Up next today: the day's remaining appointments from now (time, clients, service, room or Video, whose), each opening its appointment
- editor beside the day (a sheet from the bottom on a narrow screen): the client or clients (or New appointment) as its title and Close; Date, Starts and Length with Ends and the length in words (the day's block is the twin); Client or Clients; Service, recent ones first; Practitioner (whose it is) apart from Assisting (busy too, not theirs); Where: In a room with its rooms, or Video when the service allows (else said)
- clash: each collision named with the person or room, the other appointment's clients and service, and the time they share; the ways out once each: Use <a free room> for a room that clashes, and Move to <the next free start>, or Nothing free later today
- save bar: Unsaved changes, Not booked yet, Resolve the clash to save, or the refusal's reason; Discard and Save (Book for a new one), Save waiting for a clash and a client
- after a save: Saved. Let <clients> know? with what the email says (the new time, or confirming it), Send email and Not now; Sending, told, or the refusal's reason with Try again

## States

- nothing open (how to open or book one, New appointment, Up next today; Nothing more today when the day is done)
- an appointment open (the draft in the accent on the day; Close while unchanged)
- unsaved changes (named in the save bar; another appointment can't be opened until saved or discarded)
- new appointment (from free time, its drawn length or its service's; Not booked yet; Book waits for a client)
- room clash (both or all blocks in the warning role, each collision named; Use <room> when one is free)
- person clash (the owner or an assistant with another appointment, named)
- next free start offered, or nothing free later today
- video not offered for the service (said; the choice disabled)
- saving, save refused (the reason, the draft kept), saved
- email offered after a save (new: confirming; moved: the new time), sending, sent, refused (the reason, Try again), declined (Not now)
- narrow room: the editor as a sheet over the day

## Keyboard

- the day is the shared event calendar's: Tab to a block, Enter opens it, Space grabs it and the arrows move it (Shift for its length), Escape puts it back
- the editor's fields in order; Start is hour and minute segments, Length a number field (arrows by 5, Page by 15)
- the ways out (Use <room>, Move to <time>) and Save, Discard, Send email, Not now are buttons in the tab order

## Motion

A block dragged or resized follows the hand on the shared event calendar; the clash, the save bar and the email choice open and close by their height and take their gap with them, so what is under them glides; Close fades. Colour changes on the blocks are the calendar's own. Nothing runs at rest; reduced motion places at once.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `practitioners` (required) | `BookPractitioner[]` | — |  |
| `rooms` (required) | `BookRoom[]` | — |  |
| `clients` (required) | `BookClient[]` | — |  |
| `services` (required) | `BookService[]` | — |  |
| `recentServiceIds` | `string[]` | — | Services booked lately, most recent first: offered first in the editor. |
| `appointments` | `Appointment[]` | — | The practice's appointments. |
| `defaultAppointments` | `Appointment[]` | — |  |
| `onAppointmentsChange` | `((appointments: Appointment[]) => void)` | — | The whole list after a save succeeds. |
| `onSave` | `((appointment: Appointment, previous: Appointment \| null) => void \| Promise<unknown>)` | — | Saves one appointment (`previous` null: a new one). Return a promise to show progress; reject with the reason to keep the draft and say why. |
| `onNotify` | `((appointment: Appointment, isNew: boolean) => Promise<unknown>)` | — | Tells the client(s) about a saved appointment, offered after the save as its own choice; reject with the reason. Without it, nothing is offered. |
| `defaultDate` | `Date` | — | The day shown at first. Default: today. |
| `now` | `Date` | — | The present (the now line, Today). Default: the clock. |
| `defaultOpen` | `string` | — | The appointment open at first. |
| `dayEndsAt` | `number` | — | Where the day closes: no free start is offered after it. Default 20 (8 pm). |
| `timeFormat` | `"12h" \| "24h"` | — | How times of day are written in the editor. Default "24h". |
| `className` | `string` | — | Classes on the documented visual root; no override by default. |
| `style` | `CSSProperties` | — | Inline styles on the documented visual root; no overrides by default. |
| `ref` | `Ref<HTMLDivElement>` | — | Receives the documented native target or imperative handle; omitted by default. |
| `locale` | `string` | — | Locale for the day's dates and its hour axis ("en-GB" writes 14:00). Default: the runtime's. |

## Built from

- [event-calendar](https://beamline.io/components/event-calendar)
- [date-picker](https://beamline.io/components/date-picker)
- [time-picker](https://beamline.io/components/time-picker)
- [number-field](https://beamline.io/components/number-field)
- [multi-select](https://beamline.io/components/multi-select)
- select
- [segmented-control](https://beamline.io/components/segmented-control)
- sheet
- alert
- button

## Dependencies

`lucide-react`

## Import

```tsx
import { AppointmentBook } from "@beamline/appointment-book";
```

## Get it

Appointment book is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in Clinic

- [Book an appointment](https://beamline.io/components/client-booking): A client books an appointment on the practice's own site: a service (length and price beside it), who gives it or anyone free, and where; a day with…
- [Services and hours](https://beamline.io/components/booking-setup): A practice's services and the hours its practitioners can be booked, one relation seen from both ends. A service reads as values and changes on demand…
- [Patient overview](https://beamline.io/components/patient-overview): One patient's record on a page. A search finds patients by name, chart number or birth date (recent patients when empty; same names told apart by birth…
- [Patient chart](https://beamline.io/components/patient-chart): A clinic's chart for one client and their animals. The client's header (phone, email, contact preferences, the balance with what it means and as of when…
- [Health questionnaire](https://beamline.io/components/health-questionnaire): A patient's medical history as a versioned questionnaire. Every question takes Yes, No or I don't know, and one not answered says so, never read as No; a…
- [Case workspace](https://beamline.io/components/case-workspace): A patient's clinical cases and how cases work at the practice. A case shows its status, type, teeth, staff, location and start; its checklist counts…
- [Care plan](https://beamline.io/components/care-plan): A client's care plan composed beside what the client will see of it. Every field says who sees it (the care team only, or the client too) and the…
- [Treatment plan](https://beamline.io/components/treatment-plan): A patient's treatment plan in named phases. Each procedure shows its tooth, status and fee beside the patient's and the insurer's estimate (not known…
- [Plan templates](https://beamline.io/components/plan-templates): Reusable treatment-plan templates. A template reads as words at rest and changes on demand: its name edits in place; the status its procedures start as…
- [Plan acceptance](https://beamline.io/components/plan-acceptance): A treatment plan presented for acceptance, from both sides. The practice chooses the agreement (the account's default or this location's own) and how…
- [Plan follow-up](https://beamline.io/components/plan-follow-up): The practice's follow-up lists, for the person who turns accepted treatment into booked chairs. Treatment plans lead with what's at stake: the value…
- [Session notes and tasks](https://beamline.io/components/session-notes): A session's note beside its follow-up tasks, each task tied to the exact words it came from: choose a task and its words light in the note or the…
- [Note templates](https://beamline.io/components/note-templates): A practitioner's note templates in one library with three ways in. My templates lists their own by kind, favourites first, each with when it was last…
- [Probing chart](https://beamline.io/components/probing-chart): A periodontal probing chart. Six sites per tooth (three buccal, three lingual) across both arches as you face the patient, each depth in its cell and…
- [Procedure picker](https://beamline.io/components/procedure-picker): Procedures, conditions and bundles put on a patient's teeth from the chair. The mode (existing, planned, completed) is chosen before adding and each…
- [Results notebook](https://beamline.io/components/results-notebook): A notebook entry's structured results. The entry's text above a bounded results table with typed columns: a sample link, numbers in their unit with their…
- [Insurance claims](https://beamline.io/components/claims-queue): Insurance claims as a queue: every claim at first, in the order a person works them (rejected by the clearinghouse, denied by the payer, partly paid, not…
- [Account ledger](https://beamline.io/components/account-ledger): A patient's account. All transactions or the ones needing attention, each dated with its type in a word, its amount and the running balance; entries that…
- [Dispensing](https://beamline.io/components/dispensing): Dispensing from the shelf by lot. A product is found with its stock and prices (consumables left out unless asked); the quantity is drawn across its…
- [Record sharing](https://beamline.io/components/record-sharing): Records sent out of a clinic. Several visits' records and their documents (record, invoice, plan, lab result, image) are chosen separately, with how much…
- [Client journal](https://beamline.io/components/client-journal): A client's journal from both ends. The client's side is their home, built around their day: today's goals with how many are done and a mark each, done…

Part of [Beamline UI: polished, editable React components and complete screens for custom applications](https://beamline.io/). [Build your own style from any look; tokens, fonts, radii, motion; not only colours](https://beamline.io/docs/customize).
