1.9 KiB
Dates Tab
Nav id: reservations (label is "Dates" — internal id kept as reservations)
Icon: ◆
What it shows
Upcoming confirmed meetings between Quinn and the client, sorted ascending by date. Past meetings are excluded (they move to the Story tab). Empty state shows an explanatory message rather than nothing.
Data flow
getRelationship(token) — GET /vip/relationship/:token — returns the full relationship object including all meetings. The Dates tab filters to meetingDate > now.
The same endpoint is called by the Story tab for past meetings and gifts. The two tabs share the API call but hold independent state — no shared cache, each re-fetches on mount.
Meeting object
interface VipMeeting {
id: string
meetingDate: string // ISO 8601
durationMinutes: number | null
locationNote: string | null
notes: string | null // visible to client
}
Display logic
Each upcoming meeting renders:
- Date + time (
formatDatetime— weekday, month, day, year, hour:minute) - Duration if
durationMinutes > 0(e.g. "2h", "1h 30m") locationNote— appended to duration with·, or shown alone if no durationnotes— italic secondary text, visible to client- "Confirmed" badge (gold, always shown for upcoming — no pending state exposed to client)
Border is borderHover (brighter gold) vs the default border used in Story — slight visual distinction to make upcoming dates feel more prominent.
Non-obvious details
- The tab id is
reservationsnotdates— matches the API concept (a reservation = a confirmed meeting slot). The label "Dates" is the client-facing wording. - There is no booking UI. Clients cannot request dates from this tab — it's read-only. Booking happens out-of-band (via Messages or external scheduling).
- Past meetings intentionally excluded here to avoid clutter. Full history is in Story.