Show booking host working-hours status and manage shared availability - #4999
Conversation
Adds get-host-overlay-status and get-overlay-reciprocity actions, the shared overlay-request reservation state module, and person-calendar helpers used to detect whether a booking-link host has added the link owner back to their own calendar and has real working hours configured.
Adds the send-overlay-request action with an atomic, reservation-based rate limiter (per-peer cooldown, per-owner daily cap tracked as a fixed-window counter, and stale-reservation recovery) plus the email template it sends. Fixes email-template.ts paragraph escaping so plain-text email bodies render correctly.
Adds HostOverlayStatusIcon and SharedAvailabilityPanel to surface, per booking-link host, whether they've added the link owner back and whether their real working hours are applied, with loading/error/empty states and a keyboard-accessible tooltip. Wires the send-overlay-request action into BookingLinksPage.
Sidebar previously toggled a merged person/Google calendar row's two underlying visibility flags independently, which could require two clicks to actually show/hide it, and CalendarView filtered overlay events without accounting for a hidden merged Google source. Both now resolve to a single merged visible/hidden state, and the sidebar alphabetizes and dedupes shared/overlay calendar entries.
formatRelativeTimeFromNow used a hardcoded 'en' locale and returned the literal string 'just now' instead of an Intl.RelativeTimeFormat value; it now takes the active locale and lets the formatter produce the localized string. Adds the overlayRequestInProgress string across all locale catalogs and shortens shared-availability copy.
… design Adds the design/plan docs for the shared-availability tab and the booking-host working-hours status feature, the user-facing changelog entry, and updates the availability-booking skill notes.
…60a606a93fe947758482
Sidebar status checks and the main events query both send overlayEmails to list-events, which caps the array at 10. Beyond that, the sidebar status query 400'd outright and event loading silently dropped events for peers past the 10th. Both now split overlayEmails into batches of 10: the sidebar status check runs one inventory query per batch, and useEvents keeps the primary list-events query on the first batch while fetching extra batches as separate, source-scoped, read-only queries merged into the final event list. Mutation invalidation, prefetch, loading/placeholder state, and error surfacing all account for the extra batches.
|
@builderio-bot review the latest PR feedback (any commenter) and fix what you agree with — be skeptical, and reply on each comment thread with what you did and why (or why not). Also flag accessibility (WCAG 2.1 AA), performance, and security issues in the changed code; fix the easy ones, flag anything that needs a judgment call. |
…60a606a93fe947758482
|
Addressed the automated review feedback:
Additional pass for accessibility/performance/security in the changed code, per the request:
Ran the calendar template's full test suite (743 tests, all passing), |
…erson calc, and locale label
|
Pushed to the PR branch. Here's a summary of what was done on PR #4999: Fixed (3 medium + 1 low from the automated review):
Reviewed and found clean (a11y/perf/security pass across the diff): status icons pair color with text/aria-labels, destructive actions use confirm popovers not Replied on each of the three inline review threads, posted a summary comment on the PR, verified with the full calendar test suite (743 passing), typecheck, and ⠀ |
|
@builderio-bot review the latest PR feedback (any commenter) and fix what you agree with — be skeptical, and reply on each comment thread with what you did and why (or why not). Also flag accessibility (WCAG 2.1 AA), performance, and security issues in the changed code; fix the easy ones, flag anything that needs a judgment call. |
|
No merge conflicts ( Summary: Fixed a real concurrency bug — the overlay-people add/remove/color-change mutations read-then-fully-replaced the list client-side, which is a classic lost-update race across tabs or UI surfaces. Fixed it the same way this PR already fixes an analogous problem elsewhere ( ⠀ |
There was a problem hiding this comment.
Builder reviewed your changes and found 2 potential issues 🟡
Review Details
Incremental Code Review Summary
The previously open concurrent overlay mutation issue is fixed. Add, remove, and color updates now use dedicated server actions with mutateUserSetting compare-and-swap semantics instead of client-derived full-list replacements; that comment was verified and resolved.
Two new correctness issues remain in the new server action layer. The PR remains high risk because it combines shared availability settings, agent-callable mutations, and rate-limited transactional email behavior.
New Findings
- 🟡 MEDIUM — Pruning stale pending reservations removes the per-peer marker but does not decrement the daily count that was reserved before delivery. Repeated abandoned sends can exhaust the owner’s daily quota without delivering emails.
- 🟡 MEDIUM — The atomic add action compares email strings case-sensitively, allowing case variants of the same address to become duplicate overlay peers despite case-insensitive behavior elsewhere.
Previously reported email-delivery uncertainty concerns were not reposted under incremental-review deduplication rules.
🧪 Browser testing: Will run after this review (PR touches UI code)
…ation quota leak - add/remove/update-overlay-person-color now compare emails case-insensitively, matching the rest of the codebase's normalization convention. Previously Peer@Example.com and peer@example.com could exist as duplicate rows. - send-overlay-request now releases the daily-cap slot when pruning an abandoned pending: reservation, so a crashed/timed-out send no longer permanently consumes one of the owner's 20 daily request slots.
|
Addressed the latest incremental review (2 new findings): Fixed (2):
Verified: 743 tests pass, typecheck clean, all 73 guard checks pass, oxfmt clean. No merge conflicts ( I also re-scanned the diff for accessibility/performance/security issues — the new server actions have no UI surface (a11y n/a), only mutate the calling user's own settings (no cross-user access concern), and are covered by the existing case-insensitivity/rate-limit fixes above. No new issues found. |
…60a606a93fe947758482 # Conflicts: # templates/calendar/app/hooks/use-events.ts # templates/calendar/app/pages/CalendarView.tsx
…60a606a93fe947758482
…60a606a93fe947758482
Summary
Adds a per-host indicator in the booking-link editor showing whether a host's real working hours (vs. just free/busy) are being used, with a one-click request flow to fix it, and moves peer-relationship management into a dedicated "Shared availability" tab on the booking-links page.
Clip:
https://clips.agent-native.com/share/o440oSgx9XZG?ref=clip_share
Problem
Booking links silently degrade to free/busy-only checking when a co-host hasn't reciprocally added the link owner to their own calendar, or hasn't saved a working-hours schedule. Owners had no visibility into this degradation and no way to act on it. Separately, peer/overlay management was buried in a collapsible "People" section of the sidebar, mixed in with unrelated calendar visibility controls, and duplicated with a hover-only remove action that risked accidentally severing a peer relationship.
Solution
send-overlay-request) action that emails a peer asking them to add the owner back, guarded by an overlay-list-only check, per-peer cooldown, per-owner daily cap, and an atomic reservation to prevent duplicate sends.navigate'saddPersonEmail) and a dedicated/shared-availability/addlanding page so the request email's CTA works reliably for a signed-out recipient clicking from their inbox.Key Changes
server/lib/booking-host-availability.ts: extractedresolvePeerScheduleAndTimezone, addedgetHostOverlayStatusesandgetOverlayReciprocity.get-host-overlay-status,get-overlay-reciprocity,send-overlay-request, each with extensive access-control and rate-limit tests.server/lib/overlay-request-emails.tsandoverlay-request-reservation.ts, plus a registered transactional email.use-host-overlay-status.tsand componentHostOverlayStatusIcon.tsx(four visual states, new--successtheme token inglobal.css).SharedAvailabilityPanel.tsxcomponent andAddSharedAvailability.tsxpage/route.BookingLinksPage.tsx: added a "shared" tab with URL deep-linking, wired host status icons intoBookingHostsEditor.Sidebar.tsx: removed the "People" collapsible, merged overlay peers with matching shared Google calendars into single rows, dropped the hover-only remove button.AddCalendarDialog.tsx/AppLayout.tsx/use-navigation-state.ts: addedprefillPersonEmail/addPersonEmailsupport to open the add-people dialog prefilled without auto-adding.use-events.ts/use-google-calendars.ts: batched overlay email requests past the 10-email server cap and avoided optimistic-mutation cross-contamination between own and overlay events..agents/skills/availability-booking/SKILL.mdand added implementation plan docs underdocs/plans/.packages/core: corrected therenderEmailparagraphsdoc comment to clarify strings are injected verbatim (not escaped), with a changeset.To clone this PR locally use the Github CLI with command
gh pr checkout 4999You can tag me at @BuilderIO for anything you want me to fix or change