Casadesign - DRAFT DO NOT MERGE#7051
Draft
giacoelho wants to merge 259 commits into
Draft
Conversation
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>
giacoelho
requested review from
FireLemons,
compwron and
elasticspoon
as code owners
July 9, 2026 23:01
giacoelho
marked this pull request as draft
July 9, 2026 23:01
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>
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>
Volunteers with 2+ active cases now land on a triage dashboard instead of the Bootstrap cases index; the single-active-case fast-path to "log a contact" is unchanged. - VolunteerDashboard service + dashboard/volunteer.html.erb: KPIs (active cases, cases needing a contact in 14+ days, hours logged 30d), a "needs your attention" list, and a "your cases" table with status pills + "log a contact" CTAs. Per-case last-contact is batched into one query. - Shell parity: render org announcement banners in the casa_app shell (layouts/_casa_banner), and make the dismiss controller also add Tailwind's `hidden` class so the banner hides in both layouts. - Specs: volunteer dashboard now renders (not redirects) in the request spec; re-point the legacy sidebar-dropdown navigation in the case_contacts and other_duties system specs to visit paths directly, since those dropdowns aren't in the new shell. Verified: affected request + system specs pass in deterministic order; erb-lint, standardrb, StandardJS clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Admins now land on an org triage dashboard instead of redirecting to the supervisors page. - AdminDashboard service + dashboard/admin.html.erb: chapter KPIs (active volunteers, active cases, unassigned cases, cases needing a contact) and a "needs your attention" list of unassigned active cases each with an "assign a volunteer" CTA; a cold-start state for brand-new chapters. Queries are aggregate/batched (active cases + one grouped contact lookup + counts) to stay cheap at org scale — no per-case/per-volunteer queries. - dashboard request spec: admin renders the dashboard (not a redirect). Verified: dashboard request spec + the admin visit-root system specs (banners/new, casa_cases/new, court_dates/edit) pass; erb-lint + standardrb clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The last row butted against the card's rounded bottom corner (unlike the top, which the header border defines). Add pb-2 to the card so the final row clears the corner, keeping every row a uniform height rather than singling out the last one. Documented the table-in-card pattern in design.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orners Same treatment as the dashboard tables. The notifications list has no header, so its first and last rows both butt against the card's rounded corners — add py-2 (both sides) so they clear. Generalized the table-in-card note in design.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…wind skin Phase 3 groundwork. Rather than reimplement the server-side DataTables (search, sort, paginate, filters, state save, column toggles), skin them: add a DataTables Tailwind layer to tailwind.css that restyles the generated chrome (search box, page-length select, info text, pagination) and the table shell. Because tailwind.css only loads on the casadesign shell, the skin can't touch the legacy Bootstrap tables. Documented the decision + a Data tables component note in design.md, and the per-page plan in design-todo: cases index first (ERB-rendered rows, most tractable); server-side tables additionally need the dashboard.js columns.render output moved from Bootstrap markup + lni icons to Tailwind + bi-*. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First Phase 3 datatable page. The cases index (volunteer "My Cases" + admin / supervisor roster) now renders on the casa_app shell. - Rebuild the view + table in Tailwind; the DataTables skin styles the search/pagination chrome. Render in casa_app with @active_nav = "cases". - Replace the Bootstrap dropdown filters + column-picker modal with `dropdown` popovers (new Stimulus controller: toggle + close on outside-click/Escape), preserving every JS hook (.casa-case-filters, .status-options, #visibleColumns, .toggle-visibility, data-value/data-column) so dashboard.js filtering + column toggles keep working. The column picker stays outside .casa-case-filters so the filter-redraw handler doesn't bind to it. - Skin: pad the DataTables controls to line up with px-4 cells. - Action-button + column-header labels stay Title Case (spec-coupled across the new-case / case-group / bulk-court-date flows) — sentence-casing those belongs to the tracked interactive-label pass. Verified: casa_cases/index (filters + links), dashboard/show (volunteer + admin), casa_cases request spec, additional_index, casa_cases/new, case_groups all pass. bulk_court_dates/new is a pre-existing flake (fails on the clean branch too). erb-lint + StandardJS clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ataTables) Reverses the "theme jQuery DataTables" approach — theming couldn't match the dashboard tables or meet WCAG (its generated chrome fights the design system). The cases index is now a hand-built Tailwind table matching the dashboard, with server-side filtering + Pagy pagination. - Controller: server-side filters (status [default active], assignment, transition-aged, prefix) + Pagy; drop the client-side DataTables path. - View: bespoke table (readable headers, empty-state row, card + inset), a clear filter bar of selects that submit on change (new auto-submit Stimulus controller), and a reusable shared/_pagination partial (Pagy -> "Showing X-Y of Z" + page controls; WCAG nav/aria-current/rel). Consistent action buttons. - Remove the now-dead DataTables Tailwind skin and the dropdown controller (its popover filters are replaced by selects). - Rewrite the coupled specs (index + additional_index) for server-side filtering. - design.md / design-todo: reverse the decision; document bespoke tables + pagination as the pattern. Dropped for v1 (follow-ups): column-visibility picker, sortable headers. Action / header labels stay Title Case (spec-coupled). Verified: cases index / additional_index / request specs, dashboard/show, and the new-case + case-group nav flows all pass; erb-lint, standardrb, StandardJS clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ransition Review feedback on the cases index: - Filter selects: `appearance-none` + a positioned `bi-chevron-down` so the dropdown chevron has proper right padding (was the cramped native arrow). - Row action: the stranded far-right "Edit" text link is now a compact right-aligned pencil icon button (aria-labelled), matching the dashboard roster. - Transition Aged Youth: drop the whimsical 🦋/🐛 emoji (butterfly = aged, caterpillar = not) for a clean indicator — a violet "Yes" pill / muted "No". Scoped to the new UI; the shared decorator keeps the emoji on unmigrated legacy pages. Documented in design.md. - Blank hearing-type / judge cells show a muted em-dash instead of empty. Verified: cases index / additional_index / dashboard-show specs pass; erb-lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An icon-only pencil wasn't clear enough. Restore a visible "Edit" label as a
compact bordered button; keep the per-row aria-label ("Edit <case number>") so
the accessible name stays unique and descriptive (WCAG 2.4.4 / 2.5.3).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e migration map The footer partials (layouts/footers/_logged_in + _not_logged_in) render in no layout -- only spec/views/layouts/footer.html.erb_spec.rb exercised them. Deleted all three. Their links (Ruby For Good / Report a site issue / SMS Terms & Conditions) survive on the all_casa_admin layout footer + the static landing; casa_app itself has no footer (a pre-existing gap, noted in the map). Also corrected the map's emancipation note: _emancipation_link is rendered by CasaCaseDecorator#transition_aged_youth, which no view calls (only the decorator spec) -- the migrated cases index built its own Yes/No transition column and dropped the quick-link. So it's dead code, not a live element; left pending a delete-vs-re-add decision rather than migrating styling no one sees. Decorator + cases-index specs 18/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d but unreachable) Reported as a serious miss: admin / mileage rates / banners / imports appeared "missing". They were migrated (Tailwind, casa_app) but linked NOWHERE in the casa_app nav -- reachable only by typing the URL. A full reachability sweep confirmed 6 orphaned pages; this wires the 4 admin ones into a new "Administration" section on the Settings page (Settings is admin-only, so no per-link gating needed). Verified: the 4 links render and /casa_admins, /mileage_rates, /banners, /imports all return 200. MIGRATION-MAP.md corrected: my earlier "all migrated" claim checked Tailwind-on-a-shell, not navigability -- that was the real miss. Remaining orphans recorded: other_duties (conditional volunteer feature) and emancipation_checklists#index (index-only), placement TBD. casa_org/edit spec: only the pre-existing Twilio :63 flake fails (unrelated, parked); the additive section broke nothing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pation checklists) -- 0 orphans left Closes out the reachability sweep from the previous commit. other_duties: now a sidebar item (gated by policy(OtherDuty).index?, which already includes the org's other_duties_enabled toggle) + @active_nav in the controller so the sidebar highlights. emancipation_checklists#index: a volunteer-only link in the Cases page header (see_emancipation_checklist? is volunteers-only, so it can't live in the admin/supervisor More menu). Verified role-gated: admin sees "Other duties" in the sidebar but not the volunteer-only emancipation link (/other_duties 200); volunteer sees both, and /emancipation_checklists reaches the page (302 -> redirect to their single transitioning case, per the controller). other_duties + cases-index specs 4/0. All 6 orphaned pages are now linked; MIGRATION-MAP.md updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…is the point) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The three dashboards had a title+subtitle header but used items-end, so the CTA aligned to the subtitle's bottom and sat noticeably lower than on other pages. They also hand-rolled the button (px-4 py-2.5) instead of the button_classes token, so the CTA was a different height than the 40px token used on volunteers/supervisors/cases. - header rows: items-end -> items-start, matching the subtitle-header pattern already used by reimbursements/placements/banners (the CTA top-aligns with the h1, so the subtitle no longer pushes it down) - header + empty-state CTAs: hand-rolled strings -> button_classes(:primary/:secondary) Verified via getBoundingClientRect: the dashboard header CTA now measures ctaTop==h1Top (0) at 40px, identical to reimbursements. Compact per-row card buttons (px-3 py-1.5) intentionally left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/ghost_class
Follow-up to the dashboard header fix: swept the app for hand-rolled button
strings (design.md's single-source-of-truth rule) and converted the stragglers.
grep now finds zero hand-rolled button shapes app-wide.
- auth submits (6 devise + 2 all-CASA): full-width hand-rolled -> "#{button_classes(:primary)} w-full"
(login label pixel-verified centered, 40px, full form width)
- dashboard "Needs attention" per-row actions (Assign a volunteer / Log a contact /
Send reminder): compact hand-rolled secondary -> ghost_class, per the documented
"every repeated row action is the ghost, never a button_classes CTA" rule; the
supervisor card's Send reminder + View are now both ghost
- users/_languages "Add" -> button_classes(:primary)
- users/edit "Deactivate" -> button_classes(:danger_outline) (was a hand-rolled
danger-outline; now matches the adjacent Update-profile at 40px)
- design.md: document the page-header alignment rule (h1-only -> items-end;
subtitle -> items-start so the CTA top-aligns to the title, not the subtitle)
Specs green: devise/auth view specs + dashboard/login/all-CASA-login/password/
languages system specs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…endar" button Two case-show defects the button/emoji sweeps could not catch (neither is a hand-rolled Tailwind class string): a model method emitting emoji, and a third-party web component. Court orders: CaseCourtOrder#implementation_status_symbol returned literal ✅/🕗/❌ (inconsistent across platforms, presentation in a model). Removed it; presentation now lives in court_order_status_pill/court_order_status_label helpers rendering the design.md Status pill -- Implemented (emerald), Partially implemented (amber, a new documented variant), Not implemented (rose), Not specified (slate). Add to calendar: replaced the third-party <add-to-calendar-button> web component (show) and the legacy jQuery .cal-btn div (edit) with one ghost_class "Add to calendar" button whose add-to-calendar Stimulus controller builds and downloads an .ics (works with any calendar; a repeated per-row action is a ghost, not a CTA, per design.md). Dropped src/add_to_calendar_button.js + its require; the web component is no longer bundled. design.md: documented the amber pill, the court-order pill mapping, the Add-to- calendar ghost, and extended the pre-ship audit to also scan Ruby methods that emit glyphs and non-button_classes widgets (the two blind spots here). Verified live on CINA-08-1001 (no emoji, no web component); show + court-dates system specs (52) and full JS suite (126) green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t-aligns
A leading status pill made each row's text start at a ragged x, because the badge
widths differ ("Implemented" vs "Partially implemented" vs "Not specified"). The
industry-standard fix for an item-with-status list: text in a left column
(flex-1 min-w-0), status badge right-aligned (shrink-0) forming a clean right column.
Verified live on CINA-08-1001: every row's text left edge = 313px and every pill's
right edge = 1208px; rows with wrapped 3-line text keep the text left and the pill
top-right. show_spec green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tus badge The right-floating pill hovered at the top-right of multi-line directive text (court orders are 95-266-char sentences), reading as disconnected. Converted to a compact 2-column table (Court order | Status) using the design.md table tokens: sentence-case text-xs font-semibold text-slate-600 header, align-top cells, divide-y rows, pill in a left-aligned whitespace-nowrap status column. Verified live on CINA-08-1001: header present, order column left-aligned (x=313), status pills form a clean left-aligned column (x=1075), all single-line. show_spec green (35). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The volunteers/edit reminder was a Tailwind inline form (design-system styled but not a modal), kept inline so its CC-logic system specs could run without JS. Migrated it to the design-system Dialog (mirrors the case-show reminder), grouped the "Send reminder" trigger with Impersonate in the header, and split the coverage: - system spec (:js): the modal UI (open -> role-aware CC label -> submit -> flash), 2 examples - request spec: the CC-by-role logic (supervisor/admin x with_cc + the no-supervisor case), 5 examples Keeps the CC-logic coverage fast and reliable (no :js mailer-delivery flakiness). Renamed the partial to .html.erb; fixed a stale "still Bootstrap" comment on the twin. Verified live on /volunteers/:id/edit: the trigger sits with Impersonate and opens a native <dialog> with the role-aware CC label + submit. Specs: edit_spec 37, reminder request 5, reminder :js 2 -- all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…SweetAlert2 popup The "Make reminder" button on a case-contact card opened a SweetAlert2 popup (via legacy jQuery in src/case_contact.js) instead of the design-system Dialog -- design.md line 582 already specifies the Dialog:: suite for the set-reminder note, so this was a standard violation. Replaced it with a Dialog: a "Make reminder" trigger opens a native <dialog> with an optional-note textarea + Cancel/Confirm, creating the persisted Followup exactly as before. - removed the followup Swal handler from src/case_contact.js (kept convertDateToSystemTimeZone + the filter-form handler; Swal stays for its app-wide flash-notifier / other uses) - controller: blank note -> nil via .presence (a textarea always submits "", unlike the old JS which omitted the param when empty), preserving note-nil-when-empty - followups/create_spec rewritten for the Dialog flow (open -> note -> Confirm / Cancel / Close) Where the reminder goes (unchanged): it creates a persisted Followup (status: requested, optional note), surfaced as the "Resolve reminder" button + in follow-up reports/notifications. Verified live on CINA-08-1001: Make reminder opens a native <dialog> (rounded-2xl, "Make a reminder?", note field, Cancel/Confirm), swalPresent=false. Specs: followups create+resolve (:js) 10, case_contact jest 5 -- all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndicator, email both parties Addresses the "heavy green button + what's the utility?" feedback on case-contact followups: 1. Resolve reminder: button_classes(:success) (heavy filled emerald) -> :secondary, across all three "Resolve reminder" sites. A per-row/card resolve is low-frequency; the filled emerald over-emphasized it next to the neutral Edit / Make-reminder buttons. (:success stays for prominent positive actions like Activate.) 2. On-card pending indicator: the case-show contact card now surfaces a requested follow-up as an amber alert_classes(:warning) callout (the note + who set it + when) -- the reminder's content is visible where you act, not just a swapped button. 3. Email: FollowupNotifier + FollowupResolvedNotifier now deliver_by :email (Noticed) -> UserMailer (followup_notification / followup_resolved, inline-CSS templates), and notify BOTH the volunteer (the contact's creator) and the setter; the resolve notifier skips whoever just resolved it. Gated on receive_email_notifications. Controller keeps a blank note as nil. design.md updated. Specs green: followups create/resolve (:js), followup_service, both notifiers, user_mailer (new followup email specs); erb_lint + standardrb clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r (fix broken index button) Migrating the case-show reminder to a Dialog earlier removed the jQuery `.followup-button` handler that the case-contacts INDEX card still relied on -- its "Make reminder" was silently broken (a SweetAlert that no longer fired). Fixed by consolidating the reminder UI into two shared partials reused by both cards: - case_contacts/_reminder_control: "Make reminder" -> design-system Dialog / "Resolve reminder" -> button_classes(:secondary). Replaces the show card's _case_contact_followup and the index's Swal _followup (both deleted). - case_contacts/_reminder_indicator: the amber alert_classes(:warning) pending callout (note + who set it + when), now on the index card too, not just the show card. A reminder now behaves identically on the case-show card and the case-contacts index: Dialog to create, secondary Resolve, on-card indicator, and emails to both the volunteer + setter (already app-wide via FollowupService / the notifiers). The new-design table keeps its own compact :row/:bar Dialog + bell indicator. design.md updated. Verified live: index "Make reminder" opens the native Dialog (no Swal) and the indicator renders. Specs: followups create/resolve (:js), case_contacts index + view -- 41 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ix stale Swal spec)
"Set reminder" reads better than "Make reminder" and matches what the new-design table already
uses, so the vocabulary is now unified across the shared case_contacts/_reminder_control and the
new-design:
- trigger "Set reminder", dialog title "Set a reminder", submit "Save reminder"
(were "Make reminder" / "Make a reminder?" / "Confirm");
- the on-card indicator now reads "Reminder set by X · date" (was "Follow-up requested"),
matching the Set reminder -> Reminder set -> Resolve reminder vocabulary.
Also fixed spec/system/notifications/index_spec, which still drove the removed SweetAlert
(find(".swal2-textarea")) -- now fills the Dialog note field; a stale reference the earlier
Dialog migration had missed.
design.md updated. Specs green: followups create/resolve, notifications index, case_contact view (31).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ontact has no casa_case Setting/resolving a reminder on a case contact with a nil casa_case (casa_case is optional on CaseContact; 8 such rows exist in the seed/legacy data) raised ActionController::UrlGenerationError: the create/resolve actions eagerly evaluate casa_case_path(case_contact.casa_case) as the redirect_back_or_to fallback, and casa_case_path(nil) has no matching route. (The old jQuery Swal $.post swallowed the 500; the Dialog's real form POST surfaces it.) The fallback is now nil-safe -- casa_case ? casa_case_path(...) : case_contacts_path -- in both actions. Also repaired the request spec that the earlier dual-recipient change had broken: create/resolve now deliver to an array (volunteer + setter), and resolving your own followup still notifies the OTHER party, so the old "does not send" case is reframed to "the resolver is the only party." Added a regression test for the nil-casa_case create. Specs green: followups request (10) + system create/resolve, service, both notifiers, notifications index (29 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…acts + clean orphan followups Root cause of the earlier UrlGenerationError: a case contact is created as a `started` DRAFT (case_contacts#new eagerly creates one; casa_case stays nil until the wizard finalizes it to `active`). Abandoned drafts (8 in the dev data) are legitimate unfinished wizard sessions, but the reminder control was rendered on them, so setting a reminder on a draft hit casa_case_path(nil). - Gate the shared reminder control on `contact.active?` in both cards (case-show + case-contacts index): drafts show only Edit/Delete, never a reminder (Edit still lets you finish the draft). - After-party task removes follow-ups already left on draft contacts (1 in dev, from the earlier error); the drafts themselves are left untouched as valid drafts. - design.md: reminders render only on active contacts. The prior nil-safe redirect stays as belt-and-suspenders. Specs green: followups create/resolve, request, case_contacts index, case_contact view (51). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
casa_org#edit becomes a max-w-7xl two-pane: a sticky grouped sub-nav rail beside a content column that shows one section at a time. New `settings-nav` Stimulus controller, built as progressive enhancement — with JS off every section stays visible (a plain scroll), so no-JS users and the rack_test view/request specs are unaffected; on connect it collapses to a single desktop panel / mobile grouped accordion, defaults to the first section, and honors the URL hash so deep links keep working (#case-contact-topics from the case-contact form). The entity partials, tables, anchor ids, and the profile/features/Twilio form are unchanged (each partial still renders its own card); section order is by task frequency + setup flow. - new: app/javascript/controllers/settings_nav_controller.js (+ stimulus manifest) - rewrite: app/views/casa_org/edit.html.erb (wraps existing sections; preserves locked text) - spec: spec/system/casa_org/settings_nav_spec.rb (default / switch / deep-link) — green - design.md: documented the pattern casa_org view + system + request specs green; the lone failure (edit_spec:63) is the pre-existing Twilio native-validation issue tracked in notes, not this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… readable contact topics, admins back link Review feedback on the new settings page: - Court split into Hearing types / Judges / Sent emails (separate sub-nav items + panels) instead of one bundled "Court details". - Page heading "Editing CASA Organization" -> "Settings" to match the sidebar nav label. - Contact topics: the 4-column table crammed the long free-text details into a narrow column; now a stacked block per topic (question + status + actions on one row, details at full card width below). Applies at all breakpoints. - casa_admins#index gains a "Back to settings" link — it's reached from Settings -> Administration but had no return path (the admin *edit* page already had one). Specs updated (view heading + contact-topics block, settings-nav court->hearing); green except the pre-existing edit_spec:63 Twilio native-validation failure tracked in notes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… sub-pages Follow-up to the settings master-detail review: - The Administration card's four links now stack in a single column (the master-detail panel is narrower than a full-width page, so the 2-column grid was cramped). - Banners, Imports, and Mileage rates index pages gain a "Back to settings" link (matching the admins index) so every page reached from Settings -> Administration has a way back. banners / imports / mileage_rates / casa_org system + view specs green (except the pre-existing edit_spec:63 Twilio native-validation failure tracked in notes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing, Court split, admin stack + back-links)
design.md still described the old "Editing CASA Organization" heading and the bundled Court section.
Bring it in line with the shipped state: heading == sidebar label ("Settings"), Court split into
Hearing types / Judges / Sent emails, Administration links stacked, and every admin sub-page linking
back to Settings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…op the intermediate panel) The four admin pages (Manage admins, Mileage rates, Banners, Imports) sat behind an "Admin pages" panel-of-cards — two extra clicks, and "Back to settings" landed on the default (Details) section instead of where the user started. Promote them to direct links in the Administration rail group (desktop) plus a tappable link block (mobile), and remove the panel. Each page is now one click away, and the back-target is unambiguous — the rail always shows the links. - edit.html.erb: Administration group -> 4 direct links; removed the administration section/panel; added an lg:hidden mobile link block. - spec: settings_nav_spec asserts the four direct admin links. - design.md: synced. settings-nav + casa_org view specs green (18/0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t rail + width) Manage admins / Mileage rates / Banners / Imports were standalone full-width pages that dropped the settings chrome — inconsistent with the in-page sections. Extract the sub-nav rail into a shared partial (casa_org/_settings_rail, panels: true|false) plus a settings frame (casa_org/_settings_frame), and render all four admin pages inside it: persistent rail with the current item highlighted + content in the right pane at max-w-7xl, matching casa_org/edit. Each page's title becomes the content h2 under the shared "Settings" header; the mobile "Back to settings" link is the return path (the rail is desktop-only). - new: casa_org/_settings_rail, casa_org/_settings_frame - casa_org/edit renders the shared rail (panels: true) - casa_admins / mileage_rates / banners / imports index reframed into the frame - design.md: documented the shared frame Full settings + admin suite green (53/1; the one failure is the pre-existing edit_spec:63 Twilio native-validation issue tracked in notes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CSV import button is intentionally disabled until a file is chosen (enable-on-select via
import.js; the disabled state is spec-locked), but nothing communicated *why*. Add an associated
hint ("Choose a CSV file above to enable the import button.") tied to each button via
aria-describedby, on all three import panels (volunteers / supervisors / cases), so the reason for
the disabled state is perceivable to sighted and screen-reader users. Behavior unchanged.
Import specs green (7/0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…th inline validation
- Settings rail is now text-only: the icons were noise in a dense grouped list and one was
duplicated (Judges / Manage admins both bi-person-badge). The primary sidebar keeps its icons.
- CSV import buttons (volunteers / supervisors / cases) are no longer disabled-until-file. They stay
enabled; submitting with no file shows an inline role=alert error ("Please choose a CSV file to
import.") and focuses the file input, instead of a dimmed button with no explanation. import.js
validates on submit (preventDefault + stopPropagation so the disable_with double-submit guard
doesn't leave the button stuck) and still persists the CSV across the SMS-opt-in reload.
Specs: settings-nav / view / admin pages green; imports 8/0 (incl. a new no-file validation test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…validation Continue the disabled-until-input -> enabled+validate pattern (after the import buttons), for the two localized cases: - SMS opt-in "Continue import" is enabled; clicking without checking the opt-in box shows an inline role=alert error and focuses the checkbox, instead of a dimmed unexplained button. - Court-orders "Copy" is enabled; clicking with no case selected shows an inline error and focuses the select. copy_court_orders controller validates in open() (dropped the disabled toggle + button target; select change now clears the error). Specs: imports + casa_cases copy-court-orders green (14/0), incl. new no-selection validation tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on (disable-form) disable_form_controller no longer disables the submit button; it guards the form submit — if the supervisor dropdown is still on the "Choose a supervisor" prompt, it blocks the submit, reveals an inline role=alert error, and focuses the dropdown (selecting a value clears the error). The Confirm button is always enabled. Single usage (volunteers bulk-assignment). Spec: bulk-assign describe green (8/0); the old disable/enable-toggling tests become an "is enabled" + validation-error test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion (searchable_select)
searchable_select's toggle-submit no longer disables the row's Assign button; on submit with no
supervisor picked it blocks the submit, reveals the row's inline error ("Choose a supervisor"), and
refocuses the TomSelect. The Assign button is always enabled. The court-report case picker (the other
searchable_select usage — no toggle-submit) is unaffected.
Spec: supervisors index green (15/0), incl. a new no-selection validation test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dropdown no longer covers its error - All the new client-side validation errors (import x3, SMS opt-in, copy-court-orders, volunteers bulk-assign, supervisor assign) now match the design-system field-error style: a bi-exclamation-circle icon (rose-600) + slate-500 message, matching field_error and the rest of the app — not the plain red text I had. - The supervisor-assign guard no longer calls TomSelect focus() on an invalid submit; that was auto-opening the dropdown over the error. The error is now visible. Specs green (22/0: imports / supervisors / volunteers bulk-assign / copy-court-orders). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… enabled+validate pattern - The supervisor/admin learning-hours roster retired its client-side DataTable in the migration without replacing the search. Add a server-side search-by-volunteer (?search= filters the roster rows before Pagy pagination) + a search field (auto-submit, matching the volunteers filter). The volunteer's own entries view is unchanged. Spec added. - design.md: document the enabled + validate-on-click form pattern and the TomSelect no-focus gotcha. Learning-hours index spec green (6/0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…up to the prior commit) The learning-hours-search commit's message mentioned this note but the design.md edit hadn't landed (anchor mismatch). Add it: the enabled + validate-on-click convention (inline field_error message, preventDefault + stopPropagation) that replaced the disabled-until-input buttons, plus the TomSelect "don't focus() on failure (it reopens the dropdown over the error)" gotcha. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a work in progress. Will flag when it is ready to merge.