Skip to content

Profile refactor, dispatch vocabulary presets, and UI cleanup - #19

Merged
evanqua merged 16 commits into
mainfrom
feature/profile-refactor
Aug 12, 2026
Merged

Profile refactor, dispatch vocabulary presets, and UI cleanup#19
evanqua merged 16 commits into
mainfrom
feature/profile-refactor

Conversation

@evanqua

@evanqua evanqua commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Refactor the profile page (self-service password reset, admin venue/user management, account deletion) and add an org-wide customizable dispatch vocabulary (presets, translation context, wired across dispatch views)
  • Clean up profile/venue-selection UI: cap organization/member/venue/event lists with the minimal scrollbar instead of growing unbounded, drop the checkmark background and move the label outside on the preset "Based on" select, and remove the focus ring on the Delete Account input
  • Align dispatch call rows with clinic rows (matching chip height and action-menu cell/button classes) so row sizing and padding are consistent between the two tables

Test plan

  • tsc --noEmit passes
  • Manually verify profile, venue selection, and dispatch pages in a browser

evanqua and others added 16 commits August 11, 2026 19:36
Strips the profile page down to essentials (info, security, preferences)
and adds an admin section for managing event certifications and other
admins, backed by a new isAdmin flag on the user doc. Adds a proper
reduced-motion preference (previously only OS-driven), a collapsible
password-change form, a redesigned edit-profile page, and a self-service
"forgot password" flow using each backend's built-in email reset link
so locked-out users don't need admin intervention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ion Venues

Admins can now delete a user's venues, events, dispatch logs, and profile
doc from Profile > Admin > Manage Administrator Access (fully removes the
account on PocketBase; on Firebase the Auth record itself has to be
removed separately via the console, since the client SDK can't delete
another user's auth account without a privileged server credential).

Also adds Organization Venues: an admin can mark venues they own as
visible to every user on the instance, instead of sharing them with
people one at a time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ation context

Lays the groundwork for customizable dispatch terminology: a canonical term
registry keyed by the exact English strings already used internally (so the
default preset is an identity mapping with zero data migration), CrowdCAD
Default and CrowdCAD French built-in presets, and a DispatchVocabularyProvider
context exposing t(key) for render-site translation. No wiring into the
dispatch UI yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ed forks

Adds UserDoc.dispatchVocabularyPresetId, a dispatchVocabularyPresets
collection service (list/create, following the same flat/unfiltered query
pattern as org venues so custom presets are visible to every signed-in
user), and useDispatchVocabulary to tie it together with a localStorage
fallback for lite/unauthenticated mode.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New card in Preferences lets a user pick a dispatch vocabulary preset
(built-in or a shared custom one) and browse/edit every term grouped by
category. Editing always forks a newly-named, org-shared preset rather than
mutating the one currently selected — verified end-to-end in the browser
(preset switch, term editor, fork-and-save all round-trip correctly).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wraps the dispatch route in DispatchVocabularyProvider and switches its own
render-site labels (tab titles, section headers, add/empty-state copy) to
t() lookups, leaving every status comparison and stored value untouched.
Verified in-browser with a live lite event: switching to CrowdCAD French
correctly renders "Équipes", "Appels totaux", "Ajouter un appel", etc.
Also adds a few chrome terms (No teams available, Show/Hide Resolved Calls)
discovered while wiring.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…details

Table headers (trackingtablebase.tsx), status chips/dropdowns, add-team/
supervisor/equipment submenus, log/duplicate/priority/delete actions, and
the expanded call details panel now render through t() at each display
site. Status dropdown keys stay on the canonical English value (key={status})
so handleTeamStatusChange and all resolved-status comparisons are untouched
— only the rendered label translates. Adds a handful of terms discovered
while wiring (No available teams/supervisors/equipment, Notes, Add notes,
No log entries, Log for Call, the priority-call banner).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Status selects, location autocomplete, Refresh Post/Edit/Delete menu items,
member list header, activity log placeholder, and the (Lead) display suffix
in both teamcard.tsx and its condensed variant now render through t().
The (Lead) storage marker used by member-string parsing is left untouched;
only the formatted display label is translated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Clinic status dropdown (In Clinic/Transported/AMA/Discharged), Walkup
fallback, primary team, notes/log panels, and the No clinic calls empty
state now render through t(). Also catches No clinic calls in page.tsx,
missed during the earlier page-shell pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Equipment status/location controls, Mark Ready/Delete menu, staging/
delivery/notes labels, the clinic walkup modal, add/edit team and
supervisor modals, and the quick-call modal now render through t().
Team-location fallbacks ('Unknown', 'Clinic') translate via the same
identity-fallback t() call used elsewhere, so custom venue post names
pass through untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The desktop Show Resolved Calls / Show Resolved Clinic Calls toggle
buttons live inside calltracking.tsx/clinictracking.tsx themselves (not
page.tsx, where only the mobile variants were wired) and stayed in
English under the French preset — fixed in all three locations.

Also wires the dispatch-only navbar items: Venue Map, Posting Schedule,
End Event, and Venues in appnavbar.tsx, plus the lite dispatch navbar's
Posting Schedule/End Event/Clear Event/Export Summary. Both navbars
render outside DispatchPage's provider tree (they're siblings in
AppShell/LiteLayout, not descendants), so each calls useDispatchVocabulary()
directly rather than relying on context.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a "New preset" flow (pick a base preset + name, forks and switches
to it immediately so the term editor can be opened to customize) and a
"Your presets" list that surfaces only presets the current user created,
each with a delete action. Built-in presets and presets created by other
org members are never deletable — deletePreset() in useDispatchVocabulary
enforces createdBy ownership before touching Firestore/localStorage, and
resets the caller back to CrowdCAD Default if they delete their own
currently-active preset. Also adds the disclaimer that the preference is
per-user (not shared across dispatchers) and that logs always stay English.

Verified live: creating "My French Variant" from the CrowdCAD French
template correctly forked and activated it, and it appeared in Your
presets with a delete control.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Root-caused the "navbar still shows English" report: AppNavbar/LiteNavbar
live in the persistent root layout and never remount on client-side
navigation, so their one-time mount fetch never re-ran after the user
changed their preset elsewhere in the same session — they stayed frozen
at whatever was active on first load. Adds a small pub/sub bus
(changeBus.ts) that every useDispatchVocabulary() instance broadcasts to
and listens on, so all mounted consumers (navbar included) update
immediately on select/create/update/delete, no refetch required.
Verified live end-to-end on a real cloud event: switching to CrowdCAD
French now updates the navbar (Plan du site / Horaire des postes /
Terminer l'événement / Sites) instantly on client-side navigation.

Also, per feedback:
- Editing a preset you created now saves in place (updatePreset); editing
  any other preset (built-in or another org member's) still forks a new
  one — verified live, including a reload to confirm the in-place write
  persisted server-side.
- "New preset" now offers a Blank template (empty terms map) alongside
  existing presets to start from — verified live.
- Replaced the Select dropdown + separate "Your presets" list with a
  single row-based table: each row has an active indicator/selector, an
  Edit button (opens the term editor scoped to that preset), and a Trash
  button restricted to presets the user owns. The term editor's scroll
  container now uses the app's existing minimal-scrollbar utility instead
  of the default browser scrollbar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t select

- Add max-height + minimal-scrollbar to org venues, users, and venue
  selection lists so they scroll instead of growing unbounded
- Remove the selected-item background behind the "Based on" preset
  checkmark and move its label outside the input box
…delete-account input ring

- Apply minimal-scrollbar + max-height to the per-venue events list
  (mobile card list and desktop table) on the venue selection page
- Remove the focus ring/outline on the Delete Account password input
- Shrink call-row team chips from h-9 to h-8 so the row height settles
  on the same min-height floor as clinic rows instead of exceeding it
- Drop redundant width/alignment classes on the call row's action-menu
  cell and button so it matches the clinic row's simpler structure
@evanqua
evanqua requested a review from iv-zhang as a code owner August 12, 2026 22:21
@evanqua
evanqua merged commit 2a45dca into main Aug 12, 2026
2 of 4 checks passed
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