Files
Stefan Lazic a8a8d1e045
CI / ci (push) Canceled after 0s
Updated Calendard
The calendar is now react-big-calendar.
2026-10-08 11:01:32 +01:00

2.8 KiB

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 (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 Dates, 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.