Skip to content

Slot picker should open focused on the session you clicked, not at 00:00 of the current week #1073

Description

@teetangh

Opening Manage Timings, Allocate or Reschedule drops you into a calendar showing an arbitrary week at an arbitrary scroll position. If the booking you came to edit is on Saturday at 10:30, you have to find Saturday and then scroll down past ten hours of empty night-time rows before you can see it.

The picker should open already looking at the thing you clicked.

What you see today

Two separate problems, and they need separate answers.

Vertical. The grid renders 00:00 through 23:30 and opens at the top. Every consultant's real working day is somewhere in the middle, so the first interaction on every visit is scrolling.

Horizontal. The week shown is the current week, not the week the booking is in. For a session next month you navigate week by week to reach it.

The screenshot that prompted this shows both: a booking at 10:30 on Saturday 1 August, in a grid scrolled to 09:00 with the row barely visible, on a week the user happened to already be in.

What it should do

Open focused on the subject of the page, then let the user navigate freely from there. Concretely: pick a target instant, move the visible week to contain it, and scroll the time axis so it sits comfortably in view rather than flush against the top edge.

The interesting part is choosing that instant, because it differs per surface and per offering type.

One-session bookings — consultation, webinar

Unambiguous. The target is the session's own start. Manage Timings and Reschedule both have exactly one thing being placed.

Prolonged bookings — subscription, class

This is the case that makes the feature non-trivial, and the reason it deserves a decision rather than an implementation guess. A subscription is N sessions spread over weeks or months, each on its own Appointment row. The picker shows one week. So "the booking" is not a single point on the grid.

Candidate targets, roughly in order of how defensible they are:

  1. The next session that has not happened yet. Usually what a consultant means by "this booking" — the thing that is about to affect their week. Falls back to the most recent past session when they are all over.
  2. The earliest session still awaiting a time. Right for Manage Timings on a partly-scheduled program, where the job is to fill the gaps rather than look at what is already placed.
  3. The specific session that was clicked. Correct for Reschedule, where the user picked one session from the release step and that session is unambiguously the subject.

These are not competing — they are per-surface answers. Reschedule knows which session; Manage Timings on a partly-placed program means (2); Manage Timings on a fully-placed one means (1).

Worth deciding explicitly: on a subscription whose sessions run Tuesdays and Thursdays for three months, is jumping the user to week 7 helpful or disorienting? A defensible alternative is to focus the time of day always, but only move the week when the target is outside the currently visible one.

Nothing scheduled yet

An unscheduled class or webinar (the unscheduled-class-<id> / unscheduled-webinar-<id> synthetic ids) has no slot to focus. The sensible target is the start of the scheduling period, clamped to not be in the past — the picker already clamps selection to allowedStart/allowedEnd, so this reuses a bound it knows. Vertically, the consultant's own earliest published availability is a better anchor than 00:00.

Allocate

A pending request may carry requested times, in which case those are the target. If it does not, the same "first availability" fallback as above applies.

Why this is less complex than it looks

The pieces mostly exist. SlotPicker already receives a SlotPickerSubject carrying the slots, the event type and the scheduling period, so the target can be derived from data already on the page — no new query. The calendar already supports week navigation, so this is choosing an initial value rather than building a mechanism.

The genuinely fiddly parts are narrow:

  • Scrolling must happen after the grid has rendered its rows, and must not fight the user if they scroll immediately.
  • It must fire once per subject, not on every re-render, or the grid will yank itself back while someone is trying to look elsewhere.
  • The target is an instant, but the grid is drawn in the event's schedulingTimezone (ADR B9). Choosing the row must use the same timezone the columns were drawn in, or the focus will be off by the UTC offset — the same class of bug as the datetime-local defect fixed in feat(reschedule): dedicated pages, withdrawal, and an auto-confirm that cannot half-write #1064.

Scope

Applies to all four picker surfaces, since they share one component: Manage Timings, Allocate, and both Reschedule routes.

Out of scope: any change to what is selectable, to the palette, or to the allocation rules. This is purely where the viewport starts.

Open questions for a decision before implementation

  1. For a multi-session program, target the next upcoming session or the earliest unscheduled one? (Proposal: unscheduled if any, else next upcoming.)
  2. Should the week jump at all for a far-future target, or only the vertical scroll, with a hint that the target is elsewhere?
  3. Should focus re-fire when the user changes the release selection on a Reschedule page, or only on first open?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions