Drag, resize, duplicate
Reschedule by dragging the card. Resize by dragging the bottom edge. Alt-drag to duplicate. The card follows the cursor smoothly while a dashed snap-target ghost shows where it'll land on a 15-minute boundary.
Editing the calendar is mostly direct manipulation: grab the card, drop it where you want it. The same gesture works for moving, resizing, and copying — only the modifier key changes.
Drag to reschedule
Click and drag any event card. The card follows your cursor at 1-pixel resolution; a dashed accent outline shows where it will snap on release. The card’s inline label updates live to show the new time, so you see what you’ll get before you let go.
- Drop on the same staff column → time changes, staff stays.
- Drop on a different staff column → time and staff both change.
- Drop where it overlaps an existing booking → soft warning panel (“Slot overlaps an existing booking · Book anyway”). The default behaviour blocks the conflict; you can opt to overlap when it’s intentional (walk-in, double-up).
The snap granularity is 15 minutes by default. At 4× zoom, the snap tightens to 5 minutes so the cursor lines up with the visible 5-min ticks.
Why delta-based, not cursor-based?
Most calendar apps (FullCalendar, Google Calendar, Outlook) use delta-based drag: the card moves by the cursor’s vertical distance. So if you grab the middle of a 60-minute card and drag down 30 minutes, the start moves 30 minutes — not to wherever the cursor lands. This is the right behaviour for nudging existing events; the card’s relative position to the cursor stays the same.
If you want start = cursor semantics (drop the cursor at 4 PM → event starts at 4 PM regardless of grab point), tell us — it’s a flag we can flip.
Resize duration
Click and drag the bottom edge of an event card. The card expands or shrinks; the inline label updates live with the new end time. Release to commit.
- Hit zone is 8 px with a mouse, 12 px on touch.
- Resize never changes the start; only
end_atmoves. - Minimum duration is 15 min — the system clamps to that.
Alt-drag to duplicate
Hold Alt (Option on Mac) while dragging. The card stays in
place and a cyan dashed COPY ghost previews the new clone’s
position. On release, a new appointment is created with the same
customer, services, duration, notes — only the start time (and
optionally staff) is new.
Drag → reschedule
Drag bottom → resize
Alt + drag → duplicate
Click vs drag
If you tap and don’t drag, that opens the event details modal. Drags only commit if the cursor moved more than 4 px from the click point — small jitter doesn’t accidentally trigger a reschedule.
After a real drag commits, the synthetic click that browsers fire
post-pointerup is suppressed for one tick, so the details modal
doesn’t pop open right after you drop a card.
On mobile / touch
All three gestures work on touch with one tweak: drag-to-reschedule on touch starts after a long-press (500 ms). Otherwise the gesture is a finger-swipe to navigate days. Resize handle is bigger (12 px) so you can grab it with a thumb.
Right-click is replaced by long-press on touch — same context menu.
Cancelled-on-the-server fallback
Drag commits via PATCH /api/dashboard/appointments/:id with the
new start/end/staff. If the server rejects (e.g., another operator
took the slot a second before you), the card snaps back to its
original position and a soft error toast appears. Your local
optimistic move never gets out of sync with the server.