Project

General

Profile

Actions

User Story #598

closed

Feature #533: Authentication Hum Rahi

EPIC #597: Epic: E2.3 โ€” Citizen Report Status Tracking

US-025 ยท Citizen Views All Submitted Reports with Current Status

Added by Islam Mansoori about 1 month ago. Updated 5 days ago.

Status:
Backend completed
Priority:
low
Assignee:
Target version:
Start date:
Due date:
% Done:

100%

Estimated time:

Description

๐Ÿ“– Story

As Rahul (a citizen), I want to see all my previously submitted incident reports in one place with their current status, so that I know which issues are being addressed and which still need attention โ€” without calling anyone.


๐ŸŽฏ Goal & Context

This is the primary post-submission touchpoint for the citizen. After filing a report, Rahul's next natural question is "What happened to it?" This screen answers that. It must feel lightweight, scannable, and trustworthy. Status accuracy directly impacts citizen confidence in the app.


โœ… In-Scope

  • Paginated/scrollable list of all reports submitted by the logged-in user
  • Each card shows: title, category, location, reported date, current status
  • Status badge with visual differentiation per status type
  • "View Details" deep link per report
  • Bottom navigation bar (Reports tab active)
  • Empty state when no reports exist
  • Pull-to-refresh gesture support

โŒ Out-of-Scope

  • Editing or withdrawing a report from this screen
  • Filtering / sorting (separate story โ€” filter icon is a placeholder per wireframe)
  • Push notification trigger (separate story)
  • Admin-side status updates (backend story)

๐ŸŽจ Design Guidance (for Designer + Frontend Engineer)

Reference Wireframe Breakdown

Based on the provided low-fi wireframe, implement the following component hierarchy:

<MyReportsDashboard>
  โ”œโ”€โ”€ <AppHeader>            โ†’ Back icon | "My Reports" title | Filter icon (disabled/placeholder)
  โ”œโ”€โ”€ <ReportList>           โ†’ Scrollable container
  โ”‚     โ””โ”€โ”€ <ReportCard>     โ†’ Repeated per report item
  โ”‚           โ”œโ”€โ”€ Title + StatusBadge (top row)
  โ”‚           โ”œโ”€โ”€ LocationText
  โ”‚           โ””โ”€โ”€ ReportedDate + "View Details" CTA
  โ””โ”€โ”€ <BottomNavBar>         โ†’ Home | Reports (active) | Map | Profile

Status Badge Visual Spec

Status Label Visual Treatment
SUBMITTED Submitted Outlined, neutral grey, no fill
ASSIGNED Assigned Outlined, amber/yellow tint
IN_PROGRESS In Progress Dashed border, blue tint
RESOLVED Resolved Solid fill, green tint, bold
REJECTED Rejected Solid fill, red tint

โš ๏ธ Design Note: Do not rely on color alone โ€” pair every status with an icon or text label for accessibility (WCAG 2.1 AA).

Card Layout Rules

  • Card width: full container width minus 16px padding each side
  • Min card height: 100px (avoid cramped feel on short content)
  • "View Details" must look tappable โ€” underline + sufficient tap target (min 44ร—44px)
  • Location text: subdued (opacity ~65%), max 1 line, ellipsis overflow
  • Date format: DD MMM (e.g., 24 Oct) โ€” do not show year unless it differs from current year

Empty State (required, not in wireframe)

When reports.length === 0:

  • Illustration placeholder (hand-drawn style matching wireframe aesthetic)
  • Heading: "No reports yet"
  • Body: "Tap the + button on Home to report your first incident."
  • CTA button: "Go to Home" โ†’ navigates to Home tab

Loading State

  • Show skeleton cards (3 shimmer placeholders) while API fetch is in flight
  • Do NOT show a full-screen spinner โ€” skeleton maintains layout stability

๐Ÿ–ฅ๏ธ Frontend Implementation Guidance

Component File Structure

/features/my-reports/
  โ”œโ”€โ”€ MyReportsDashboard.tsx       โ† Page-level component
  โ”œโ”€โ”€ ReportCard.tsx               โ† Individual card (pure/presentational)
  โ”œโ”€โ”€ StatusBadge.tsx              โ† Reusable badge component
  โ”œโ”€โ”€ ReportListSkeleton.tsx       โ† Loading placeholder
  โ”œโ”€โ”€ EmptyReportsState.tsx        โ† Zero-data state
  โ”œโ”€โ”€ useMyReports.ts              โ† Data fetching hook
  โ””โ”€โ”€ myReports.types.ts           โ† TypeScript interfaces

TypeScript Interface

// myReports.types.ts

export type ReportStatus =
  | 'SUBMITTED'
  | 'ASSIGNED'
  | 'IN_PROGRESS'
  | 'RESOLVED'
  | 'REJECTED';

export interface ReportSummary {
  id: string;                    // UUID
  title: string;                 // e.g., "Broken Street Light"
  category: string;              // e.g., "Streetlight Fault"
  location: string;              // Short address / landmark
  status: ReportStatus;
  reportedAt: string;            // ISO 8601
  updatedAt: string;             // ISO 8601 โ€” for "last updated" display
  thumbnailUrl?: string;         // Optional โ€” photo thumbnail
}

export interface MyReportsResponse {
  data: ReportSummary[];
  total: number;
  page: number;
  pageSize: number;
}

Data Fetching Hook

// useMyReports.ts
const useMyReports = () => {
  const [reports, setReports] = useState<ReportSummary[]>([]);
  const [status, setStatus] = useState<'idle' | 'loading' | 'error' | 'success'>('idle');

  const fetchReports = async (page = 1) => {
    setStatus('loading');
    try {
      const res = await api.get<MyReportsResponse>(`/citizen/reports?page=${page}&pageSize=20`);
      setReports(prev => page === 1 ? res.data.data : [...prev, ...res.data.data]);
      setStatus('success');
    } catch {
      setStatus('error');
    }
  };

  useEffect(() => { fetchReports(); }, []);
  return { reports, status, refresh: () => fetchReports(1) };
};

API Contract (Frontend โ†’ Backend)

GET /api/v1/citizen/reports
Authorization: Bearer <token>
Query params:
  page      (default: 1)
  pageSize  (default: 20)
  status    (optional filter: SUBMITTED | IN_PROGRESS | RESOLVED ...)

Response 200:
{
  "data": [ ...ReportSummary[] ],
  "total": 42,
  "page": 1,
  "pageSize": 20
}

Response 401: Token expired โ†’ redirect to Login
Response 404: No reports found โ†’ render EmptyState (not an error)

Navigation & Routing

Action Behavior
Tap "View Details" Navigate to /reports/:id (Report Detail Screen)
Tap back < Navigate to previous screen in stack
Tap "Reports" nav tab No-op if already active; scroll list to top
Tap "Home" nav tab Navigate to Home screen
Tap "Map" nav tab Navigate to Map view
Tap "Profile" nav tab Navigate to Profile screen

Infinite Scroll / Pagination

  • Load first 20 records on mount
  • When user scrolls to within 200px of list bottom, automatically fetch next page (page + 1)
  • Append new cards to existing list (no full re-render)
  • Show a small inline loader at bottom during next-page fetch
  • When all records loaded, show: "You've seen all your reports" at the bottom

Pull-to-Refresh

  • On downward overscroll gesture: trigger refresh() from hook (re-fetch page 1, replace list)
  • Show a subtle loading indicator during refresh
  • On success: briefly show a toast "Reports updated" (auto-dismiss 2s)

โ™ฟ Accessibility Requirements

  • All status badges must have aria-label (e.g., aria-label="Status: In Progress")
  • Report cards must be keyboard-navigable (tab order)
  • "View Details" links must have descriptive aria-label: "View details for Broken Street Light"
  • Minimum tap target: 44ร—44px for all interactive elements
  • Color contrast ratio: โ‰ฅ 4.5:1 for all text (WCAG AA)
  • Screen reader should announce: "Report list, 4 items" on load

๐Ÿ“ Acceptance Criteria

# Criteria Test Method
AC-1 All reports submitted by the logged-in citizen are displayed, sorted by reportedAt descending (most recent first) Manual + API test
AC-2 Each card displays: title, location, reported date, and correct status badge Visual QA
AC-3 Status badge visually matches the spec table above for all 5 status types Design QA
AC-4 "View Details" navigates to the correct Report Detail screen for that report.id Manual
AC-5 Empty state is shown when the user has zero reports Manual
AC-6 Skeleton loading state appears while data is fetching Manual
AC-7 Pull-to-refresh updates the list with latest data from the API Manual
AC-8 Reports tab is visually active in the bottom nav Visual QA
AC-9 List handles 50+ reports without UI freeze (pagination/infinite scroll works) Performance test
AC-10 Screen is accessible โ€” passes Lighthouse Accessibility score โ‰ฅ 90 Automated

๐Ÿ”— Dependencies & Open Questions

# Question Owner Status
1 Should the filter icon (top-right) be completely hidden or greyed out/disabled in this sprint? PM (Rahul) Open
2 Do we show a photo thumbnail on the card? (Not in wireframe, but improves scannability) Design Open
3 What is the sort order โ€” reported date DESC or last updated DESC? PM (Rahul) Open
4 Is there a maximum number of reports a citizen can have? (impacts pagination design) Backend Open
5 Should REJECTED status be shown, or are rejected reports hidden from the citizen view? PM (Rahul) Open โ€” needs policy decision

โœ… Definition of Done

  • All 10 ACs pass QA sign-off
  • Design reviewed against wireframe โ€” no deviations without PM approval
  • Unit tests for useMyReports hook (loading, success, error, empty states)
  • Component tests for StatusBadge covering all 5 status variants
  • Lighthouse Accessibility score โ‰ฅ 90 on the screen
  • No hardcoded strings โ€” all labels via i18n keys
  • Skeleton, empty state, and error state all implemented and reviewed
  • thumbnailUrl gracefully degrades if missing (no broken image icons)


Files

screen.png (147 KB) screen.png Islam Mansoori, 03/17/2026 08:21 AM
Actions #1

Updated by zaid ali 5 days ago

  • Status changed from To Do to Backend completed
  • Assignee changed from Hamdan Iftikhar to Tayyab Khan
  • % Done changed from 0 to 100
Actions

Also available in: Atom PDF