Skip to content

[ENG-500] Support for creating multiple diagnostic reports in a service request - #16455

Open
NikhilA8606 wants to merge 33 commits into
developfrom
ENG-500-support-for-creating-multiple-diagnostic-reports-in-a-service-request
Open

[ENG-500] Support for creating multiple diagnostic reports in a service request#16455
NikhilA8606 wants to merge 33 commits into
developfrom
ENG-500-support-for-creating-multiple-diagnostic-reports-in-a-service-request

Conversation

@NikhilA8606

@NikhilA8606 NikhilA8606 commented Jun 16, 2026

Copy link
Copy Markdown
Member

Proposed Changes

ENG-500
Figma link: https://www.figma.com/design/Z93EYKSa1MdBmXndsMBJSQ/Care---Master?node-id=40865-19149&t=94gI7vbM9r8kx6hY-1

Screen record:

Screen.Recording.2026-06-16.at.11.31.07.AM.mov

Merge Checklist

  • Add specs that demonstrate the bug or test the new feature.
  • Update product documentation.
  • Ensure that UI text is placed in I18n files.
  • Prepare a screenshot or demo video for the changelog entry and attach it to the issue.
  • Request peer reviews.
  • Complete QA on mobile devices.
  • Complete QA on desktop devices.
  • Add or update Playwright tests for related changes

Summary by CodeRabbit

Release Notes

  • New Features
    • Create and review multiple diagnostic reports in the same workflow, with per-report editing and approval.
  • Improvements
    • Report creation now checks specimen readiness and provides guidance when required items are missing.
    • Updated save/approve behavior for preliminary vs final reports, including clearer enabled/disabled states, improved loading behavior, and more precise file/result handling.
  • Localization
    • Updated English text with new prompts for report type selection and clearer error/success messages (including {{error}} details).

@NikhilA8606
NikhilA8606 requested review from a team and Copilot June 16, 2026 06:02
@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit f15ef2e
🔍 Latest deploy log https://app.netlify.com/projects/care-ohc/deploys/6a4dfbe9ab92590008f33bb9
😎 Deploy Preview https://deploy-preview-16455.preview.ohc.network
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Updates diagnostic report creation and review to operate per report entry, with status-gated editing, per-report queries and mutations, upload input IDs, and new locale strings for report creation, approval, and review states.

Changes

Diagnostic Report Multi-Report Refactor

Layer / File(s) Summary
i18n strings
public/locale/en.json
Adds another_diagnostic_report, failed_to_approve_diagnostic_report, failed_to_save_test_results, review_test_results, select_report_type_to_create, and test_results_saved_successfully; updates failed_to_create_diagnostic_report and result_review.
Service request report filtering
src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx
Filters out final diagnostic reports for the form and always renders DiagnosticReportForm when observation requirements exist.
File upload input id
src/hooks/useFileUpload.tsx
Adds optional inputId to the hook options and uses it for the file input element when provided.
Diagnostic report form container
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx
Reworks the form around collected-specimen and multi-code state, renders existing reports directly, gates creation, and rewrites the collapsed create form for multi-report selection.
Diagnostic report item save flow
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx
Binds conclusion and file mutations to report.id, updates submit behavior, clears upload state on close, and narrows submission state to mutation activity.
Diagnostic report item UI
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx
Updates item headers and status badges from the current report, and gates editing, upload controls, and saved-results actions by report status.
Diagnostic report review items
src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx
Renders a review item per diagnostic report, fetches full report/files per item, and uses report-detail state for approval, conclusion editing, and review visibility.

Suggested labels

Type Changes

Suggested reviewers

  • Jacobjeevan
  • nihal467
  • amjithtitus09
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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
Title check ✅ Passed The title clearly states the main feature: multiple diagnostic reports in a service request.
Description check ✅ Passed The description includes the issue reference, design/screen-record links, and the merge checklist required by the template.
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 ENG-500-support-for-creating-multiple-diagnostic-reports-in-a-service-request

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the Service Request diagnostic report workflow to support multiple diagnostic reports per request, updating both the entry form and the review UI to render and operate on each report independently.

Changes:

  • Render diagnostic report entry/review UI as a list of per-report components instead of only using the latest report.
  • Add UI for creating additional diagnostic reports (with optional report-type selection based on activityDefinition.diagnostic_report_codes).
  • Update/enhance i18n strings to support the new UI text.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Refactors review UI to render one collapsible review panel per diagnostic report and adjusts queries/actions per report.
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Refactors entry UI to render one collapsible form per report and adds UI to create additional reports (with report-type selection).
public/locale/en.json Adds/updates translation strings for the multi-report workflow UI.
Comments suppressed due to low confidence (1)

src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx:1240

  • With multiple diagnostic reports rendered, reusing id="conclusion" / htmlFor="conclusion" creates duplicate IDs and breaks label association for assistive tech. Make the conclusion field IDs unique per report.
                      <Label
                        htmlFor="conclusion"
                        className="text-base font-semibold text-gray-950"
                      >
                        {t("conclusion")}

Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Outdated
Comment thread public/locale/en.json Outdated
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR extends the diagnostic report workflow to support multiple concurrent reports per service request, each with its own edit card, approval flow, and print route. The old single-report form is decomposed into a DiagnosticReportItem (per active report) and a CreateDiagnosticReportForm (first-report creation or adding additional coded reports).

  • DiagnosticReportForm and DiagnosticReportReview are both split into per-item sub-components with independent state, queries, and per-report-scoped element ids (file input fixed; see inline comment for conclusion textarea).
  • New DiagnosticReportPreview component consolidates the print view for one or all reports; DiagnosticReportPrint is updated to route to it from two new URL patterns.
  • WorkflowProgress strings are i18n'd, sort order is reversed to latest-first, and a "Latest" badge marks the most recent event.

Confidence Score: 4/5

Safe to merge with a minor fix: the conclusion textarea in DiagnosticReportItem uses a hardcoded id that duplicates across cards in multi-report mode.

The multi-report refactor is well-structured. Per-report element ids were correctly scoped for file inputs and the review form conclusion field, but the edit form conclusion textarea still uses id=conclusion for every card. This only manifests when two or more preliminary reports are open simultaneously, causing the label to target the wrong textarea. Everything else including routing, query invalidation, state isolation, and i18n looks correct.

Files Needing Attention: src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx — conclusion textarea id needs to be scoped per-report the same way DiagnosticReportReview already does it.

Important Files Changed

Filename Overview
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Major refactor splitting the old single-report form into DiagnosticReportItem (per-report card with its own state/queries) and a new CreateDiagnosticReportForm. File upload ids are now scoped per-report, but the conclusion textarea still uses a hardcoded id that will duplicate when multiple preliminary reports are open.
src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Refactored into a container + per-item DiagnosticReportReviewItem; conclusion correctly initialised from report prop and scoped ids used.
src/pages/Facility/services/diagnosticReports/DiagnosticReportPreview.tsx New component extracted from DiagnosticReportPrint; handles multi-report print preview with per-item file URL fetching.
src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx Simplified to delegate rendering to DiagnosticReportPreview; now supports both single-report and all-reports print routes.
src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx Updated for multiple diagnostic reports: hasFinalizedReport/hasPendingReports completion gating and new all-reports print route.
src/Routers/routes/FacilityRoutes.tsx Old per-report print route replaced with two new service_request-scoped routes.
src/hooks/useFileUpload.tsx Added optional inputId prop to allow unique file input ids per card.
src/components/Files/FileUploadDialog.tsx Added instanceId prop to prefix all internal element ids, fixing duplicate-id collisions.
public/locale/en.json Added locale keys for new multi-report workflow; removed unused result_review and failed_to_update_conclusion keys.

Reviews (24): Last reviewed commit: "used DR api instead of getting it from ..." | Re-trigger Greptile

Comment thread public/locale/en.json Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Outdated
Comment thread public/locale/en.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx (1)

369-371: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Bug: toast.success used in error handler should be toast.error.

The onError callback incorrectly uses toast.success to display the failure message, which will show a success toast for an error condition.

      onError: () => {
-       toast.success(t("failed_to_update_conclusion"));
+       toast.error(t("failed_to_update_conclusion"));
      },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx`
around lines 369 - 371, In the onError callback within DiagnosticReportForm
component, replace the toast.success call with toast.error to properly display
an error notification when the conclusion update fails. This ensures that error
conditions show error toasts rather than success toasts to users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@public/locale/en.json`:
- Line 5071: Fix the spelling error in the review_test_results string value
where "Reult" is misspelled. Change it to "Result" so the user-facing string
reads "Review Test Result" instead of "Review Test Reult".
- Line 5537: The select_report_type_to_create string in the locale file is
grammatically awkward and confusing due to the repetition and unclear phrasing.
Rewrite this user-facing instruction to be clear and grammatically correct. The
new text should clearly tell users to select a diagnostic report type and then
create a report, without awkward quotation marks or repeated words, using simple
and direct language that guides the user action.

In
`@src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx`:
- Around line 158-162: Replace all hardcoded English toast message strings with
translation keys using the t() function in DiagnosticReportForm.tsx. At lines
158-162 in the onError handler within the mutation, replace the hardcoded
failure message string with a call to t() using the key
"failed_to_create_diagnostic_report" and pass the error message as a parameter.
At lines 338-351, replace the hardcoded success message "Test results saved
successfully" with t("test_results_saved_successfully") and replace the
hardcoded failure message string in the error handler with a call to t() using
the key "failed_to_save_test_results" and pass the error message as a parameter.
For both locations, use t("unknown_error") as a fallback when the error message
is unavailable, consistent with i18n requirements.
- Around line 733-747: The upsertObservations and updateDiagnosticReport
mutations are executed sequentially without coordination, causing them to run in
parallel. If upsertObservations fails, updateDiagnosticReport will still
execute, leaving the diagnostic report in an inconsistent state. Fix this by
ensuring updateDiagnosticReport only executes after upsertObservations succeeds.
Either use mutateAsync with await to chain the mutations, or move the
updateDiagnosticReport call into the onSuccess callback of the
upsertObservations mutation. This ensures data consistency by preventing
updateDiagnosticReport from executing if the observations upsert operation
fails.
- Around line 1306-1312: The variables hasCollectedSpecimens and
isMultipleDiagnosticReport are being computed identically in both the parent
component and the DiagnosticReportForm child component. To follow DRY principles
and ensure consistency, remove the duplicate computations from
DiagnosticReportForm (the const declarations for hasCollectedSpecimens based on
activityDefinition.specimen_requirements and specimens, and
isMultipleDiagnosticReport based on activityDefinition.diagnostic_report_codes).
Instead, compute these values once in the parent component and pass them as
props to DiagnosticReportForm. Update the DiagnosticReportForm component
signature to accept these two values as props and use the passed-in values
instead of computing them locally.

In
`@src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx`:
- Around line 206-208: The Badge component and status-driven actions (render
gates for "view report" and approve actions) in DiagnosticReportReview.tsx are
using report.status from the stale list data instead of the fresher reportDetail
object. Replace report.status with the status from reportDetail at lines 206-208
and also at lines 294-331 where similar status checks are used for conditional
rendering and actions, ensuring all UI elements reflect the fetched detail data
consistently rather than potentially stale source data.
- Around line 163-167: The empty-state check for observations in the condition
block does not filter out ENTERED_IN_ERROR observations, while the table that
renders those observations applies this filter. This causes reports containing
only entered-in-error observations to display as non-empty with blank results.
Update the observation length check in the condition to filter out any
observations with ENTERED_IN_ERROR status before evaluating the length, matching
the filtering logic applied to the table rendering below. Apply the same
filtering logic at all affected locations where the raw observation length is
evaluated to determine visibility.
- Around line 102-106: The conclusion input field at line 267 (and related area
at lines 266-268) uses a fallback value logic that re-injects the server value
when the user clears the field, preventing empty edits from being representable
in UI state. Remove the fallback to reportDetail.conclusion in the value prop of
the input field—change the value binding from value={conclusion ||
reportDetail.conclusion || ""} to value={conclusion || ""} so that when users
clear the conclusion field, the empty state persists without being overwritten
by the server value.
- Around line 144-147: The toast.error call in the onError handler of
DiagnosticReportReview.tsx is using hardcoded English strings instead of i18next
translation keys. Add two new translation keys to public/locale/en.json: one for
the main error message template that accepts an error parameter (like
"diagnostic_report_approve_failed"), and one for the fallback unknown error text
(like "unknown_error"). Then update the toast.error call in the onError handler
to use i18next.t() to retrieve the localized message, passing the error text as
a parameter to the translation template.

---

Outside diff comments:
In
`@src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx`:
- Around line 369-371: In the onError callback within DiagnosticReportForm
component, replace the toast.success call with toast.error to properly display
an error notification when the conclusion update fails. This ensures that error
conditions show error toasts rather than success toasts to users.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bf6bbacd-e990-42e4-a76b-8cf598ade0b9

📥 Commits

Reviewing files that changed from the base of the PR and between 5466816 and 5fcab8e.

📒 Files selected for processing (3)
  • public/locale/en.json
  • src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx
  • src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx

Comment thread public/locale/en.json Outdated
Comment thread public/locale/en.json Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportForm.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx Outdated
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

🎭 Playwright Test Results

Status: ❌ Failed
Test Shards: 3

Metric Count
Total Tests 337
✅ Passed 333
❌ Failed 2
⏭️ Skipped 2

📊 Detailed results are available in the playwright-final-report artifact.

Run: #10565

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deploying care-preview with  Cloudflare Pages  Cloudflare Pages

Latest commit: cfcaa11
Status: ✅  Deploy successful!
Preview URL: https://faac5c4d.care-preview-a7w.pages.dev
Branch Preview URL: https://eng-500-support-for-creating.care-preview-a7w.pages.dev

View logs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

@nihal467 nihal467 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

look into the AI review

@yash-learner yash-learner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

File upload is broken in ServiceRequest page can you fix it

@yash-learner yash-learner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@NikhilA8606

@aravindm4 mentioned we should only allow one diagnostic report per code

<div className="mt-8 border-t border-gray-300 pt-6">
{/* Report header with per-report details */}
<div className="break-inside-avoid">
<h2 className="text-lg font-semibold mb-3">{report.code?.display}</h2>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you think, is it good to show the report status as well in the print ? -> Preliminary or Final

@yash-learner

Copy link
Copy Markdown
Member
image

if we mark a service request as entered in error/cancelled state we are not showing that in the timeline

if you think if it already present on develop and if you're planning to fix in this PR, file a separate Jira ticket

@yash-learner

Copy link
Copy Markdown
Member
image

I think Diagnostic Report in Progress should be the latest one instead of the instead of diagnostic report created in the timeline

https://www.figma.com/design/Z93EYKSa1MdBmXndsMBJSQ/Care---Master?node-id=42386-49306&t=MVOU11D9M5muJfm0-4

@yash-learner yash-learner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Image

We do not have this button in new design, it is below

and also this button shows up even when all reports not final


On the encounter diagnostic report path -> The diagnostic reports of a service request does not show actual diagnostic report name/code it just showing test results

Image

Comment thread src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx Outdated
Comment thread src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx
@NikhilA8606

Copy link
Copy Markdown
Member Author

if we mark a service request as entered in error/cancelled state we are not showing that in the timeline

if you think if it already present on develop and if you're planning to fix in this PR, file a separate Jira ticket

it is not present in develop

@NikhilA8606

Copy link
Copy Markdown
Member Author

We do not have this button in new design, it is below

and also this button shows up even when all reports not final

I discussed this with @gauritejusa, and we decided to keep the View All Reports button only at the top. It doesn't need to be shown at the bottom as well. We also decided that the button should be displayed even when there is only a single report. This was discussed and confirmed with the product team.

@NikhilA8606

Copy link
Copy Markdown
Member Author

On the encounter diagnostic report path -> The diagnostic reports of a service request does not show actual diagnostic report name/code it just showing test results

This is the existing behavior in develop as well and is not related to this PR.

@yash-learner

yash-learner commented Jul 23, 2026

Copy link
Copy Markdown
Member

On the encounter diagnostic report path -> The diagnostic reports of a service request does not show actual diagnostic report name/code it just showing test results

This is the existing behavior in develop as well and is not related to this PR.

Because previously we had only one diagnostic report per Service Request and now we support multiple so I think it is good to show because without that how would some distinguish which report is which ? check with Product

@yash-learner

Copy link
Copy Markdown
Member

On the encounter diagnostic report path -> The diagnostic reports of a service request does not show actual diagnostic report name/code it just showing test results

This is the existing behavior in develop as well and is not related to this PR.

But in develop we do not have latest badge right now we have Latest badge in front of the event so that is misleading when SR is actually cancelled

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

tests/facility/patient/encounter/serviceRequests/ServiceRequestCreate.spec.ts:182

  • Using await reportTypeSelect.count() to decide whether to expand the card can be flaky because locator.count() doesn't auto-wait for the dropdown to appear. If the dropdown is still rendering, the count can momentarily be 0 and the extra click may collapse the card, causing intermittent failures. Prefer attempting the click and only expanding on timeout/failure.
    // reveal the report-type dropdown before interacting with it.
    if ((await reportTypeSelect.count()) === 0) {
      await page.getByText("Test Results Entry").click();
    }
    await reportTypeSelect.click();

src/pages/Encounters/tabs/diagnostic-reports.tsx:174

  • buildEncounterUrl(...) falls back to the organization route when facilityId is undefined, but the new print route is only registered under facility routes. In org-context encounter pages this would navigate to /organization/organizationId/.../service_request/.../diagnostic_report/.../print, which has no matching route. Use the report's encounter facility id as a fallback so printing works from both contexts.
                        facilityId,

src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx:173

  • This effect always overwrites the local conclusion state when the full report finishes loading. If a user starts typing before the detail query resolves, their input can be reset back to the server value (often empty) mid-edit. Only sync from the server when the user hasn’t changed the field yet (e.g., when the local value is still empty or equals the initial report conclusion).
  useEffect(() => {
    setConclusion(reportDetail?.conclusion || "");
  }, [reportDetail?.conclusion]);

src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx:633

  • The new behavior disables “Mark as complete” while any diagnostic reports are still pending final review. There isn’t Playwright coverage validating that (a) multiple reports can be created and (b) the completion CTA stays disabled until all reports are finalized. Adding an E2E spec (or extending the existing ServiceRequestCreate spec) would prevent regressions in this workflow.
                disabled={isCompletingServiceRequest || hasPendingReports}

@NikhilA8606

Copy link
Copy Markdown
Member Author

But in develop we do not have latest badge right now we have Latest badge in front of the event so that is misleading when SR is actually cancelled

As discussed, we can keep the existing behavior from develop.

@NikhilA8606

NikhilA8606 commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

Because previously we had only one diagnostic report per Service Request and now we support multiple so I think it is good to show because without that how would some distinguish which report is which ? check with Product

nice finding. https://openhealthcarenetwork.atlassian.net/browse/ENG-500?focusedCommentId=12420

@rithviknishad rithviknishad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

simply use service_request filter instead to fetch required diagnostic reports?

@NikhilA8606

Copy link
Copy Markdown
Member Author

simply use service_request filter instead to fetch required diagnostic reports?

I intentionally avoided that API because, for superusers, it fetches all patient records without any filtering. As we discussed, I'm avoiding that use case for now and using the retrieve API instead, since this is the existing behavior across CARE.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx:173

  • This effect resets conclusion whenever the full report loads. If a user starts typing before the detail query resolves, their input can be overwritten. It’s safer to only sync from the fetched report when the user hasn’t edited the field yet.
  useEffect(() => {
    setConclusion(reportDetail?.conclusion || "");
  }, [reportDetail?.conclusion]);

tests/facility/patient/encounter/serviceRequests/ServiceRequestCreate.spec.ts:182

  • This spec updates interactions for the report-type dropdown, but it still only validates creating a single diagnostic report. Since this PR adds support for multiple diagnostic reports per service request (including completion being blocked when reports are pending), add Playwright coverage for creating at least two reports and verifying the expected review/print/complete behavior.
    const reportTypeSelect = page
      .getByRole("combobox")
      .filter({ hasText: "Select Diagnostic Report Type" });
    // The "Test Results Entry" card is collapsed by default; expand it to
    // reveal the report-type dropdown before interacting with it.
    if ((await reportTypeSelect.count()) === 0) {
      await page.getByText("Test Results Entry").click();
    }
    await reportTypeSelect.click();

src/pages/Facility/services/serviceRequests/components/WorkflowProgress.tsx:205

  • WorkflowProgress currently pushes two timeline events per diagnostic report (the status event in the first loop and a separate "created" event in the second). For preliminary reports both events use created_date, which produces duplicate entries with the same timestamp and title/meaning. Consider only adding the extra "created" entry for finalized reports (or otherwise de-duplicating).
  // Add diagnostic report events
  request.diagnostic_reports?.forEach((report: DiagnosticReportRead) => {
    events.push({
      title: t("diagnostic_report_created"),
      description: t("diagnostic_report_created_description", {

src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx:50

  • DiagnosticReportPrint can briefly render "service_request_not_found" while the service request query is still loading, because only the diagnostic report queries are included in the loading gate. Include the service request query's loading state in the loading check so we don't show a not-found state prematurely.
  const { data: request } = useQuery({
    queryKey: ["serviceRequest", facilityId, serviceRequestId],
    queryFn: query(serviceRequestApi.retrieveServiceRequest, {
      pathParams: {
        facilityId: facilityId,

src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx:72

  • When there are no finalized diagnostic reports for the service request, diagnosticReports becomes an empty array (truthy) and the component renders an empty preview instead of the "no_diagnostic_reports_found" state. Treat an empty array as "not found" here.
  if (!diagnosticReports) {
    return <div>{t("no_diagnostic_reports_found")}</div>;
  }

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

src/pages/Facility/services/serviceRequests/components/DiagnosticReportReview.tsx:173

  • This effect will overwrite the user’s in-progress edits to the conclusion when fullReport finishes loading (because reportDetail.conclusion changes), causing typed text to disappear. The conclusion should only be initialized from fetched data when the user hasn’t modified it yet.
  useEffect(() => {
    setConclusion(reportDetail?.conclusion || "");
  }, [reportDetail?.conclusion]);

tests/facility/patient/encounter/serviceRequests/ServiceRequestCreate.spec.ts:184

  • This PR adds a new user-facing workflow for creating multiple diagnostic reports, but this spec still only exercises a single-report creation path. Adding an E2E assertion that the “Another Diagnostic Report” flow works (create a second report, verify both report cards appear, and that completion is blocked until all are final) would prevent regressions.
    const reportTypeSelect = page
      .getByRole("combobox")
      .filter({ hasText: "Select Diagnostic Report Type" });
    // The "Test Results Entry" card is collapsed by default; expand it to
    // reveal the report-type dropdown before interacting with it.
    if ((await reportTypeSelect.count()) === 0) {
      await page.getByText("Test Results Entry").click();
    }
    await reportTypeSelect.click();
    await page.getByRole("option").first().click();
    await page.getByRole("button", { name: "Create Report" }).click();

src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx:54

  • serviceRequest is fetched via useQuery, but its loading state isn’t included in the early-loading guard. This can briefly render service_request_not_found while the request query is still in-flight. Also, the diagnosticReports guard only checks for undefined; if the list query returns an empty array, the UI will render an empty preview instead of no_diagnostic_reports_found.
  const { data: request } = useQuery({
    queryKey: ["serviceRequest", facilityId, serviceRequestId],
    queryFn: query(serviceRequestApi.retrieveServiceRequest, {
      pathParams: {
        facilityId: facilityId,
        serviceRequestId: serviceRequestId,
      },
    }),
  });

@nihal467 nihal467 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Image
  • the requested by data is missing in the view full report (Cumulative Report) in the SR, can you verify what should be shown here

</div>
<DiagnosticReportPreview
diagnosticReports={diagnosticReports}
isLoading={isLoadingReport || isLoadingReports}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Suppressed comments (4)

tests/facility/patient/encounter/serviceRequests/ServiceRequestCreate.spec.ts:182

  • After expanding the "Test Results Entry" card, the test clicks the report-type combobox immediately. This can be flaky if the dropdown renders asynchronously (or if multiple comboboxes match). Add an assertion that the locator exists before clicking, and click a single element explicitly.
    if ((await reportTypeSelect.count()) === 0) {
      await page.getByText("Test Results Entry").click();
    }
    await reportTypeSelect.click();

src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx:55

  • The print view fetches full details for every diagnostic report returned by listDiagnosticReports, but later only prints final reports. Filtering to final before useQueries() avoids unnecessary network requests when there are preliminary/in-progress reports.
  const { allDiagnosticReports, isLoading: isLoadingReports } = useQueries({
    queries:
      diagnosticReportResults?.map((report) => ({
        queryKey: ["diagnosticReport", report.id, patientId, facilityId],
        queryFn: query(diagnosticReportApi.retrieveDiagnosticReport, {

src/pages/Facility/services/serviceRequests/components/WorkflowProgress.tsx:205

  • This adds a second diagnostic-report timeline entry for every report (“created” + “in progress/approved”). For non-final reports, both entries use created_date, so the timeline will show near-duplicate items with identical timestamps. Consider only adding the “created” event once a report is finalized (or otherwise ensure timestamps differ).
  // Add diagnostic report events
  request.diagnostic_reports?.forEach((report: DiagnosticReportRead) => {
    events.push({
      title: t("diagnostic_report_created"),
      description: t("diagnostic_report_created_description", {

src/pages/Facility/services/diagnosticReports/DiagnosticReportPrint.tsx:98

  • diagnosticReports is always an array here, so if (!diagnosticReports) never triggers. This means an empty result set (or an invalid diagnosticReportId where fullReport is undefined) will fall through and render the preview with zero reports. Check for diagnosticReports.length === 0, and add an explicit guard for diagnosticReportId && !fullReport to show a not-found state.
  if (!diagnosticReports) {
    return <div>{t("no_diagnostic_reports_found")}</div>;
  }

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

The feature direction is reasonable — multiple diagnostic reports per service request is a legitimate need, and most of the refactoring (splitting DiagnosticReportForm into DiagnosticReportItem, extracting DiagnosticReportPreview, per-report file upload IDs) is sound. The useQueries pattern in DiagnosticReportPrint.tsx is the right approach.

However, there are a few real bugs and code quality issues that need addressing before merge:

  1. {} as any in DiagnosticReportPreview.tsx — calling a React Query factory imperatively with a fake context. This bypasses the type system and is fragile. Should use useQueries or direct API calls.
  2. Missing getFileUrl in useEffect deps (DiagnosticReportPreview.tsx:251) — stale closure waiting to cause subtle bugs.
  3. Dead code guard (DiagnosticReportPrint.tsx:96) — if (!diagnosticReports) is always false.
  4. Silent empty print when all reports are preliminary in the all-reports print route — this needs either documentation or a user-facing message.
  5. const { data: data } — proofreading issue.
  6. eslint-disable silencing missing deps — either justify it with a comment or fix the actual issue.

The window.innerWidth issue in PDFRenderer is a minor annoyance for a print-only component, but test environments will give you 0px pages.

Fix the {} as any and the dead code at minimum. The rest are code quality issues that'll cause head-scratching later.

Generated by Grumpy PR Reviewer for issue #16455 · 100.7 AIC · ⌖ 6.35 AIC · ⊞ 6.3K

} catch (error) {
console.error("Error fetching signed URL:", error);
return null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Oh wonderful, {} as any. The gold standard of "I gave up on types." query() returns a function that expects a QueryFunctionContext, not an empty object cast to oblivion. This is calling the query factory imperatively outside of React Query — that's the actual problem. Use fetch or the API client directly for imperative calls, or restructure this to use useQueries for each file like the DiagnosticReportPrint.tsx does. Don't paper over broken abstractions with as any.

return (
<div className="p-6">
<div className="text-center text-gray-500">
{t("diagnostic_report_not_found")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

getFileUrl is defined in component scope and closes over report?.id, but it's not in the useEffect dependency array. ESLint is screaming at you and you chose to not listen. Either move getFileUrl inside the effect, wrap it in useCallback and add it to deps, or — better — refactor to useQueries like the rest of this PR does. Stale closures in effects cause bugs that are a joy to debug at 2am.

const { facility } = useCurrentFacility();

const { data: report, isLoading } = useQuery({
const { data: data } = useQuery({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

const { data: data } — really? JavaScript has had shorthand property names since ES6. This is const { data }. The redundant alias tells me this code wasn't proofread before submission.

ext.endsWith("webp")
);
});
if (!diagnosticReports) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

diagnosticReports is either [fullReport] or allDiagnosticReports.filter(...) — it is always an array, never null or undefined. This check if (!diagnosticReports) will never be true. Dead code. The error message will never display. If you want to handle the empty case, check diagnosticReports.length === 0.

const diagnosticReports = fullReport
? [fullReport]
: allDiagnosticReports.filter(
(report) => report.status === DiagnosticReportStatus.final,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

When printing "all reports" via the no-diagnosticReportId route, this silently filters to only final status reports. A user navigating to the all-reports print URL will get a blank print if all reports are preliminary. There's no error, no loading state — just nothing. Is this intentional design? If so, document it. If not, fix it.

if (!openUploadDialog) {
fileUpload.clearFiles();
}
// eslint-disable-next-line react-hooks/exhaustive-deps

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ah yes, the classic // eslint-disable-next-line react-hooks/exhaustive-deps. The lint rule is there for a reason. fileUpload.clearFiles is a function from a hook — if it's not stable (not wrapped in useCallback), omitting it from deps can cause stale references. Either ensure clearFiles is stable and document why, or add it to the deps. Don't just silence the linter and move on.

renderAnnotationLayer={false}
/>
))}
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

window.innerWidth captured during render is not reactive — resize the window and the PDF page width stays wrong. For a print view this matters less, but it also breaks in test environments where window.innerWidth is 0, making every PDF page 0px wide. At minimum, capture this in a useEffect or useMemo with a resize listener, or use a CSS-based approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants