Skip to content

feat(app): public witnessing - #5297

Draft
ux-git wants to merge 10 commits into
sws2apps:mainfrom
ux-git:feat_public_witnessing
Draft

feat(app): public witnessing#5297
ux-git wants to merge 10 commits into
sws2apps:mainfrom
ux-git:feat_public_witnessing

Conversation

@ux-git

@ux-git ux-git commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

Implements the Public Witnessing MVP (frontend + local-first data layer), following the Figma "Public witnessing MVP" section: a locations list with details, and a day view where publishers book witnessing shifts.

Since the app is a local-first PWA, this includes the IndexedDB model, state and mutation services — only the congregation sync endpoint remains for a later PR.

What's included

Data layer. Two Dexie tables (public_witnessing_locations, public_witnessing_arrangements) registered as schema v13, following the established vertical slice: definition types using the _deleted/updatedAt data-blob pattern, soft-delete services that flag metadata.send_local for auto-sync, jotai atoms wired through the IndexedDb wrapper.

Two decisions worth reviewing:

  • Shifts are virtual. A day's slots are derived at render time from the location's per-weekday schedule merged with booked arrangements — nothing is materialized per date, so changing a location's hours never migrates stored rows.
  • One record per booking action (author in created_by), so two publishers booking the same slot offline merge without conflicts. Joining a partner-seeker creates the joiner's own record and never mutates the seeker's; the orange "partner needed" state is derived.

Locations management (admin: app admin + service overseer, via usePermissions).
Two-column page — sidebar (reusing settings_tab from the settings redesign, #5224) and a details card with badges and description. Add/edit dialog with General information and Schedule tabs (approved days + per-day shift ranges), delete confirmation (soft delete), and drag reorder persisting sort_index.

Day view + booking (all users).
Day navigation with jump-to-today, plus the segmented TabSwitcher from #5291 (week/month rendered but disabled — post-MVP). Shift cells follow the design's states: available, partner needed (orange), fully occupied (dashed) and past. Cells are interactive only for bookable states, the arrangement's author, or admins.

The "Confirm the arrangement" dialog covers every flow in the Figma: partner needed with a wanted-count, "I have a partner" with a persons autocomplete that also accepts free-text (partners who aren't app users), the admin For myself / For others tabs, joining a seeker, editing/cancelling, and the add-to-calendar ICS prompt after booking.

Mobile. The page shows only the locations list; a location opens as a subpage via its own route (/public-witnessing/:locationId), so the app navbar renders it as a subpage with a working back arrow. In the schedule tab, a day's shifts expand inline under it.

Notes for reviewers

  • Locale keys are reused, not duplicated. Most strings already existed (tr_PW* family, tr_startTime/tr_endTime, weekday names); only a handful of genuinely new keys were added. Figma labels were mapped onto existing wording rather than adding synonyms (e.g. Figma's "From/To" → the existing Start/End).
  • IconReorder fix: its center dot was a separate <circle>, which the app's icon recoloring (svg g path selectors) never reached, so the dot kept a hardcoded fill. Merged into the arrows path — this affects every existing usage of the icon, and is a drive-by fix.
  • Entry point is the Ministry dashboard card.
  • Not in this PR (post-MVP): week/month views, the Location map tab, backend sync.

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
staging-organized-app Ready Ready Preview Jul 16, 2026 4:38pm
test-organized-app Ready Ready Preview Jul 16, 2026 4:38pm

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b9500cc7-dd20-454b-ba56-d5a47f89f3dc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

ux-git added 9 commits July 16, 2026 18:33
Locations and arrangements tables follow the established vertical slice:
definition types with the _deleted/updatedAt data-blob pattern, Dexie
v13 schema, soft-delete services flagging metadata send_local, jotai db
atoms wired through the IndexedDb wrapper, and a publisher route with a
Ministry dashboard entry (reusing the existing tr_PW locale key).

Arrangements are one record per booking action (author in created_by)
so concurrent offline bookings merge without conflicts; day-view shifts
are derived from the location's per-weekday schedule and never stored.
Two-column page: locations sidebar (settings_tab from the settings
redesign, PR sws2apps#5224) and a details card with badges and description.
Admin actions gated by usePermissions (app admin + service overseer):
add/edit dialog with General information and Schedule tabs (approved
days + per-day shift ranges), delete confirmation (soft delete), and
drag reorder persisting sort_index.

Shift time rows memoize their Date values in a dedicated ShiftRow —
the shared TimePicker resets its in-progress edit whenever the value
prop identity changes. Locale keys reuse the existing tr_PW*/general
strings; only genuinely new labels were added.
Shifts card composes day navigation (arrows + jump-to-today, matching
the field-service-meetings calendar pattern) with the segmented
TabSwitcher from the clicker PR (week/month disabled for now). Day
slots are derived at render time from the location's weekday schedule
merged with booked arrangements — nothing is materialized per date.

Cell states follow the design spec: available (accent border + chip),
partner needed (orange, stays open until the requested partners join),
fully occupied (dashed) and past. Cells are interactive only for
bookable states, the arrangement author, or admins.

The confirm-the-arrangement dialog covers all flows: partner needed
with a wanted-count, I-have-a-partner with a freeSolo persons
autocomplete (non-app partners stay name-only), admin for-myself /
for-others tabs, joining a seeker (creates the joiner's own record —
derived state keeps records conflict-free), edit and cancel, and an
add-to-calendar ICS prompt after booking.
Schedule tab now matches the design measurements: fixed 240px approved
days column, vertical divider with 32px gaps, 16px shifts-column
spacing, 48px day rows, and a 16px dash between the start/end time
fields. Tab content renders through the Tabs component's own panels,
removing the double gap the empty tabpanels used to add (same fix in
the arrangement dialog).

Header actions reordered to Reorder / Edit / Add with Add as the main
button, and the max publishers badge shortened to "Max. publishers".
Shift cells now behave like buttons: outlined states fill with
accent-100 on hover instead of casting a shadow, and publisher names
use the smaller text style. The day header drops the year from its
label and paints the jump-to-today icon black; the no-shifts state
uses the standard info-icon message row.

IconReorder's center dot was a separate circle element that CSS
recoloring (svg g path selectors) never reached — merged into the
arrows path so the glyph is one shape. The cart badge icon gets an
explicit accent-dark color for the same reason: its paths sit directly
under the svg root with a hardcoded default fill.

Location dialog: badges use the small size, the storage field label is
now "Stored at", "Every day" shows an indeterminate state when only
some days are approved, Add shift uses the small button variant, shift
delete buttons sit in the 48px rounded container used by the circuit
overseer week rows, and an unselected schedule shows a select-a-day
hint with no divider.
The shift-row trash button cancels the IconButton edge-start negative
margin that was eating its left spacing, and the day checkboxes drop
the FormControlLabel offset so the row's 8px inner padding matches the
design. The location delete action moves from a full-width button at
the dialog bottom to a small red button beside the Edit location title.

Max. publishers per shift is now optional: the field may stay empty,
the badge hides when unset, and shift capacity falls back to the
default of 3.
Mobile now mirrors the app's subpage pattern: the page shows only the
locations list, and tapping a location opens its details as a subpage
using the SubpageNavbar from the clicker PR (location name with the
parent page underneath, animated back arrow returning to the list).

The day navigation adopts the field service meetings calendar layout:
single row on tablet+ with the toggle right-aligned, stacked on mobile
with the arrows pushed to the card edges; the jump-to-today control
always reserves its slot so the label never shifts, the label gets a
180px centered slot with ellipsis, and min-width guards keep the
switcher and header clipped inside the card.
On mobile the schedule tab no longer stacks a detached shifts panel
under the day list — the editor expands inline right under the tapped
day, with expand/collapse chevrons on the far right of approved days
and tap-to-toggle behavior. Desktop keeps the two-column layout.

Small buttons (Add shift, Add person, the title Delete) now pass
disableAutoStretch so they stay compact instead of stretching to the
global full-width mobile button default.
The mobile detail view was rendering its own SubpageNavbar below the
app navbar, so the screen showed two headers. The app navbar already
renders a back arrow with a title and secondary title, so the detail
is now a real route (/public-witnessing/:locationId) that drives it
through PageTitle: one header, and the navbar back arrow returns to
the list on its own. The cherry-picked SubpageNavbar is dropped — it
exists for fullscreen overlays that cover the navbar, not for this.

Also: the empty locations state uses the InfoNote card variant, the
locations list keeps its chevron visible on touch devices (hover never
fires there), the dashboard entry uses the cart icon, and a day's
shifts only open once the day is approved — tapping an unapproved row
approves it, unchecking closes its shifts again.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant