Skip to content

Update Search Reports #1

Open
Nivetha-2501 wants to merge 1 commit into
masterfrom
nivi
Open

Update Search Reports #1
Nivetha-2501 wants to merge 1 commit into
masterfrom
nivi

Conversation

@Nivetha-2501
Copy link
Copy Markdown
Collaborator

@Nivetha-2501 Nivetha-2501 commented Jan 1, 2026

…y's Reports filtering

Summary by CodeRabbit

  • New Features
    • Added pagination controls with customizable page size for browsing reports
    • Enhanced search and filtering capabilities across multiple fields
    • Expanded pagination UI displaying result range, total count, and navigation controls
    • Improved status badge rendering for better clarity

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 1, 2026

📝 Walkthrough

Walkthrough

The PR adds server-side pagination support to report fetching via updated getReports action signature with page/pageSize parameters, pagination metadata response, and consolidated filtering logic. A corresponding client-side pagination UI component integrates pagination state management and user controls in the search page.

Changes

Cohort / File(s) Summary
Server-side pagination logic
src/app/actions/billActions.ts
Updated getReports signature to accept page, pageSize, searchTerm, and date parameters. Implemented pagination offset computation, total count tracking, and pagination metadata (totalCount, totalPages) in response. Refactored filtering to consolidate date and searchTerm logic with .or() queries across patient fields. Results now ordered by created_at descending with range limiting.
Client-side pagination UI and state
src/app/dashboard/lab/search/page.tsx
Added page, pageSize, and pagination state variables. Updated fetchReports to accept and pass pagination parameters to getReports, then update pagination state from response. Modified useEffect to depend on page/pageSize and re-fetch on pagination changes. Added handlePageChange function with bounds validation. Enhanced UI with Pagination component displaying range, total count, page size selector, and Prev/Next controls. Page size changes reset to page 1 and trigger immediate fetch. Simplified status badge rendering logic.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Component as search/page.tsx
    participant Action as getReports (server)
    participant DB as Database/API

    User->>Component: Navigate/change page or page size
    Component->>Component: Update pagination state
    Component->>Component: Compute fetch params (page, pageSize, searchTerm)
    Component->>Action: fetchReports(page, pageSize, term)
    activate Action
    Action->>Action: Compute from/to offsets
    Action->>DB: Query bills with filters & range
    DB-->>Action: Return bills + total count
    Action->>Action: Map & flatten results
    Action-->>Component: Return { reports, pagination: { totalCount, totalPages, ... } }
    deactivate Action
    Component->>Component: Update pagination state from response
    Component->>Component: Re-render with new results & pagination controls
    Component-->>User: Display paginated results & controls
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop through pages, quick and neat,
Pagination makes the search complete!
Filters dance with pagination's grace,
Bills sorted swift in every place. 🔍✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Update Search Reports' is vague and generic, lacking specificity about the main changes (pagination, enhanced search, filtering fixes). Consider revising the title to be more specific, such as 'Add pagination and enhance search functionality to Reports' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link
Copy Markdown

@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

🧹 Nitpick comments (2)
src/app/dashboard/lab/search/page.tsx (2)

43-45: Consider adding missing dependencies or using useCallback.

The useEffect references fetchReports and searchTerm but they're not in the dependency array. While the current behavior works as intended, this will trigger ESLint's react-hooks/exhaustive-deps warning.

Consider wrapping fetchReports in useCallback or restructuring to satisfy the exhaustive-deps rule.


199-221: Pagination ellipsis logic may produce inconsistent results.

The windowing logic on lines 202-206 can produce unexpected output (e.g., multiple consecutive ellipses or missing page numbers near boundaries). Consider a cleaner approach:

🔎 Alternative pagination window approach
const renderPageButtons = () => {
    const pages: (number | string)[] = [];
    const total = pagination.totalPages;
    const current = page;

    if (total <= 7) {
        for (let i = 1; i <= total; i++) pages.push(i);
    } else {
        pages.push(1);
        if (current > 3) pages.push('...');
        for (let i = Math.max(2, current - 1); i <= Math.min(total - 1, current + 1); i++) {
            pages.push(i);
        }
        if (current < total - 2) pages.push('...');
        pages.push(total);
    }

    return pages.map((p, idx) =>
        typeof p === 'string' ? (
            <span key={`ellipsis-${idx}`} className="px-1">...</span>
        ) : (
            <button key={p} onClick={() => handlePageChange(p)} className={...}>
                {p}
            </button>
        )
    );
};
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 994631d and fba7aa8.

📒 Files selected for processing (2)
  • src/app/actions/billActions.ts
  • src/app/dashboard/lab/search/page.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/dashboard/lab/search/page.tsx (1)
src/app/actions/billActions.ts (1)
  • getReports (126-207)
🔇 Additional comments (9)
src/app/actions/billActions.ts (5)

126-135: Function signature and pagination setup look good.

The updated signature cleanly supports pagination with sensible defaults. The from/to calculation for Supabase's range() is correct.


157-162: Timezone assumption in date filtering.

The hardcoded T00:00:00.000Z and T23:59:59.999Z suffixes assume UTC storage. If created_at is stored in UTC but users expect local-date filtering, records near midnight boundaries may be unexpectedly included or excluded. Consider whether this matches your database timezone configuration and user expectations.


171-175: Query execution is correctly structured.

The ordering, range limiting, and count extraction are properly implemented.


177-188: Good defensive handling for missing patient data.

The || '' fallback and .trim() ensure graceful handling when patient fields are missing.


190-202: Pagination metadata response is well-structured.

The calculation handles edge cases correctly, and the response shape aligns with the frontend's expectations.

src/app/dashboard/lab/search/page.tsx (4)

13-20: Pagination state initialization is correct.

The initial state values match the defaults in getReports and provide a consistent starting point.


22-41: Fetch function is well-structured with flexible parameters.

Good approach allowing explicit overrides while defaulting to current state values.


47-57: Search and pagination handlers are correctly implemented.

Resetting to page 1 on new search and validating page bounds are good UX practices.


139-146: Status badge styling is clean and handles unknown statuses gracefully.

Good use of a fallback style for any status not explicitly handled.

Comment on lines +164 to +169
// Handle search term
if (searchTerm) {
// Search across reg_number, or patient fields
// Using .or() with nested filters for patients. Note: for joins, syntax is 'relation.column'
query = query.or(`reg_number.ilike.%${searchTerm}%,patient_id.in.(select id from patients where first_name ilike '%${searchTerm}%' or last_name ilike '%${searchTerm}%' or uhid ilike '%${searchTerm}%')`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

SQL injection vulnerability via unsanitized searchTerm.

The searchTerm is directly interpolated into the .or() filter string, including a nested select subquery. A malicious input like %'); DELETE FROM patients; -- could potentially exploit this.

Even if Supabase/PostgREST provides some escaping, directly embedding user input into query strings is unsafe. Consider:

  1. Sanitizing/escaping special characters (%, ', ), etc.) from searchTerm
  2. Using a database function or RPC call for complex searches
  3. Performing separate queries and merging results in application code
🔎 Minimal sanitization approach
    // Handle search term
    if (searchTerm) {
+     // Escape special characters to prevent injection
+     const sanitized = searchTerm.replace(/[%_'\\()]/g, '\\$&');
      // Search across reg_number, or patient fields
      // Using .or() with nested filters for patients. Note: for joins, syntax is 'relation.column'
-     query = query.or(`reg_number.ilike.%${searchTerm}%,patient_id.in.(select id from patients where first_name ilike '%${searchTerm}%' or last_name ilike '%${searchTerm}%' or uhid ilike '%${searchTerm}%')`);
+     query = query.or(`reg_number.ilike.%${sanitized}%,patient_id.in.(select id from patients where first_name ilike '%${sanitized}%' or last_name ilike '%${sanitized}%' or uhid ilike '%${sanitized}%')`);
    }

However, a safer architectural approach would be to use a Supabase RPC function with parameterized queries.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Handle search term
if (searchTerm) {
// Search across reg_number, or patient fields
// Using .or() with nested filters for patients. Note: for joins, syntax is 'relation.column'
query = query.or(`reg_number.ilike.%${searchTerm}%,patient_id.in.(select id from patients where first_name ilike '%${searchTerm}%' or last_name ilike '%${searchTerm}%' or uhid ilike '%${searchTerm}%')`);
}
// Handle search term
if (searchTerm) {
// Escape special characters to prevent injection
const sanitized = searchTerm.replace(/[%_'\\()]/g, '\\$&');
// Search across reg_number, or patient fields
// Using .or() with nested filters for patients. Note: for joins, syntax is 'relation.column'
query = query.or(`reg_number.ilike.%${sanitized}%,patient_id.in.(select id from patients where first_name ilike '%${sanitized}%' or last_name ilike '%${sanitized}%' or uhid ilike '%${sanitized}%')`);
}

Comment on lines +176 to +183
<select
value={pageSize}
onChange={(e) => {
const newSize = Number(e.target.value);
setPageSize(newSize);
setPage(1);
fetchReports(1, newSize, searchTerm);
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Double fetch when changing page size.

The onChange handler calls fetchReports(1, newSize, searchTerm) directly, but also updates page and pageSize state. The useEffect on line 43-45 will trigger another fetch on the next render when these state values change, causing redundant API calls.

🔎 Suggested fix: remove the direct fetch call
                            <select
                                value={pageSize}
                                onChange={(e) => {
                                    const newSize = Number(e.target.value);
                                    setPageSize(newSize);
                                    setPage(1);
-                                   fetchReports(1, newSize, searchTerm);
                                }}
                                className="text-sm border rounded px-2 py-1 bg-white"
                            >

The useEffect will handle the fetch when page and pageSize state update.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<select
value={pageSize}
onChange={(e) => {
const newSize = Number(e.target.value);
setPageSize(newSize);
setPage(1);
fetchReports(1, newSize, searchTerm);
}}
<select
value={pageSize}
onChange={(e) => {
const newSize = Number(e.target.value);
setPageSize(newSize);
setPage(1);
}}
🤖 Prompt for AI Agents
In src/app/dashboard/lab/search/page.tsx around lines 176 to 183, the select
onChange handler triggers fetchReports(1, newSize, searchTerm) directly while
also updating page and pageSize state, causing a duplicate API call because the
useEffect watching page/pageSize will fetch again; remove the direct
fetchReports(...) call from the onChange handler so the state updates
(setPage(1) and setPageSize(newSize)) drive the single fetch via the existing
useEffect.

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