# Calendar A living reference for the day calendar on `/staff` (a barber's own day) and `/owner/calendar` (everyone, one column per barber). Both render `src/features/staff/components/day-calendar.tsx`. ## What it's built on [react-big-calendar](https://github.com/jquense/react-big-calendar) (MIT) with its drag-and-drop addon, restyled to match the app in `day-calendar.css` (scoped under `.day-cal`). It was chosen over DayPilot Lite mainly because per-barber columns, a current-time line and sideways scrolling on a phone all work out of the box; FullCalendar and Schedule-X put per-resource columns behind a paid licence. Only the day view is used. The agenda (list) view is a separate component. ## Time zones — read this before touching it The library works in JavaScript `Date`s, which carry the **browser's** time zone; the app's scheduling data is **business-local minutes since midnight on a business-local date**. So the calendar never sees a real instant: times go in as "floating" dates (minutes laid onto one fixed day — `calendar-time.ts`) and a drop comes back out as plain minutes. The real date and the business time zone are applied on the server in `moveCalendarAppointmentAction`. ## Drag to reschedule Turned on per page with the `reschedule` prop (`"owner"` or `"staff"`). - A drop **never saves on its own.** It opens a confirmation ("From 11:00 AM with Leo → To 1:00 PM with Leo… the customer will be notified"), because a reschedule emails the customer. - `"owner"`: any appointment in the business, and it can be dropped into another barber's column (a reassignment). `"staff"`: their own bookings, along the time axis only. - Only `pending_approval`, `confirmed` and `arrived` bookings can be moved — the same statuses `rescheduleBooking` accepts. Breaks, time off, and finished or in-progress bookings are not draggable. Resizing (changing the length) is off: duration comes from the services. - **The server is the gate.** `moveCalendarAppointmentAction` delegates to the existing `ownerRescheduleAppointmentAction` / `rescheduleStaffAppointmentAction`, so working hours, breaks, overlaps, the staff member's services, the business's minimum-notice rule, the audit log, notifications, reminders and Google Calendar sync all behave exactly as they do from the appointment screen. A rejected move shows the reason inside the dialog and nothing is saved. - The calendar itself does not stop you dropping onto a break or outside someone's hours — it just fails the server check. ## Phones Columns keep a 190px minimum and the grid scrolls sideways, with the hour labels pinned on the left and the header row scrolling with it. Dragging was verified with a mouse only; the library has touch handlers but this has not been tried on a real touch screen. The appointment screen's Reschedule always works.