Skip to content

Casadesign - DRAFT DO NOT MERGE#7051

Draft
giacoelho wants to merge 79 commits into
mainfrom
casadesign
Draft

Casadesign - DRAFT DO NOT MERGE#7051
giacoelho wants to merge 79 commits into
mainfrom
casadesign

Conversation

@giacoelho

Copy link
Copy Markdown
Collaborator

This is a work in progress. Will flag when it is ready to merge.

gia and others added 12 commits July 9, 2026 17:49
Introduce Tailwind v4 alongside the existing Bootstrap stack so the UI can be
modernized page-by-page without breaking current views.

- Add tailwindcss + @tailwindcss/cli (v4), build:tailwind[:dev] npm scripts,
  and a `tw` process in Procfile.dev. Output lands in app/assets/builds, which
  Sprockets already serves via the manifest's link_directory.
- Add app/assets/stylesheets/tailwind.css: CSS-first design system (Inter font
  + an indigo "brand" palette) — the visual direction for the redesign.
- New Tailwind-only layout casa_auth.html.erb (split brand panel + form),
  used by both the user and all-casa sign-in controllers.
- Redesign devise/sessions/new.html.erb in a clean, modern Stripe/Airbnb style
  and wire up remember-me properly.

Scoped to sign-in only; every other page keeps the Bootstrap `application`
layout untouched. First step of an incremental migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Approved font direction: swap the design-system typeface and the auth
layout's webfont link from Inter to Figtree (warmer humanist sans).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- design.md: living design-system doc (Tailwind v4 approach, Figtree type scale,
  color tokens, icon-tile pattern, component + empty-state specs, app-shell spec,
  migration checklist). Codifies the icon-tile treatment (icons on a soft colored
  background) for stat/status icons and reserves initial-avatars for people only.
- CLAUDE.md: point to design.md and record the casadesign commit/push-per-checkpoint
  workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New Tailwind-only layout: left sidebar with Pundit-guarded nav mirroring the
existing routes, plus a top bar (notifications, profile menu, sign out). Coexists
with the Bootstrap `application` layout — redesigned authenticated pages opt in via
`layout "casa_app"`. Icons via Bootstrap Icons CDN + Figtree (per design.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Supervisors now land on a real dashboard (DashboardController#show renders it in the
casa_app shell) instead of the Bootstrap volunteers table:

- SupervisorDashboard service builds per-volunteer follow-up status + summary stats
  from the supervisor's assigned volunteers.
- View: KPI cards, a "Needs your attention" list (icon-tile treatment per design
  feedback — replaces the ringed avatars), and a roster with color-coded
  contact-status pills.
- Empty states handled: no volunteers -> welcome + CTAs; nobody behind -> all
  caught up. The full volunteer management table remains at /volunteers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feedback from design review:
- Avatar initials strip honorific prefixes (Mrs./Mr./…) and use first + last name
  only, via a shared `avatar_initials` helper (removed the duplicate in the service).
- Top-bar profile menu is triggered by the avatar alone; the name lives in the
  dropdown, not the trigger.
- Page header is the page name ("Dashboard") + <title>, not a greeting.

Accessibility (WCAG AA targets):
- Skip-to-content link, landmark labels, aria-labels on icon-only controls,
  aria-current on the active nav item, table scope + sr-only caption, visible
  focus rings, contrast bumps (slate-400 -> 500/600), role=status/alert on flash.

Responsive:
- Sidebar becomes an off-canvas drawer below lg with an accessible toggle
  (button + aria-expanded, Escape/backdrop to close) and a responsive grid/padding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Names now render as first + last only (no Mr./Mrs./...) wherever a person is shown
in the redesign — the shell sidebar/profile menu and the supervisor dashboard
(names and aria-labels), plus the avatar initials.

- New `NamePresentation.strip_honorific` + a `display_person(user)` view helper.
- Presentation-only: the stored `display_name` is left untouched. (An attempted
  `User#display_name` override was reverted — a security spec requires display_name
  to round-trip raw input unchanged, e.g. dangerous strings.)
- Documented in design.md + CLAUDE.md so it's applied on every page going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bottom-of-sidebar user block (avatar + name + role) duplicated the identity
already shown by the top-right avatar account menu, and was non-interactive. Drop
it; the top-right menu is the single source for identity + account actions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "CV" placeholder brand mark wasn't a value-add at 36px (the org name already
identifies the chapter) and using the real org logo there would add image/variant
infrastructure for little gain. Show the org name alone in the sidebar header; the
full logo stays for contexts with room (sign-in, court reports). design.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the rest of the auth flow in line with the redesigned sign-in:
- Forgot password (passwords/new), reset password (passwords/edit), and
  accept-invitation (invitations/edit) rebuilt in Tailwind, matching the sign-in's
  inputs/buttons/error styling. CASA's email-or-phone reset is preserved.
- Users::PasswordsController uses `layout "casa_auth"`; the invitation-accept action
  renders in casa_auth (admin invite `new`/`create` untouched).
- casa_auth `<title>` is now driven by `content_for(:page_title)`; each page sets its
  own title (Sign in / Reset your password / Choose a new password / Accept your invitation).

Verified all three render 200 in the new layout (accept-invitation via a valid token).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply the honorific-free naming rule to the existing Bootstrap UI, not just the
redesign:
- 37 `.display_name` person-name sites across ~20 legacy views now render via the
  `formatted_name` helper (org names, form-value symbols, and the checkbox-id slug
  line were intentionally excluded).
- The 4 DataTables (volunteer, supervisor, case-contact, reimbursement) strip
  honorifics on their Ruby name outputs (display_name + supervisor_name); SQL
  select/order strings are untouched.
- Added a `formatted_name(name)` string helper alongside `display_person`, both
  backed by `NamePresentation`.

Verified /supervisors, /volunteers, /casa_cases render 200 with zero honorifics;
datatable classes load clean; standardrb + rendering green. Docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The header helper text becomes a short single sentence with no em-dash; the org
name already appears in the sidebar header, so it's no longer repeated here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added dependencies Touches dependency files javascript Touches JavaScript code ruby Touches Ruby code erb Touches ERB templates labels Jul 9, 2026
@giacoelho
giacoelho marked this pull request as draft July 9, 2026 23:01
gia and others added 3 commits July 10, 2026 15:34
DashboardController#show now renders the casadesign supervisor dashboard
(SupervisorDashboard + casa_app layout) for supervisors, but the request
spec still asserted the old redirect to the volunteers overview and was
failing on the branch. Assert the dashboard renders and lists an assigned
volunteer instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…app shell

First page-by-page migration off the legacy Bootstrap UI, following design.md.
The notifications page is linked straight from the new shell (top-bar bell +
account menu), so it was the most visible remaining Bootstrap seam.

- Render NotificationsController#index in the casa_app layout.
- Restyle the index, NotificationComponent, and patch-notes partial onto the
  design system: card list, leading icon tiles, unread dot, and a cold-start
  empty state. Switch Font Awesome (fas fa-*) to Bootstrap Icons (bi-*), which
  is the icon set actually loaded on Tailwind pages.
- Move the specs off Bootstrap-class selectors onto semantic data-* hooks
  (data-notification-list-item, data-read / data-unread-dot) without weakening
  behavior coverage. All notification/patch-note ordering, counts, and empty
  states remain asserted.

Verified: component, view, request (renders the full casa_app layout), and
system specs all pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… backlog

- design.md: reframe as the permanent source of truth to refer to for all UI
  work. Add a "Design decisions (rationale)" log capturing the why behind the
  system (Tailwind-alongside-Bootstrap, layout opt-in, indigo/slate, Figtree,
  bi-* icons, icon-tile-vs-avatar, org-name-only sidebar, presentation-only
  honorific stripping, triage dashboards, empty-state taxonomy, a11y bar,
  build/output), a repeatable "Migrating a page" playbook, and a migration
  status that points at the backlog.
- design-todo.md: new prioritized, phased backlog (the "what's left") for the
  page-by-page migration off Bootstrap, plus cross-cutting infra and known
  pre-existing debt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the 🧪 Tests Tests label Jul 10, 2026
gia and others added 6 commits July 10, 2026 15:54
Second app-shell leaf page (linked from the account menu). Rebuilds the whole
edit-profile screen on the design system while preserving every behavior.

- Render UsersController in the casa_app layout.
- Rewrite edit.html.erb into cards: details, account, security, communication
  preferences, plus the volunteer languages table — using the documented input,
  button, and checkbox patterns.
- Replace the Bootstrap collapse accordions (Change Password / Change Email)
  with a small `disclosure` Stimulus controller (real <button> trigger, toggles
  a hidden panel, syncs aria-expanded) instead of relying on Bootstrap JS.
- Add a reusable Tailwind `shared/_form_errors` partial (the legacy
  `shared/_error_messages` stays for Bootstrap pages); it keeps the
  `@custom_error_header` hook so "... this password change ..." still renders.
- Preserve all field labels, ids, and JS-hook classes
  (toggle-email/sms-notifications, save-preference, password-new/-confirmation,
  submit-password, current_password_email, toggle-sms-notification-event) so
  require_communication_preference.js and password_confirmation.js keep working.

Verified: users request spec + the full edit system spec pass (79 examples);
erb-lint, standardrb, and StandardJS clean; JS bundle builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rofile done

Add the two components introduced by the edit-profile migration (the Tailwind
form-error summary and the disclosure/collapsible-panel pattern) to design.md,
and tick edit profile in both the design.md status and design-todo.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rd subtitle

- Add a role badge (current_role as a brand-tinted pill) to the casa_app account
  menu header, under name + email — the one place identity metadata lives, and a
  parity with the role line the legacy header used to show. Industry-standard
  placement for a multi-role internal tool (keeps the sidebar/top-bar chrome clean).
- Supervisor dashboard subtitle -> "Track volunteer progress at a glance."
- Document the role badge in design.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The person-badge icon added no signal, so remove it. Colour the pill by role
using the design system's non-semantic accent tints — Volunteer = sky (blue),
Supervisor = violet (purple), Casa Admin = amber — so roles read apart at a
glance; unknown roles fall back to slate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pt WCAG AA

- Drop the shouty `uppercase` transform from all design-system labels (account
  details, dashboard + languages table headers, patch-note category, auth "or"
  divider); render them sentence case. Sentence-case isolated copy ("My
  languages", "Learning hours this year").
- Bump muted label text from slate-400 (fails AA) to slate-500/600 for contrast.
- Redesign the form-error summary (shared/_form_errors): a role="alert" card with
  a leading icon and a tidy bulleted list instead of the plain block; keeps the
  heading text + #error_explanation so specs and behavior are unchanged.
- design.md: add Sentence case + Accessibility (WCAG 2.1 AA) as standing
  conventions, and fix the muted-text token. design-todo: track the app-wide
  interactive-label sentence-case pass and a slate-400 contrast audit.

Interactive button/field labels shared across pages (Update Profile, Change
Password, field labels) are spec-coupled across users/volunteers/all-casa-admin
and a shared example, so they're deferred to a holistic pass (tracked).

Verified: 109 examples across the touched pages pass; erb-lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per design feedback: one sentence, no bullets, dashboard-style icon tile.
- shared/_form_errors now renders "Unable to save: <messages via to_sentence>"
  inside a rose danger icon tile (bg-rose-100 text-rose-600, bi-exclamation-
  triangle) matching the dashboard, dropping the old heading + bulleted list.
- Update edit_spec assertions from the Rails "N errors prohibited this X from
  being saved:" text to "Unable to save".
- design.md: refresh the Form errors component note.

Verified: 79 users edit + request examples pass; erb-lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gia added 14 commits July 14, 2026 14:59
White text on emerald-600 was 3.77:1 (fails AA for text); emerald-700 is
5.48:1. Bumped the resolve-reminder button background to emerald-700
(hover emerald-800). Measured with the WCAG contrast formula.
design-todo.md: mark Case show migrated (approach, infra added, and the
follow-up to consolidate the show-specific contact card / reminder form when
the contacts index and volunteers-edit migrate); note the now-orphaned
_generate_report_modal in the dead-code cleanup item.
design.md: add the Modal (native dialog) component pattern.
Case groups (index, form, controller) move to the casa_app Tailwind layout,
with a TomSelect theme so the multiselect matches the design system on casa_app.

Establish two shared tokens so styling stops drifting:

- button_classes(:primary | :secondary | :danger) in DesignSystemHelper is the
  single source of truth for buttons, replacing five copy-pasted class locals.
  Every variant shares a fixed h-10 (40px) height, so box-sizing: border-box
  absorbs the outlined variant's 1px border and all variants are the same height
  by construction, with no fragile border border-transparent compensation.

- One native-<dialog> modal template: header (optional 32px status badge, title,
  close), divider, body, divider, right-aligned footer. The delete confirm
  (shared/_confirm_button), the court-report modal, and the success dialog now
  share it. The status icon is one rounded-full badge in two sizes (32px inline,
  48px hero). tailwind.css re-centers the dialog because Tailwind's reset drops
  the browser's centering margin.

WCAG: the modal close icon moves from slate-400 (2.56:1) to slate-500 (4.76:1).

Specs: a DesignSystemHelper#button_classes unit spec and a case-groups
delete-via-confirmation-dialog system test. design.md documents both tokens.
The court-report, success, and delete-confirm modals were three copies of the
same inline <dialog> markup: the same drift the button token just fixed. Fold
the template into a Dialog:: ViewComponent suite (the native-dialog counterpart
to the Bootstrap Modal:: suite):

- Dialog::GroupComponent: the <dialog> shell (trigger slot, size, aria label,
  modal controller wiring, extra controllers, open-on-connect, extra data).
- Dialog::HeaderComponent: optional status badge, title, and close button.
- Dialog::BodyComponent: panel or centered status body, with extra classes.
- Dialog::FooterComponent: a divided action row, end- or center-aligned.

Header/body/footer render as standalone components so they compose even when a
form_with wraps them (the court-report modal). shared/_confirm_button and the
two case-show modals now use the suite; markup and geometry are unchanged
(verified centered, 40px buttons, 32px badges). Specs cover all four components,
and design.md documents the suite.
The case-show header was a flat row of up to five buttons. Adopt the cases
index's header pattern: one primary CTA plus a More overflow menu.

- New Case Contact (primary), Edit Case Details, and Emancipation (when the
  youth is transition-aged) stay visible; Generate Court Report and New Fund
  Request move into a More disclosure (native <details> + the dropdown
  controller), matching the index.
- Core actions stay visible on purpose: burying Edit or Emancipation would cost
  a click on common actions and break non-JS specs, since rack_test cannot open
  a native <details>.
- Dialog::GroupComponent gains a wrapper_class option; "contents" lets the
  court-report modal's trigger and dialog drop straight into the menu as an
  item. The report modal is extracted to casa_cases/_court_report_modal.
- Menu-item leading icons top-align to the first line (items-start).
- The index's More summary now uses button_classes(:secondary), matching the
  40px primary and fixing a height mismatch introduced by the button token.

design.md and CLAUDE.md document the header pattern and the icon alignment.
The header keeps New Case Contact (primary) and Edit Case Details visible and
now overflows Generate Court Report, Emancipation, and New Fund Request into the
More menu.

The emancipation-link check becomes :js and opens More first, since the link now
lives in the native <details> menu. design.md updated to match.
On phones the header wrapped into a messy multi-row of buttons. Now only the
primary CTA and More share the top line; Edit collapses into More below sm.

Edit renders twice with responsive visibility: a button wrapped in
hidden sm:contents (sm+) and a sm:hidden menu item (mobile). It stays no-JS,
is unambiguous (one visible Edit at any width), and the non-JS Edit test still
finds the visible button. design.md and CLAUDE.md document the pattern.
casa_cases#new and create now render on casa_app with a Tailwind form:

- Two-column responsive grid: case number and contact types span full width;
  dates, court report status, and assign volunteer take one column each. A single
  bottom "Create case" submit (no top CTA), and the design-system select pattern
  (appearance-none + chevron), with month/year pickers via
  casa_cases/_month_year_select.
- Contact-types multiselect themed for casa_app: a chevron, brand-100 chips each
  with a visible x (the LineIcons x and grey divider are overridden), flip-up when
  the control is near the viewport bottom (multiple-select controller), and the
  "select all" sentinel chip and the always-"never" last-used subtext hidden on a
  new case.
- Validation: invalid fields get a rose-500 border (.field_with_errors) alongside
  the shared/_form_errors summary card.
- Volunteer options are honorific-free.

edit and the shared _form stay on Bootstrap until Stage 2. design.md documents
the form-layout, select, multiselect, and validation patterns; CLAUDE.md records
that approved components are documented in design.md and reused from there.
- New/edit forms: lift the "Court details" section heading and the case
  number out of the uniform-gap grid so the heading hugs its fields (12px)
  instead of floating with the 20px inter-field gap.
- Volunteers: replace the shared Bootstrap manage_volunteers table with a
  self-contained Tailwind card list, design-system status pills
  (Assigned/Unassigned/Deactivated, all AA), and a themed assign form.
- Court orders + court dates: casa_app-specific Tailwind partials
  (shared/court_order_list stays for the Bootstrap court-date pages),
  preserving the nested-form, copy-from-sibling, and add/remove hooks.
- Deactivate moves to a Dialog confirm in its own danger zone outside the
  edit form; inactive case gets a Tailwind view.

edit_spec 46/46 green; mobile has no horizontal overflow; contrast is AA.
design.md and CLAUDE.md updated with the new patterns.
The court-orders sub-form now confirms removing a persisted order through
the design-system native <dialog> (opened programmatically by the
court-order-form controller, centered by the modal controller) instead of
SweetAlert. New unsaved rows still remove without a prompt; copy-from-sibling
keeps its own confirm for now.

edit_spec 46/46 green. design.md documents the programmatic-open pattern.
The casa_app copy-from-sibling flow is now a small copy-court-orders Stimulus
controller: it enables the button once a case is picked, confirms through the
design-system <dialog>, PATCHes copy_court_orders, and reloads. The action sets a
flash so the "Court orders have been copied" message survives the reload. The
legacy casa_case.js SweetAlert and the shared Bootstrap partial are left untouched
for the court-date pages.

edit_spec 46/46 green (aside from one pre-existing flaky volunteer :js test that
passes in isolation). design.md updated.
- Send Reminder now uses button_classes(:secondary) so it matches Add a court
  date; it was a hand-written brand-outline string at a smaller height.
- Youth's date in care no longer reads light-dark-light: the derived duration
  moves to a muted second line and is reworded from "(over 8 years ago)" to
  "In care for over 8 years" so its meaning is clear.

show, show_more, new, and edit specs green.
- Send Reminder is now a Dialog confirm (the Send CC option lives inside it)
  and returns to the case after sending, not the volunteer edit page.
- Convert every remaining hand-rolled button on the case pages to
  button_classes: Reactivate, Filter, case-contact Edit/Delete, and the
  followup Make/Resolve Reminder. Add a :success variant (emerald-700, AA)
  for Resolve.
- Court Report Status derived info moves to a muted second line (same fix as
  date-in-care) so it no longer reads light-dark-light.
- design.md and CLAUDE.md document the two new variants and a pre-ship audit
  step to catch hand-written button styling.

show, show_more, followups, and case-contact specs green.
…pography

- Drop the trailing colons and Title Case from section subtitles: "Assigned
  Volunteers:" -> "Assigned volunteers", "Current Placement:" -> "Current
  placement", "Court Orders" -> "Court orders". Colons stay only on inline
  key:value fact labels.
- Volunteer name is now dark identifying text (slate-800, hover underline)
  instead of a brand hyperlink, so it reads as a name, not a nav link.
- Current placement value uses the same slate-800 as other fact values; the
  grey "Unknown" is the muted empty-state convention, kept.
- design.md + CLAUDE.md: no-colon-on-headings rule (with an audit grep) and a
  person-name typography/link convention.

show and show_more specs green.
gia and others added 15 commits July 15, 2026 18:23
Clicking a volunteer's name from a case now carries from_case_id, and the
volunteer edit page shows a "Back to case <number>" link (org-scoped) so the
user can return instead of being stranded on an un-migrated page. The name
links (case show and the edit-page volunteer table) also adopt the design-system
name treatment (dark slate-800, hover underline) rather than a brand hyperlink.

show, show_more, and edit specs green.
- The contact-types multiselect now loads blank with a "Select or search contact
  types" placeholder instead of pre-selecting every option; the dropdown's
  Select/Unselect all still selects everything. Contact types is required (an
  at-least-one validation), so blank plus placeholder is the correct required-field UX.
- The dropdown chevron is now the real bi-chevron-down icon injected by the
  controller, matching the single-selects. The previous CSS ::after content glyph
  was silently dropped by the CSS minifier, which is why the chevron looked missing
  despite the rule being present.
- design.md and CLAUDE.md document both (blank-by-default multiselect, injected chevron).

new and edit specs green.
The chevron was rendering all along but painted behind TomSelect's opaque
.ts-control, so it needed z-index. Root-caused by pixel inspection (computed
style reported the element present while nothing actually painted, which is why
every prior attempt looked done but showed nothing).

The chevron is now a base64-SVG caret on .ts-wrapper::after with z-index: 2. A
CSS content-glyph escape and a raw (non-base64) data URI both broke in the CSS
build, and the injected icon-font element never painted; base64 + z-index is
robust. Reverted the JS icon injection. Verified at the pixel level (darkest
pixel 0.45 = slate-500). new and edit specs green.
The contact-types chevron now uses the exact Bootstrap-Icons chevron-down shape
as a base64 SVG, sized (text-xs) and placed (right-3) like the single-selects.
Pixel-verified: both chevrons have an identical 8x4px dark extent.

design.md and CLAUDE.md: the multiselect chevron matches the single-selects, and
before finishing a component, check it against design.md and its siblings and
pixel-verify the match, not just that it renders.
… case

The app-shipped default contact types (ContactTypeGroup::DEFAULT_CONTACT_TYPE_GROUPS),
which render as the multiselect chips, are now sentence case, keeping the proper
nouns/acronyms CASA and IEP. design.md and CLAUDE.md now record that sentence case
covers app-shipped content (seed defaults and constants), not just view copy, so
scan those before finishing; never force-case free-form org data.

Existing orgs keep their data; re-seed to see the new defaults in dev.
- design-todo.md: save the scoped volunteer edit page migration plan at the top
  (resume-here) and check off the CaseContact occurred_at flake (already a lambda).
- Delete the orphaned casa_cases/_generate_report_modal (Case show uses the Dialog
  report modal; the live report generation lives in case_court_reports / reports).
The cases filter chevron/search/clear icons and the index/show menu leading icons
were slate-400 (2.56:1, below the 3:1 UI floor and against design.md's slate-500
chevron rule). Now slate-500 (4.76:1). Decorative empty-state / notification icon
tiles left as-is.
Rebuild the volunteer edit page as one self-contained Tailwind view on
`layout: "casa_app"` (@active_nav "volunteers"); the shared Bootstrap
user-edit partials stay for the supervisor/admin edit pages. Sections:
identity header + Impersonate, an inline reminder card, Profile (two-column
grid, editable vs read-only per update_user_setting?), Account (metadata dl),
Status/activation, Cases (card list), Supervisor, and Notes (md+ table with a
mobile card twin). Rebuilt volunteers/_manage_active, _manage_cases,
_manage_supervisor, _notes and _volunteer_reminder_form as casa_app twins and
folded in _send_reminder_button.

Also lands two app-shell items this migration surfaced:
- casa_app impersonation banner (layouts/_impersonation_banner), fixing the two
  impersonation examples red since the volunteer dashboard moved to casa_app.
- flash parity: the casa_app flash strip carries the flash key as a class
  (.notice/.alert) alongside role=status/alert.

Deactivate keeps the UJS data-confirm (the :js spec drives accept_confirm).
Spec-locked Title Case action labels kept verbatim (queued for the sentence-case
sweep). All 745 volunteer-edit system examples green, plus the view + request
specs; no overflow 375-1280; select chevron darkest-pixel verified (slate-500).
Updated the three specs coupled to the old page title/flash, and documented the
Person edit page pattern + impersonation banner + flash parity in
design.md/design-todo.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuild the volunteers roster on the casa_app shell as a bespoke Tailwind table,
retiring the jQuery DataTable. Server-side filters (status, supervisor, transition-aged,
extra languages), search, sortable headers, and Pagy pagination reuse VolunteerDatatable's
SQL via new #index_relation / #index_count (the controller maps plain GET filters into the
DataTables param shape; the count strips the custom SELECT/ORDER aliases and counts
DISTINCT users.id). Responsive: desktop table (scrolls within its card) + a mobile card
twin; emoji columns become pills/text; names are honorific-free.

Bulk supervisor assignment is preserved — select-all + a native-dialog modal + the
disable-form-gated Confirm — with checkboxes in the desktop table only so the select-all
counts and #id lookups stay unambiguous. The Manage trigger toggles `hidden!` (Tailwind v4
important) because a plain `hidden` loses to button_classes' `inline-flex`.

The column-visibility picker is dropped (design.md — a responsive layout beats a picker).
The legacy DataTable is retired by moving the #volunteers hook off the <table> onto its
wrapper, so dashboard.js's $('table#volunteers').DataTable() no longer matches (it otherwise
re-inits a serverSide table whose undefined ajax.url POSTs to the index). The now-unused
datatable JSON action + dashboard.js volunteer block are dead (queued for cleanup).

Rewrote the 435-line DataTables-coupled spec (259 lines) for the server-side behavior:
listing/nav/filtering/search/empty-state (non-JS) plus auto-submit and the full bulk flow
(:js). Verified WCAG AA, chevrons darkest-pixel-checked (slate-500), and no page overflow
375-1280. Documented the DataTable-retirement and bulk-roster patterns in design.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Index: bespoke Tailwind roster + "volunteers without supervisors" + "CASA
cases without court dates", with a server-side status filter (auto-submit).
Retires the serverSide DataTable by moving #supervisors off the <table>
onto its wrapper (dashboard.js no longer re-inits over the markup).
Per-supervisor contact stats become labeled pills (color + icon + word:
attempting / not attempting / transition-aged, or "No assigned
volunteers") instead of a color-only bar chart; the transition-aged column
is a Yes/No pill, not the butterfly/caterpillar emoji; and the always-blank
Hearing type / Judge columns are dropped (court-date-less cases never have
them).

Edit: self-contained casa_app column (Profile / Account / Status /
Volunteers). supervisors/_manage_active is now Tailwind, and a new
supervisors/_manage_volunteers twin replaces the shared Bootstrap
manage_volunteers; the shared _edit_form / _invite_login stay for the
casa_admin edit page (rebuilt inline here). "Edit supervisor" heading;
Deactivate keeps the UJS data-confirm the :js spec drives with
accept_confirm/dismiss_confirm.

Both view + system specs rewritten to semantic hooks ([data-stat],
.supervisor-filters, [data-test=cases-without-court-dates]). Chevrons
darkest-pixel verified (114 = slate-500); no overflow 375-1280; standardrb
+ erb_lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The casa_app top-bar account/notification dropdowns are absolute panels
inside the <header>, and relied on the header's backdrop-blur stacking
context to sit above page content. That's fragile: any page element with
its own stacking context (a positioned z-* toolbar, a transform/hover-lift
card, a native control) ties the header and wins by DOM order — painting a
page button (e.g. the "New Supervisor" CTA) over the open dropdown.

Give the header `relative z-[25]`: above all page content (which tops out
at z-20) yet below the mobile nav scrim (z-30, so the open drawer still
dims the header), the sidebar drawer (z-40), and native <dialog> modals
(top layer). Reproduced and verified with elementFromPoint probes at 1018
and 375px (dropdown now fully on top; mobile drawer + scrim unchanged).
Documented the shell stacking order in design.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
index / show / new / edit + LearningHours::Volunteers#show now render on
layout: "casa_app" (@active_nav "learning").

- Volunteer index: a bespoke Tailwind entries table (desktop table + mobile
  card twin), reused by the supervisor/admin volunteers#show.
- Supervisor/admin index: a per-volunteer YTD-total roster, server-rendered
  + Pagy paginated, retiring the client-side DataTable (dropped the
  table#learning-hours id learning_hours.js targets; initializeDataTable
  no-ops on the empty selector).
- new/edit form: Tailwind, with the Hour(s)/Minute(s) inputs rebuilt as a
  twin of Form::HourMinuteDurationComponent (left untouched — still used by
  the Bootstrap case-contacts form); native-select chevrons; form_errors
  summary. Duration fields default to 0 so leaving one blank submits 0.
- show: a fact card + Edit/Delete.

Column headers sentence-cased; system + request specs updated to match, and
the DataTables Previous/Next pagination test replaced with the Pagy summary.
Chevrons darkest-pixel verified (114 = slate-500); no overflow 375-1280;
standardrb + erb_lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
volunteers#new and supervisors#new now render on layout: "casa_app"
(@active_nav volunteers/supervisors), rebuilt as self-contained Tailwind
invite forms (email, display name, phone [+ date of birth for volunteers])
using shared/_form_errors. Dropped the single-use volunteers/_form; fixed
the supervisor create-failure render (render new_supervisor_path -> :new).

Also fixes the shared not-authorized flash on casa_app: the handler ships
"Sorry, you are not authorized..." as flash[:notice] (locked by ~dozens of
request specs, so the key can't change), and the old Bootstrap layout gave
every flash a base .alert class (flash_class). The casa_app flash strip now
does the same (base `alert` + the flash key), so the .alert not-authorized
redirect specs (new volunteer, new supervisor, invite, imports) pass while
.notice parity holds.

Specs: updated the supervisor invalid-submission error-summary text
(shared/_form_errors -> "Unable to save") and the volunteers/index "New
volunteer" heading. No overflow 375-1280; standardrb + erb_lint clean. The
5 accepting-invitation failures in invite_spec are pre-existing (casa_auth
accept-page spec drift), unrelated to these pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The invitation-accept page (devise/invitations/edit) was migrated to
casa_auth ("Set your password" / "Confirm password" / "Activate account"),
but invite_spec still asserted the old Devise defaults ("Set my password" /
"Password confirmation"), leaving 5 red examples. Point the locators at the
shipped page; the Devise error assertions are unchanged (they use the
password_confirmation attribute's humanized name). Dropped the brittle
post-accept landing-text check — the .notice success flash + accepted-at
timestamp already verify the accept + sign-in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Touches dependency files erb Touches ERB templates javascript Touches JavaScript code ruby Touches Ruby code 🧪 Tests Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant