Shared, defensive helpers for the calendar's dashboard widgets.
Every function here is scoped to the widget VIEWER (via the scope the host
dashboard passes) and fails soft: no scope, a disabled module, or a missing
table all collapse to an empty result rather than crashing the host — a
widget must never take the dashboard down with it.
Times are handled the same way as the rest of the calendar: events are stored
in UTC and shown in the viewer's offset-hours frame (their user_timezone
setting → site time_zone → "0").
Summary
Functions
Height-based compact flag: a one-row-tall widget renders tighter.
The viewer's non-cancelled events overlapping [from, until) (dates in the
viewer's frame), through the authorized context path. "Theirs" means the same
set the main calendar shows a person — events they OWN plus events they are a
PARTICIPANT in — never anyone else's. Any failure (no scope, disabled module,
missing table) yields [].
The viewer's LOCAL today (their offset frame), not UTC today.
The list of calendar dates an event occupies in the viewer's frame — used to place per-day markers. All-day events use their exclusive DATE end; timed events use their shifted local dates, excluding an end that lands exactly on local midnight (that boundary belongs to the previous day).
Whether the event occupies date in the viewer's frame.
Chronological sort key. An all-day event sorts at the very start of its day (00:00), so events read soonest-first across days AND all-day events lead a single day's agenda — one key serves both the Upcoming and Today widgets.
The viewer's offset-hours timezone string (never raises).
The viewer's user uuid, or nil when there is no authenticated scope.
Functions
Height-based compact flag: a one-row-tall widget renders tighter.
@spec fetch_events(term(), Date.t(), Date.t()) :: [ PhoenixKitCalendar.Schemas.Event.t() ]
The viewer's non-cancelled events overlapping [from, until) (dates in the
viewer's frame), through the authorized context path. "Theirs" means the same
set the main calendar shows a person — events they OWN plus events they are a
PARTICIPANT in — never anyone else's. Any failure (no scope, disabled module,
missing table) yields [].
The viewer's LOCAL today (their offset frame), not UTC today.
@spec occupied_dates(PhoenixKitCalendar.Schemas.Event.t(), String.t()) :: [Date.t()]
The list of calendar dates an event occupies in the viewer's frame — used to place per-day markers. All-day events use their exclusive DATE end; timed events use their shifted local dates, excluding an end that lands exactly on local midnight (that boundary belongs to the previous day).
@spec on_date?(PhoenixKitCalendar.Schemas.Event.t(), Date.t(), String.t()) :: boolean()
Whether the event occupies date in the viewer's frame.
@spec sort_key(PhoenixKitCalendar.Schemas.Event.t()) :: DateTime.t()
Chronological sort key. An all-day event sorts at the very start of its day (00:00), so events read soonest-first across days AND all-day events lead a single day's agenda — one key serves both the Upcoming and Today widgets.
The viewer's offset-hours timezone string (never raises).
The viewer's user uuid, or nil when there is no authenticated scope.