Skip to content

Calendar views & day detail ​

The Calendar module has two tabs and one always-visible filter bar. The defaults are tuned for "what's happening this month, at my branch" β€” the most common question β€” but the filters and view switch let you broaden or narrow as needed.

Calendar month view

The month grid ​

The Calendar tab is the default landing surface. It renders a traditional month grid with the selected date highlighted and three visual layers on every day cell:

  • Event dots β€” coloured by the event's chosen colour. One dot per event, capped visually so a busy day doesn't overflow.
  • Birthday markers β€” a small cake icon. Pulled directly from members.date_of_birth, not from any event row.
  • Today underline β€” the current date is underlined, regardless of which date you've selected.

Click any date to load the day-detail panel below the grid. Click the month name in the header to jump to month-picker; click the arrows to step one month at a time. The selected date persists when you change months β€” the panel still shows whatever was last picked.

TIP

You don't have to click into a day to read its events β€” hover over an event dot and a preview card appears with the title, time, and location.

What the grid actually queries ​

The month grid runs one Supabase query for the visible window: every event whose event_date falls in the month or whose recurring = true regardless of date. The browser then expands the recurring rows into individual occurrences using the RRULE, filtering out exception dates and dates past recurrence_end_date. There's no server cron pre-computing occurrence rows β€” everything is derived on the fly.

That means changes propagate instantly. Edit a recurring event's RRULE and the new dates render on next render; add an exception and the cancelled date disappears the moment the query revalidates.

The day-detail panel ​

Below the grid, a card shows everything on the currently selected date β€” events first, then birthdays, separated by a divider when both are present. Each event card carries:

  • A coloured bar matching the event's colour.
  • Title, start/end time, location.
  • A repeat icon if the date came from a recurring expansion.
  • A branch badge if the event is scoped to a specific org unit.
  • Edit and delete buttons (visible only if you have events.edit / events.delete).

Click anywhere on the card to open the edit dialog; click the trash icon for the soft-delete confirmation. Birthday cards are clickable and link straight to the member's profile.

The empty state is intentional: if nothing is on the date and you have events.create, a small "+ Add event" link appears in the empty panel so you can fill it in without leaving the screen.

The upcoming list ​

The Upcoming tab flips the calendar over: instead of laying out a month, it shows the next twenty events from today forward, in chronological order. Each row is the same compact event card you see in the day panel, plus a date label.

Use this tab when you're answering "what's next?" rather than "what's on March 14?" β€” it's the right view for a Monday morning leaders' meeting where you're reviewing the week ahead.

The upcoming query is bounded by branch filter and by the user's role. A shepherd assigned to one branch sees only that branch's events; a global admin sees all twenty across the org.

Filtering by org unit ​

The toolbar carries a single dropdown labelled with a branch icon. By default it shows your assigned branch; admins with global scope see "All branches."

The filter applies an OR org_unit_id IS NULL clause, which means org-wide events stay visible no matter which branch you pick. A Christmas service marked as org-wide shows up on every branch's calendar. Only branch-specific events (with a concrete org_unit_id) get scoped out.

Users whose role doesn't span the whole org only see the branches they're assigned to in the dropdown. There's no "leak" β€” picking a branch you're not assigned to isn't an option in the first place.

WARNING

The filter doesn't currently support multi-select. If you need to compare two specific branches, switch between them; if you need a true cross-branch view, pick "All branches."

Filtering by event category ​

Each event has a category text column (set on the event form, separate from colour) β€” values like service, outreach, meeting, social. The calendar doesn't surface category as a top-level filter today; it's recorded for use by reports and by future filter passes.

If you're looking for a single-category subset right now, the workaround is the upcoming list β€” visually scan by colour, since most orgs map colour onto category one-to-one (blue = service, green = outreach, etc.).

Permissions and what each role sees ​

The view rules are simple:

RoleSees
AdminEverything in the org, every branch.
PastorEverything in their assigned branches.
ShepherdOrg-wide events + their assigned branch's events.
MemberOrg-wide events + events in their primary branch.

The same events.view permission gates the page entirely. Without it, the menu item is hidden.

Mobile and small screens ​

On a phone, the month grid keeps its full layout but each cell shrinks; event dots collapse from coloured bars to small filled circles. The day-detail panel stacks below the grid as a separate card β€” tap the date you want, scroll down. The branch filter and tab switcher both move into the sticky toolbar so they stay reachable.

The PWA install is the better experience if you live on mobile β€” calendar views feel native and the day-detail tap-target is bigger. Push notifications also become possible once installed, which feeds the reminders flow without going through SMS or WhatsApp credits.