Skip to content

fix(citizen-pwa): P0-P3 bug fixes and polish sweep#92

Merged
Exc1D merged 13 commits intomainfrom
fix/citizen-pwa-bugs-polish
May 3, 2026
Merged

fix(citizen-pwa): P0-P3 bug fixes and polish sweep#92
Exc1D merged 13 commits intomainfrom
fix/citizen-pwa-bugs-polish

Conversation

@Exc1D
Copy link
Copy Markdown
Owner

@Exc1D Exc1D commented May 3, 2026

Summary

Comprehensive bug fix and polish sweep for the Citizen PWA covering P0 critical bugs through P3 design/a11y issues.

P0 — Critical Bugs

  • P0-1: Show RevealSheet on submission success instead of racing to navigate away
  • P0-2: Ensure auth before lookup request (fixes CORS/auth error)
  • P0-3: SW retry with exponential backoff (1s/2s), dispatch failure event for banner wiring
  • P0-4: iOS PWA meta tags (apple-mobile-web-app-capable, status bar style, touch icon)
  • P0-6: Show fallback "Switch to manual location" button when GPS auto-start fails silently

P1 — Major Issues

  • P1-1/P1-8: Settings page — add Sign out, "Add to Home Screen" prompt, disable push toggle when permission denied
  • P1-2: Wire FilterBar on map with stateful filters and pointer-events wrapper
  • P1-3: cursor:pointer on map markers
  • P1-5: Delete account modal — proper fixed overlay, Escape/click-outside dismiss, autoFocus, aria attributes, semantic danger colors

P2 — UX Polish

  • P2-1: Consistent px-3 py-3 spacing on incident type buttons
  • P2-4/P2-5: py-4 on summary rows, mb-3 below consent
  • P2-12: WCAG AA medium severity color #a73400#7c3500 (4.5:1 on white)
  • P2-14: "Check another report" button in LookupScreen

P3 — Design & Accessibility

  • P3-3: Respect prefers-reduced-motionanimate-pulsemotion-safe:animate-pulse
  • P3-6/P3-7/P3-12/P3-13: Feed empty-state — neutral Info icon, authority-navy selected chips, text-xs everywhere
  • P3-9: Alert border thickness border-l-4border-l-2
  • P3-14: Remove redundant role=group wrapper from toggle
  • P3-15: Bilingual labels — / Pangalan and / Numero ng telepono
  • P3-16: Delete account dialog a11y fixes

Verification

  • All changes tested in dev environment
  • QA findings recorded in docs/qa-findings-2026-05-03.md

Summary by Sourcery

Apply a QA-driven bugfix and polish sweep to the Citizen PWA covering critical submission, auth, PWA, and UX/a11y issues.

New Features:

  • Add a conditional “Add to Home Screen” prompt in Settings when a deferred install prompt is available.
  • Introduce a GPS failure fallback that lets users switch to manual location entry in the report flow.
  • Provide a “Check another report” action in the lookup flow to quickly reset and search a new report.

Bug Fixes:

  • Guard lookup requests by ensuring the user is authenticated to avoid CORS/auth errors.
  • Improve service worker registration with retry and failure signaling to support offline behavior and error handling.
  • Prevent the report wizard from navigating away on submission success so the RevealSheet can display and control the post-submit transition.
  • Disable push notification controls and show helper text when browser notification permission is denied.

Enhancements:

  • Redesign the delete account flow into an accessible, dismissible modal with proper keyboard handling, focus, and danger styling.
  • Wire the map filter bar into stateful filters, overlaying it above the map with appropriate pointer-events handling.
  • Refine incident and alert visuals, including cursor affordances on markers, contrast-safe medium severity colors, thinner alert borders, and updated skeleton/loading animations that respect reduced motion preferences.
  • Polish report submission and feed layouts with consistent spacing, typography, and bilingual labels on key contact fields.
  • Update settings with a visible sign-out action and tidy documentation with a QA findings summary and tracking table.

Documentation:

  • Document the QA findings sweep, including addressed and deferred items, in docs/progress.md for future reference.

Summary by CodeRabbit

  • New Features

    • iOS PWA meta tags for improved iOS behavior
    • Dismissible delete-account flow (Escape + backdrop)
    • "Check another report", Add to Home Screen and Sign out in Settings
    • Incident filter bar overlay with offline awareness
  • Improvements

    • Reduced-motion-aware animations; bilingual (English/Tagalog) labels
    • Improved ARIA/keyboard accessibility and dialog focus behavior
    • Service worker retry logic and improved map marker hover affordance
    • Report success now returns to home
  • Documentation

    • Added QA findings and progress notes (2026-05-03)

Exc1D added 9 commits May 3, 2026 11:24
…t button\n\n- LookupScreen: ensureSignedIn() before requestLookup (fixes CORS/auth error)\n- Step3Review: remove danger-500 override on Submit (navy per DESIGN.md)\n- SettingsPage: add Sign out to Account section\n- SettingsPage: Add to Home Screen when deferredInstallPrompt available\n- SettingsPage: disable push toggle + hint when browser permission is denied\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ve nav('/reports/{id}') from onSuccess callback â�� it was racing the\nRevealSheet render away before users could see their reference/secret\ncodes. RevealSheet now handles dismissal via onClose -> nav('/').\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n\n- main.tsx: retry SW registration up to 3 times (1s/2s backoff); dispatch\n sw-registration-failed event on exhaustion for future banner wiring\n- index.html: add apple-mobile-web-app-capable, status-bar-style, title,\n apple-touch-icon â�� required for iOS home-screen install\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…markers\n\n- MapTab/index.tsx: import FilterBar, make filters stateful, render FilterBar\n absolutely above map with pointer-events-auto wrapper\n- IncidentLayer.tsx + MyReportLayer.tsx: add cursor:pointer to marker div\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ly\n\nWhen auto-location triggers GPS on mount but the device denies/times out,\nlocationMethod stays 'gps' with no location and no method-picker visible.\nNow renders a 'Switch to manual location' button when GPS failed.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-state polish\n\nDeleteAccountFlow: proper fixed-overlay backdrop, Escape-key dismiss,\nclick-outside close, autoFocus on first interactive element per dialog\nstate, aria-modal + aria-labelledby, semantic danger-600 color classes\ninstead of inline style. (P1-5, P3-16)\n\nFeedTab: swap green CheckCircle 'All clear' empty-state for neutral\nInfo icon + 'No incidents' heading; fix badge text-[10px] â�� text-xs;\nauthority-navy (001e40) for selected filter chips; caption text-[11px]\nâ�� text-xs. (P3-6, P3-7, P3-12, P3-13)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…\nAlertsTab: border-l-4 â�� border-l-2 (P3-9, stay within 1px design-law\nspirit; 2px is minimal visual cue, not a heavy stripe).\n\nLookupScreen: add 'Check another report' button below result card so\nusers can look up a second incident without refreshing. (P2-14)\n\nMapTab IncidentLayer + FilterBar: medium severity color #a73400 â�� #7c3500\nto meet WCAG AA 4.5:1 contrast on white backgrounds. (P2-12)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…els\n\nStep1Evidence: px-3 py-3 on incident type buttons (P2-1)\nStep3Review: py-3 â�� py-4 on all summary rows, mb-3 below consent (P2-4, P2-5)\nFeedTab/AlertsTab/ProfileTab/Step*: animate-pulse â�� motion-safe:animate-pulse\n respects prefers-reduced-motion for all skeleton loaders (P3-3)\nToggle: remove redundant role=group wrapper with duplicate aria-label; the\n role=switch button already carries the label (P3-14)\nContactFields: Tagalog sub-labels '/ Pangalan' and '/ Numero ng telepono'\n added to name and phone fields per PRODUCT.md inclusive-by-default (P3-15)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 3, 2026

Reviewer's Guide

This PR implements a broad bug-fix and polish sweep for the Citizen PWA, focusing on critical reliability (submission flow, auth, SW registration, GPS fallback), UX/a11y of destructive flows and settings (delete account modal, push toggle, sign-out, A2HS), map and feed usability (filter wiring, marker affordances, empty states, colors), motion/accessibility preferences, and documentation of QA coverage.

Sequence diagram for report submission success RevealSheet flow

sequenceDiagram
  actor User
  participant SubmitReportForm
  participant WizardContainer
  participant SubmissionPanel
  participant RevealSheetSuccess
  participant WizardSnapshot
  participant Nav as Router
  participant ReportApi

  User->>SubmitReportForm: Complete steps and click Submit
  SubmitReportForm->>WizardContainer: onSubmit()
  WizardContainer->>SubmissionPanel: Render with draft, secret, onSuccess

  User->>SubmissionPanel: Confirm submission
  SubmissionPanel->>ReportApi: submitReport(draft, secret)
  ReportApi-->>SubmissionPanel: success

  SubmissionPanel->>WizardSnapshot: clear()
  SubmissionPanel-->>WizardContainer: onSuccess()

  WizardContainer->>SubmissionPanel: Render RevealSheetSuccess
  SubmissionPanel->>RevealSheetSuccess: referenceCode, municipalityId, secretCode, onClose

  User->>RevealSheetSuccess: Tap close button
  RevealSheetSuccess-->>SubmissionPanel: onClose()
  SubmissionPanel->>Nav: navigate("/")
Loading

Sequence diagram for lookup request with ensureSignedIn

sequenceDiagram
  actor User
  participant LookupScreen
  participant FirebaseConfig
  participant EnsureSignedIn
  participant Fns as FirebaseFunctions
  participant CloudFn as requestLookup

  User->>LookupScreen: Enter reference and submit
  LookupScreen->>FirebaseConfig: hasFirebaseConfig()
  alt config missing
    FirebaseConfig-->>LookupScreen: false
    LookupScreen-->>User: Show FIREBASE_ENV_ERROR_MESSAGE
  else config present
    FirebaseConfig-->>LookupScreen: true
    LookupScreen->>EnsureSignedIn: ensureSignedIn()
    EnsureSignedIn-->>LookupScreen: user authenticated

    LookupScreen->>Fns: fns()
    Fns-->>LookupScreen: functions instance
    LookupScreen->>CloudFn: httpsCallable("requestLookup", payload)
    CloudFn-->>LookupScreen: result
    LookupScreen-->>User: Show lookup result
  end

  User->>LookupScreen: Click "Check another report"
  LookupScreen->>LookupScreen: setResult(null)
  LookupScreen-->>User: Show lookup form again
Loading

Updated class diagram for key Citizen PWA components

classDiagram
  class DeleteAccountFlow {
    +step: string
    +typed: string
    +error: string
    +onGoodbye(): void
    +goIdle(): void
    +handleConfirm(): Promise~void~
  }

  class SettingsPage {
    +enabled: boolean
    +user: object
    +requestPermission(): Promise~boolean~
    +disable(): Promise~void~
  }

  class Toggle {
    +checked: boolean
    +label: string
    +disabled: boolean
    +onChange(next: boolean): void
  }

  class MapTab {
    +filters: Filters
    +isOffline: boolean
    +selectedPin: SelectedPin
    +sheetPhase: string
  }

  class FilterBar {
    +filters: Filters
    +disabled: boolean
    +onChange(next: Filters): void
  }

  class IncidentLayer {
    +filters: Filters
    +onPinTap(incident: PublicIncident): void
  }

  class MyReportLayer {
    +onPinTap(report: MyReport): void
  }

  class SubmitReportForm {
  }

  class WizardContainer {
    +draft: object
    +secret: string
  }

  class SubmissionPanel {
    +draft: object
    +secret: string
    +onSuccess(): void
  }

  class RevealSheetSuccess {
    +referenceCode: string
    +municipalityId: string
    +secretCode: string
    +onClose(): void
  }

  class LookupScreen {
    +result: LookupResult
    +error: string
  }

  class ContactFields {
    +name: string
    +phoneNumber: string
  }

  DeleteAccountFlow --> SettingsPage : used in
  SettingsPage --> Toggle : renders

  MapTab --> FilterBar : renders
  MapTab --> IncidentLayer : configures
  MapTab --> MyReportLayer : configures

  SubmitReportForm --> WizardContainer : contains
  WizardContainer --> SubmissionPanel : renders
  SubmissionPanel --> RevealSheetSuccess : shows on success

  SubmitReportForm --> ContactFields : uses
  LookupScreen --> SettingsPage : navigates from
Loading

File-Level Changes

Change Details Files
Reworked Delete Account flow into an accessible, modal overlay with proper dismissal behaviors and danger styling.
  • Added Escape-key listener to close the dialog when not idle.
  • Replaced inline dialog markup with a fixed, full-screen backdrop that supports click-outside-to-dismiss.
  • Split warn and confirm steps into styled modal cards with autoFocus on primary actions, aria attributes, and clear visual hierarchy.
  • Refined button styles and disabled states, including a submitting state label for the confirm action.
apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
Improved settings page to handle push permission denial, expose Add to Home Screen, and add sign-out control.
  • Wrapped push notification row to allow hint text and disabled state messaging.
  • Disabled the push toggle when Notification.permission is 'denied' and show instructional helper text.
  • Added conditional Add to Home Screen button wired to window.deferredInstallPrompt.prompt().
  • Added a signed-in-only Sign out button that calls auth().signOut() and navigates home.
apps/citizen-pwa/src/pages/SettingsPage.tsx
Documented QA sweep and mapped findings to concrete fixes and commits.
  • Added a dated section describing the QA findings sweep and scope.
  • Listed each P0–P3 finding with a short description, implemented fix, and commit reference where available.
  • Documented which findings were skipped and why (non-code or out-of-scope).
  • Recorded lint gate status for the project.
docs/progress.md
Polished feed and alerts UX and accessibility, including typography, motion safety, and empty-state design.
  • Normalized severity badges and timestamps to text-xs and adjusted empty-state caption typography.
  • Guarded skeleton animations with motion-safe:animate-pulse in FeedTab and AlertsTab skeletons.
  • Changed selected filter chip color to authority navy and updated empty-state icon/text to neutral Info/No incidents.
  • Reduced alert card border-left thickness from 4px to 2px while keeping skeleton styling consistent.
apps/citizen-pwa/src/components/FeedTab.tsx
apps/citizen-pwa/src/components/AlertsTab.tsx
Improved submission wizard UX: respect reduced motion, adjust spacing, and fix submission completion flow.
  • Replaced animate-pulse with motion-safe:animate-pulse on step indicators across Step1/2/3 and other components.
  • Standardized padding on incident type buttons and review summary rows, and added margin under consent block.
  • Removed hard-coded danger color override from the submit button to use primary styling instead.
  • Changed post-submit behavior to clear wizard state and show the RevealSheet, navigating home only when the sheet closes.
apps/citizen-pwa/src/components/SubmitReportForm/Step1Evidence.tsx
apps/citizen-pwa/src/components/SubmitReportForm/Step2WhoWhere.tsx
apps/citizen-pwa/src/components/SubmitReportForm/Step3Review.tsx
apps/citizen-pwa/src/components/SubmitReportForm/index.tsx
Enhanced GPS and contact/lookup flows with resilience and bilingual/a11y improvements.
  • Added a visible "Switch to manual location" fallback when GPS is selected, not loading, and no location is available, wiring it to resetGps and switch to manual mode.
  • Introduced a "Check another report" button on lookup results that clears the result state for a new query.
  • Ensured requestLookup calls ensureSignedIn() before httpsCallable to avoid CORS/auth issues.
  • Augmented contact field labels with Tagalog equivalents for name and phone number.
apps/citizen-pwa/src/components/SubmitReportForm/Step2WhoWhere.tsx
apps/citizen-pwa/src/components/LookupScreen.tsx
apps/citizen-pwa/src/components/SubmitReportForm/ContactFields.tsx
apps/citizen-pwa/src/services/firebase.js
Hardened service worker registration with exponential backoff and failure signaling.
  • Wrapped navigator.serviceWorker.register in an async registerSW helper with up to 3 attempts.
  • Implemented incremental delays (1s, 2s, 3s) between attempts based on attempt count.
  • Logged attempt-specific failures to console.
  • Dispatched a custom sw-registration-failed event when all attempts are exhausted for potential UI handling.
apps/citizen-pwa/src/main.tsx
Refined map layers and filter UI, including stateful filters, marker affordances, and color contrast updates.
  • Changed map filters from a const to React state and rendered FilterBar over the map with pointer-events management.
  • Updated IncidentLayer and FilterBar medium severity color to #7c3500 to meet contrast requirements.
  • Added cursor:pointer styling to custom Leaflet icons in IncidentLayer and MyReportLayer to signal interactivity.
  • Guarded additional skeletons and animations with motion-safe where applicable.
apps/citizen-pwa/src/components/MapTab/index.tsx
apps/citizen-pwa/src/components/MapTab/IncidentLayer.tsx
apps/citizen-pwa/src/components/MapTab/FilterBar.tsx
apps/citizen-pwa/src/components/MapTab/MyReportLayer.tsx
Improved general a11y of toggles and skeletons and added iOS PWA meta tags.
  • Removed redundant role="group" and aria-label from Toggle wrapper, relying on the switch role and label prop.
  • Applied motion-safe:animate-pulse to skeleton loaders in ProfileTab and other components to respect prefers-reduced-motion.
  • Added iOS-specific PWA meta tags and apple-touch-icon link in index.html for better standalone behavior on iOS.
apps/citizen-pwa/src/components/Toggle.tsx
apps/citizen-pwa/src/components/ProfileTab.tsx
apps/citizen-pwa/index.html

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

Warning

Rate limit exceeded

@Exc1D has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 20 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e79e249d-ba42-42ca-a293-5ecf97404b76

📥 Commits

Reviewing files that changed from the base of the PR and between eeea591 and 6e0be1e.

📒 Files selected for processing (2)
  • apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
  • apps/citizen-pwa/src/components/MapTab/index.tsx
📝 Walkthrough

Walkthrough

Multiple QA-driven UI, accessibility, and infra refinements across the Citizen PWA: iOS PWA meta tags, motion-safe animations, minor visual/tokens tweaks, marker cursor affordance, Delete Account dialog accessibility and Escape handling, GPS fallback, service-worker registration retries, bilingual labels, notification/install UI, and added QA documentation.

Changes

QA refinements: single change DAG

Layer / File(s) Summary
PWA Entrypoint / Meta
apps/citizen-pwa/index.html
Adds iOS-specific meta tags (apple-mobile-web-app-capable, apple-mobile-web-app-status-bar-style, apple-mobile-web-app-title) and a touch icon link.
Service Worker / Infra
apps/citizen-pwa/src/main.tsx
Replaces one-shot SW registration with async registerSW(attemptsLeft = 3) retry helper that logs attempts and dispatches sw-registration-failed after final failure; load handler invokes registerSW().
Data / UI wiring
apps/citizen-pwa/src/components/MapTab/index.tsx, .../FilterBar.tsx
Converts filters to React state, adds FilterBar overlay wired via filters/setFilters, disables when offline, and introduces WINDOW_LABELS for empty-state messaging.
Auth Flow Guard
apps/citizen-pwa/src/components/LookupScreen.tsx
Calls ensureSignedIn() (if Firebase configured) before invoking requestLookup; adds “Check another report” button to clear results.
Dialog / UX Behavior
apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
Adds useEffect Escape-key listener to call goIdle() when appropriate; consolidates non-idle UI into a full-screen overlay with backdrop-dismiss (unless submitting); enhances ARIA, autofocus, typed-confirmation disabling during submit, and error role rendering.
Reduced-Motion / Accessibility
apps/citizen-pwa/src/components/... (AlertsTab.tsx, FeedTab.tsx, ProfileTab.tsx, SubmitReportForm/*)
Replaces unconditional animate-pulse with motion-safe:animate-pulse for skeletons and progress indicators to respect reduced-motion preferences.
Visual styling & affordances
apps/citizen-pwa/src/components/... (MapTab/IncidentLayer.tsx, MapTab/MyReportLayer.tsx, MapTab/FilterBar.tsx, FeedTab.tsx, AlertsTab.tsx)
Adjusts medium severity color (#a73400#7c3500), changes selected filter chip color (#0f9488#001e40), reduces AlertCard left border (border-l-4border-l-2), and adds cursor:pointer to marker icon wrappers.
Submit report UX & copy
apps/citizen-pwa/src/components/SubmitReportForm/... (ContactFields.tsx, Step1Evidence.tsx, Step2WhoWhere.tsx, Step3Review.tsx, index.tsx)
Adds bilingual labels (English / Tagalog) for name/phone, gates step pulse animations with motion-safe, adds GPS fallback to switch to manual location and show errors, tweaks spacing in review rows, removes custom danger class overrides from submit button, and changes draft success handling so success sheet navigates to / (no draft-specific nav via onSuccess).
Toggle & Feed adjustments
apps/citizen-pwa/src/components/Toggle.tsx, FeedTab.tsx
Removes wrapper role="group"/aria-label from Toggle container (internal switch retains ARIA); Feed empty state swaps CheckCircleInfo, adjusts text/time-ago sizing to text-xs, and updates skeletons to motion-safe variants.
Settings / Account controls
apps/citizen-pwa/src/pages/SettingsPage.tsx
Disables push-notifications toggle when Notification.permission === 'denied' and shows a warning; adds “Add to Home Screen” button when window.deferredInstallPrompt exists; adds “Sign out” button that calls auth().signOut() and navigates to /.
Documentation / QA log
docs/progress.md, docs/qa-findings-2026-05-03.md
Adds a QA findings sweep entry and a detailed QA findings document enumerating P0–P3 issues, confirmations, missing features, and a prioritized fix order referencing specific files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopped the QA list, nibbling bugs away,

Motion-safe pulses now rest when you say,
iOS meta snug, and SW retries three,
Delete with Escape, GPS falls back free,
Bilingual labels — install, sign out — hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(citizen-pwa): P0-P3 bug fixes and polish sweep' accurately summarizes the main objective of the PR, which is applying a comprehensive QA-driven bugfix and polish sweep covering critical to design-level issues across the Citizen PWA.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/citizen-pwa-bugs-polish

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
Review rate limit: 0/1 reviews remaining, refill in 38 minutes and 20 seconds.

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

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="apps/citizen-pwa/src/components/Toggle.tsx" line_range="34" />
<code_context>
   ].join(' ')

   return (
-    <div className="flex items-center gap-3" role="group" aria-label={label}>
+    <div className="flex items-center gap-3">
       <button
         type="button"
</code_context>
<issue_to_address>
**issue (bug_risk):** The Toggle's accessible label appears to have been removed, which may break screen-reader labeling.

Previously, `label` was passed to `aria-label` on the `role="group"` wrapper, giving the control an accessible name. After this change, `label` is unused and the `role="switch"` button has no label, so it will be announced as an unlabeled switch by screen readers. Please reintroduce an accessible name (for example `aria-label={label}` on the button, or another appropriate labeling strategy).
</issue_to_address>

### Comment 2
<location path="docs/progress.md" line_range="52" />
<code_context>
+
 ## 2026-05-03 — PR #91 Review Follow-ups (branch: `fix/citizen-pwa-auth-and-wizard-followups`)

 Addressed all Sourcery-ai and CodeRabbit review comments on PR #91.
</code_context>
<issue_to_address>
**issue (typo):** Possible typo in the name "Sourcery-ai".

If you’re referring to the code review tool, its official name is “Sourcery AI” (no hyphen, capitalized “AI”).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

].join(' ')

return (
<div className="flex items-center gap-3" role="group" aria-label={label}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The Toggle's accessible label appears to have been removed, which may break screen-reader labeling.

Previously, label was passed to aria-label on the role="group" wrapper, giving the control an accessible name. After this change, label is unused and the role="switch" button has no label, so it will be announced as an unlabeled switch by screen readers. Please reintroduce an accessible name (for example aria-label={label} on the button, or another appropriate labeling strategy).

Comment thread docs/progress.md Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/citizen-pwa/src/components/MapTab/index.tsx (1)

233-233: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Humanize the time-window copy.

filters.window renders raw tokens like 7d and 30d, which reads awkwardly in the empty-state message. Reuse the existing user-facing labels here so the copy says “last 7 days” / “last 30 days.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/citizen-pwa/src/components/MapTab/index.tsx` at line 233, The
empty-state message is showing raw tokens (filters.window) like "7d" — update
the JSX in the MapTab component so it uses the same user-facing label used by
the time-window control instead of the raw token; replace "No reported incidents
in this area in the last {filters.window}." with "No reported incidents in this
area in the last {humanLabel}" where humanLabel is obtained by reusing the
existing time-window label mapping/helper used by the filter control (the same
source used to render the window selector) so tokens like "7d"/"30d" become "7
days"/"30 days".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/citizen-pwa/src/components/DeleteAccountFlow.tsx`:
- Around line 35-45: The Escape/backdrop dismissal currently calls goIdle() even
while deletion is in flight; change the dismissal guards to ignore events when
step === 'submitting' so the dialog cannot close once handleConfirm() has moved
to 'submitting'. Specifically, update the useEffect's onKey handler to only call
goIdle() when step is neither 'idle' nor 'submitting' (check step before calling
goIdle), and likewise update the backdrop/close button click handler(s) (the
same handler that currently invokes goIdle on backdrop clicks) to return early
if step === 'submitting', ensuring the UI stays open until the deletion
completes or explicitly transitions out of 'submitting'.

---

Outside diff comments:
In `@apps/citizen-pwa/src/components/MapTab/index.tsx`:
- Line 233: The empty-state message is showing raw tokens (filters.window) like
"7d" — update the JSX in the MapTab component so it uses the same user-facing
label used by the time-window control instead of the raw token; replace "No
reported incidents in this area in the last {filters.window}." with "No reported
incidents in this area in the last {humanLabel}" where humanLabel is obtained by
reusing the existing time-window label mapping/helper used by the filter control
(the same source used to render the window selector) so tokens like "7d"/"30d"
become "7 days"/"30 days".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cdc6566b-206f-4d4b-97fe-ff36427a3998

📥 Commits

Reviewing files that changed from the base of the PR and between 01ef488 and d9f5896.

📒 Files selected for processing (19)
  • apps/citizen-pwa/index.html
  • apps/citizen-pwa/src/components/AlertsTab.tsx
  • apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
  • apps/citizen-pwa/src/components/FeedTab.tsx
  • apps/citizen-pwa/src/components/LookupScreen.tsx
  • apps/citizen-pwa/src/components/MapTab/FilterBar.tsx
  • apps/citizen-pwa/src/components/MapTab/IncidentLayer.tsx
  • apps/citizen-pwa/src/components/MapTab/MyReportLayer.tsx
  • apps/citizen-pwa/src/components/MapTab/index.tsx
  • apps/citizen-pwa/src/components/ProfileTab.tsx
  • apps/citizen-pwa/src/components/SubmitReportForm/ContactFields.tsx
  • apps/citizen-pwa/src/components/SubmitReportForm/Step1Evidence.tsx
  • apps/citizen-pwa/src/components/SubmitReportForm/Step2WhoWhere.tsx
  • apps/citizen-pwa/src/components/SubmitReportForm/Step3Review.tsx
  • apps/citizen-pwa/src/components/SubmitReportForm/index.tsx
  • apps/citizen-pwa/src/components/Toggle.tsx
  • apps/citizen-pwa/src/main.tsx
  • apps/citizen-pwa/src/pages/SettingsPage.tsx
  • docs/progress.md

Comment thread apps/citizen-pwa/src/components/DeleteAccountFlow.tsx Outdated
- DeleteAccountFlow: prevent Escape/backdrop dismissal while submitting (CodeRabbit)
- MapTab: humanize time-window labels in empty state (CodeRabbit)
- progress.md: fix Sourcery AI capitalization (Sourcery)
- Toggle.tsx: already correct — aria-label present on role=switch button
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/citizen-pwa/src/components/MapTab/index.tsx (1)

233-241: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Empty state message is misleading when a non-"all" severity filter is active.

visibleIncidents is already severity-filtered by usePublicIncidents, so when severity !== 'all' the message "No reported incidents in this area in the last {window}" may display even though medium/low incidents exist — the user has no indication their filter is responsible.

🔧 Proposed fix
-            No reported incidents in this area in the last {WINDOW_LABELS[filters.window]}.
+            No{filters.severity !== 'all' ? ` ${filters.severity}` : ''} incidents reported in this area in the last {WINDOW_LABELS[filters.window]}.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/citizen-pwa/src/components/MapTab/index.tsx` around lines 233 - 241, The
empty-state message for the MapTab component incorrectly assumes no incidents
exist when showEmpty is true even though visibleIncidents is already
severity-filtered by usePublicIncidents; update the JSX that renders the <div>
(the block controlled by showEmpty) to check filters.severity and render a
different message when filters.severity !== 'all' that includes the active
severity (filters.severity) or instructs the user to clear/change the severity
filter, while keeping the existing WINDOW_LABELS[filters.window] text for the
time window; ensure you reference showEmpty,
visibleIncidents/usePublicIncidents, filters.severity, filters.window, and
WINDOW_LABELS when making the conditional message change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/citizen-pwa/src/components/DeleteAccountFlow.tsx`:
- Around line 92-104: The destructive "Yes, delete my account →" button
currently has autoFocus; move the autoFocus attribute to the least-destructive
control (the Cancel button) so keyboard/AT users land on Cancel by default.
Update the JSX so the confirm button (which calls setStep('confirm'),
setTyped(''), setError(null)) no longer has autoFocus or the eslint-disable
comment, and instead add autoFocus on the Cancel button element; keep all
existing handlers and classNames unchanged except for the autofocus relocation.
- Around line 156-162: The Cancel button currently calls goIdle()
unconditionally which allows the modal to be dismissed while step ===
'submitting' and then be force-reopened when the async deletion fails; update
the Cancel button handler in DeleteAccountFlow (and/or the goIdle() call site)
to be guarded by the step state: either disable the button and make its onClick
a no-op when step === 'submitting', or return early from goIdle() if step ===
'submitting'; also ensure the button has an appropriate disabled/aria-busy state
so UI and a11y reflect that the operation is in progress.

---

Outside diff comments:
In `@apps/citizen-pwa/src/components/MapTab/index.tsx`:
- Around line 233-241: The empty-state message for the MapTab component
incorrectly assumes no incidents exist when showEmpty is true even though
visibleIncidents is already severity-filtered by usePublicIncidents; update the
JSX that renders the <div> (the block controlled by showEmpty) to check
filters.severity and render a different message when filters.severity !== 'all'
that includes the active severity (filters.severity) or instructs the user to
clear/change the severity filter, while keeping the existing
WINDOW_LABELS[filters.window] text for the time window; ensure you reference
showEmpty, visibleIncidents/usePublicIncidents, filters.severity,
filters.window, and WINDOW_LABELS when making the conditional message change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 37f51422-1589-4a81-91b4-5008275cdb03

📥 Commits

Reviewing files that changed from the base of the PR and between d9f5896 and 2e009e9.

📒 Files selected for processing (4)
  • apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
  • apps/citizen-pwa/src/components/MapTab/index.tsx
  • docs/progress.md
  • docs/qa-findings-2026-05-03.md

Comment thread apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
Comment thread apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
- DeleteAccountFlow: move autoFocus to Cancel button; guard Cancel during submitting
- MapTab: severity-aware empty state message when filter is active
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/citizen-pwa/src/components/DeleteAccountFlow.tsx`:
- Around line 130-141: The confirmation input (id "delete-confirm") stays
editable during the async submitting state and loses focus recovery after an
error; update the input in DeleteAccountFlow.tsx to set disabled={submitting}
(or equivalent) so users cannot type while deletion is in progress, and
replace/remove the unreliable autoFocus by adding a ref (e.g., confirmInputRef)
plus a useEffect that watches step === 'confirm' to call
confirmInputRef.current?.focus() when entering the confirm step (so focus is
restored after handleConfirm fails and step resets); keep the value handlers
(typed/setTyped) intact and ensure the disabled check uses the same submitting
state used by the submit button.

In `@apps/citizen-pwa/src/components/MapTab/index.tsx`:
- Around line 239-241: The filter-guidance hint is currently gated by the
overall empty condition (showEmpty) which also requires myReports.length === 0,
so when a user has personal reports the severity-filter hint is suppressed;
update the MapTab rendering to compute and use an independent condition (e.g., a
boolean like filterOnlyEmpty or showFilterHint) that checks the active filters
against the public incidents collection (use filters.severity, filters.window,
WINDOW_LABELS and the public incidents list or filteredPublicIncidents result)
and render the "Try clearing the severity filter." message whenever no public
incidents match the current filters, regardless of myReports length, while
keeping the existing full-empty message logic (showEmpty) for truly empty maps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3314450f-e825-4660-ab49-1fea295345ef

📥 Commits

Reviewing files that changed from the base of the PR and between 2e009e9 and eeea591.

📒 Files selected for processing (2)
  • apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
  • apps/citizen-pwa/src/components/MapTab/index.tsx

Comment thread apps/citizen-pwa/src/components/DeleteAccountFlow.tsx
Comment thread apps/citizen-pwa/src/components/MapTab/index.tsx Outdated
- DeleteAccountFlow: replace autoFocus with ref+useEffect focus management; disable input during submitting
- MapTab: show severity filter hint independently from showEmpty so it appears even when myReports exist
@Exc1D Exc1D merged commit ae7f841 into main May 3, 2026
14 checks passed
@Exc1D Exc1D deleted the fix/citizen-pwa-bugs-polish branch May 3, 2026 10:49
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