From 2c95f32dfdf998c4a90cacca5d88803221420328 Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Tue, 10 Feb 2026 14:12:39 +0000 Subject: [PATCH 1/8] [PRMP-1337] LGR review journey adjustments (skipping the option to remove some files) --- .../ReviewDetailsAddMoreChoiceStage.test.tsx | 94 +++++++++----- .../ReviewDetailsAddMoreChoiceStage.tsx | 15 ++- .../ExistingRecordTable.tsx | 2 +- .../ReviewDetailsAssessmentStage.test.tsx | 117 ++---------------- .../ReviewDetailsAssessmentStage.tsx | 16 +-- .../PatientVerifyPage.test.tsx | 8 +- ...ectronicHealthRecordAttachmentsConfig.json | 5 +- app/src/config/lettersAndDocumentsConfig.json | 5 +- app/src/config/lloydGeorgeConfig.json | 5 +- app/src/helpers/utils/documentType.ts | 5 +- .../LloydGeorgeRecordPage.test.tsx | 4 + .../pages/privacyPage/PrivacyPage.test.tsx | 9 +- 12 files changed, 121 insertions(+), 164 deletions(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.test.tsx b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.test.tsx index fdb159e703..a5e6d4ded8 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.test.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.test.tsx @@ -1,11 +1,18 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest'; -import ReviewDetailsAddMoreChoiceStage from './ReviewDetailsAddMoreChoiceStage'; +import { afterEach, beforeEach, describe, expect, it, Mock, vi } from 'vitest'; import { runAxeTest } from '../../../../helpers/test/axeTestHelper'; +import * as documentTypeModule from '../../../../helpers/utils/documentType'; +import { ReviewDetails } from '../../../../types/generic/reviews'; +import ReviewDetailsAddMoreChoiceStage from './ReviewDetailsAddMoreChoiceStage'; +import { DOCUMENT_TYPE } from '../../../../helpers/utils/documentType'; const mockNavigate = vi.fn(); const mockReviewId = 'test-review-123'; +const testData = { + yesText: 'Yes, I have more scanned paper notes to add for this patient', + noText: "No, I don't have anymore scanned paper notes to add for this patient", +}; vi.mock('react-router-dom', async (): Promise => { const actual = await vi.importActual('react-router-dom'); @@ -16,10 +23,23 @@ vi.mock('react-router-dom', async (): Promise => { }; }); -describe('ReviewDetailsAddMoreChoicePage', () => { +describe('ReviewDetailsAddMoreChoiceStage', () => { + const mockReviewData = { + snomedCode: DOCUMENT_TYPE.LLOYD_GEORGE, + } as ReviewDetails; + beforeEach(() => { vi.clearAllMocks(); import.meta.env.VITE_ENVIRONMENT = 'vitest'; + const mockGetConfig = vi.spyOn(documentTypeModule, 'getConfigForDocType'); + mockGetConfig.mockReturnValue({ + ...documentTypeModule.getConfigForDocType(DOCUMENT_TYPE.LLOYD_GEORGE), + multifileZipped: true, + content: { + addMoreFilesRadioNoText: testData.noText, + addMoreFilesRadioYesText: testData.yesText, + }, + } as any); }); afterEach(() => { @@ -28,29 +48,29 @@ describe('ReviewDetailsAddMoreChoicePage', () => { describe('Rendering', () => { it('renders the page heading correctly', () => { - render(); + render(); expect( screen.getByRole('heading', { - name: 'Do you want to add more files to this patients record?', + name: "Do you want to add more files to this patient's record?", }), ).toBeInTheDocument(); }); it('renders back button with correct text', () => { - render(); + render(); expect(screen.getByText('Go back')).toBeInTheDocument(); }); it('renders both radio button options', () => { - render(); + render(); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); expect(yesRadio).toBeInTheDocument(); @@ -60,13 +80,13 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('renders continue button', () => { - render(); + render(); expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument(); }); it('does not show error message initially', () => { - render(); + render(); expect(screen.queryByText('Select an option')).not.toBeInTheDocument(); }); @@ -74,7 +94,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { describe('Error Handling', () => { it('displays error message when continue is clicked without selection', async () => { - render(); + render(); const continueButton = screen.getByRole('button', { name: 'Continue' }); await userEvent.click(continueButton); @@ -85,7 +105,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('does not navigate when no selection is made', async () => { - render(); + render(); const continueButton = screen.getByRole('button', { name: 'Continue' }); await userEvent.click(continueButton); @@ -97,7 +117,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('clears error message when yes radio button is selected', async () => { - render(); + render(); const continueButton = screen.getByRole('button', { name: 'Continue' }); await userEvent.click(continueButton); @@ -107,7 +127,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); await userEvent.click(yesRadio); @@ -117,7 +137,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('clears error message when no radio button is selected', async () => { - render(); + render(); const continueButton = screen.getByRole('button', { name: 'Continue' }); await userEvent.click(continueButton); @@ -127,7 +147,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(noRadio); @@ -139,10 +159,10 @@ describe('ReviewDetailsAddMoreChoicePage', () => { describe('User Interactions', () => { it('allows selecting the yes radio button', async () => { - render(); + render(); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); await userEvent.click(yesRadio); @@ -152,10 +172,10 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('allows selecting the no radio button', async () => { - render(); + render(); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(noRadio); @@ -165,13 +185,13 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('allows changing selection from yes to no', async () => { - render(); + render(); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(yesRadio); @@ -187,7 +207,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('prevents default form submission', async () => { - render(); + render(); const form = screen.getByRole('button', { name: 'Continue' }).closest('form'); const submitHandler = vi.fn((e: Event) => e.preventDefault()); @@ -202,10 +222,10 @@ describe('ReviewDetailsAddMoreChoicePage', () => { describe('Navigation', () => { it('navigates to add more files when yes is selected', async () => { - render(); + render(); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); await userEvent.click(yesRadio); @@ -229,7 +249,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { render(); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(noRadio); @@ -253,7 +273,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { render(); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(noRadio); @@ -277,7 +297,7 @@ describe('ReviewDetailsAddMoreChoicePage', () => { render(); const noRadio = screen.getByRole('radio', { - name: /No, I don't have anymore scanned paper records to add for this patient/i, + name: testData.noText, }); await userEvent.click(noRadio); @@ -295,14 +315,18 @@ describe('ReviewDetailsAddMoreChoicePage', () => { describe('Accessibility', () => { it('passes axe accessibility tests in initial state', async () => { - const { container } = render(); + const { container } = render( + , + ); const results = await runAxeTest(container); expect(results).toHaveNoViolations(); }); it('passes axe accessibility tests in error state', async () => { - const { container } = render(); + const { container } = render( + , + ); const continueButton = screen.getByRole('button', { name: 'Continue' }); await userEvent.click(continueButton); @@ -316,10 +340,12 @@ describe('ReviewDetailsAddMoreChoicePage', () => { }); it('passes axe accessibility tests with radio button selected', async () => { - const { container } = render(); + const { container } = render( + , + ); const yesRadio = screen.getByRole('radio', { - name: /Yes I have more scanned paper records to add for this patient/i, + name: testData.yesText, }); await userEvent.click(yesRadio); diff --git a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx index ebc1bd609e..96b322f877 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx @@ -4,6 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import { navigateUrlParam, routeChildren } from '../../../../types/generic/routes'; import BackButton from '../../../generic/backButton/BackButton'; import { ReviewDetails } from '../../../../types/generic/reviews'; +import { getConfigForDocType } from '../../../../helpers/utils/documentType'; type ReviewDetailsAddMoreChoicePageProps = { reviewData: ReviewDetails | null; @@ -19,6 +20,13 @@ const ReviewDetailsAddMoreChoiceStage: React.FC(); + if (!reviewData) { + navigate(routeChildren.ADMIN_REVIEW); + return <>; + } + + const reviewConfig = getConfigForDocType(reviewData?.snomedCode || ''); + const handleContinue = (): void => { if (!addMoreChoice || !reviewId) { setShowError(true); @@ -54,7 +62,7 @@ const ReviewDetailsAddMoreChoiceStage: React.FC
- Do you want to add more files to this patients record? + Do you want to add more files to this patient's record? - Yes I have more scanned paper records to add for this patient + {reviewConfig.content.addMoreFilesRadioYesText} - No, I don't have anymore scanned paper records to add for this - patient + {reviewConfig.content.addMoreFilesRadioNoText}
diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ExistingRecordTable.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ExistingRecordTable.tsx index 84dadd7d70..86bd6fea06 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ExistingRecordTable.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ExistingRecordTable.tsx @@ -14,7 +14,7 @@ const ExistingRecordTable = ({ return (

Existing files

- +
Filename diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx index af9ed6b839..e4c575102c 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx @@ -1,6 +1,5 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { act } from 'react'; import { describe, expect, it, Mock, vi } from 'vitest'; import ReviewDetailsAssessmentStage from './ReviewDetailsAssessmentStage'; import { DOWNLOAD_STAGE } from '../../../../types/generic/downloadStage'; @@ -175,15 +174,14 @@ const createMockUploadDocuments = (): ReviewUploadDocument[] => [ }, ]; -describe('ReviewDetailsAssessmentPage', () => { +describe('ReviewDetailsAssessmentStage', () => { beforeEach(() => { vi.clearAllMocks(); + mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); }); describe('Rendering', () => { it('displays spinner when reviewData is null', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { }); it('displays spinner only when uploadDocuments is null/undefined or reviewData is null', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - const { rerender } = render( { />, ); - expect( - screen.getByText(/Review the new and existing Scanned paper notes/i), - ).toBeInTheDocument(); + expect(screen.getByText(/Review the new Scanned paper notes/i)).toBeInTheDocument(); }); - it('renders page title for review with existing and new files', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - + it('renders page title for review the new scanned paper notes', () => { render( { />, ); - expect( - screen.getByText(/Review the new and existing Scanned paper notes/i), - ).toBeInTheDocument(); + expect(screen.getByText(/Review the new scanned paper notes/)).toBeInTheDocument(); }); it('renders accept/reject radio buttons when only canBeDiscarded is true', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { }); it('renders add-all and choose-files radio buttons when no existing record', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { }); it('renders all radio options when has existing record in storage', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { name: /Add all files to the existing Scanned paper notes/i, }), ).toBeInTheDocument(); - expect( - screen.getByRole('radio', { name: /Choose which files to add to the existing/i }), - ).toBeInTheDocument(); expect( screen.getByRole('radio', { name: /I don't need these files, they are duplicates/i, @@ -323,8 +304,6 @@ describe('ReviewDetailsAssessmentPage', () => { }); it('displays existing files table when available', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { }); it('displays new files table', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { }); it('displays "all files" viewing message by default', () => { - mockUsePatientDetailsContext.mockReturnValue([null, mockSetPatientDetails]); - render( { ); const viewButtons = screen.getAllByRole('button', { name: /View/i }); - await act(async () => { - await user.click(viewButtons[1]); - }); + await user.click(viewButtons[1]); await waitFor(() => { expect(mockSetDownloadStage).toHaveBeenCalledWith(DOWNLOAD_STAGE.PENDING); @@ -444,9 +417,7 @@ describe('ReviewDetailsAssessmentPage', () => { ); const viewButtons = screen.getAllByRole('button', { name: /View/i }); - await act(async () => { - await user.click(viewButtons[1]); - }); + await user.click(viewButtons[1]); await waitFor(() => { expect(mockGetReviewById).toHaveBeenCalled(); @@ -471,9 +442,7 @@ describe('ReviewDetailsAssessmentPage', () => { ); const viewButtons = screen.getAllByRole('button', { name: /View/i }); - await act(async () => { - await user.click(viewButtons[1]); - }); + await user.click(viewButtons[1]); await waitFor(() => { expect( @@ -506,9 +475,7 @@ describe('ReviewDetailsAssessmentPage', () => { const existingFileViewButton = screen.getByTestId('existing-record-table'); const viewButton = existingFileViewButton.querySelector('button'); - await act(async () => { - await user.click(viewButton!); - }); + await user.click(viewButton!); await waitFor(() => { expect( @@ -573,9 +540,7 @@ describe('ReviewDetailsAssessmentPage', () => { ); const viewButtons = screen.getAllByRole('button', { name: /View duplicate.pdf/i }); - await act(async () => { - await user.click(viewButtons[0]); // Click first duplicate - }); + await user.click(viewButtons[0]); // Click first duplicate await waitFor(() => { expect(screen.getByText(/\(new files\)/)).toBeInTheDocument(); @@ -648,9 +613,7 @@ describe('ReviewDetailsAssessmentPage', () => { const existingFileViewButton = screen.getByTestId('existing-record-table'); const viewButton = existingFileViewButton.querySelector('button'); - await act(async () => { - await user.click(viewButton!); - }); + await user.click(viewButton!); await waitFor(() => { expect(screen.getByText(/\(existing files\)/)).toBeInTheDocument(); @@ -690,28 +653,6 @@ describe('ReviewDetailsAssessmentPage', () => { expect(addAllRadio).toBeChecked(); }); - it('allows selecting choose-files option', async () => { - const user = userEvent.setup(); - - render( - , - ); - - const chooseFilesRadio = screen.getByLabelText( - /Choose which files to add to the existing/i, - ); - await user.click(chooseFilesRadio); - - expect(chooseFilesRadio).toBeChecked(); - }); - it('allows selecting duplicate option', async () => { const user = userEvent.setup(); @@ -837,34 +778,6 @@ describe('ReviewDetailsAssessmentPage', () => { ); }); - it('navigates to choose which files when choose-files is selected', async () => { - const user = userEvent.setup(); - - render( - , - ); - - const chooseFilesRadio = screen.getByRole('radio', { - name: /Choose which files to add to the existing/i, - }); - await user.click(chooseFilesRadio); - - const continueButton = screen.getByRole('button', { name: 'Continue' }); - await user.click(continueButton); - - expect(mockedUseNavigate).toHaveBeenCalledWith( - '/admin/reviews/test-review-id.v1/files', - undefined, - ); - }); - it('navigates to no files choice when duplicate is selected', async () => { const user = userEvent.setup(); @@ -1008,9 +921,7 @@ describe('ReviewDetailsAssessmentPage', () => { ); const viewButtons = screen.getAllByRole('button', { name: /View/i }); - await act(async () => { - await user.click(viewButtons[1]); - }); + await user.click(viewButtons[1]); await waitFor(() => { expect(mockedUseNavigate).toHaveBeenCalledWith('/session-expired'); @@ -1034,9 +945,7 @@ describe('ReviewDetailsAssessmentPage', () => { ); const viewButtons = screen.getAllByRole('button', { name: /View/i }); - await act(async () => { - await user.click(viewButtons[1]); - }); + await user.click(viewButtons[1]); await waitFor(() => { expect(mockedUseNavigate).toHaveBeenCalledWith( diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx index 340e70abbb..917a17cc15 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx @@ -54,6 +54,10 @@ const ReviewDetailsAssessmentStage = ({ const { reviewId } = useParams<{ reviewId: string }>(); const navigate = useNavigate(); + if (!hasExistingRecordInStorage && reviewId !== undefined) { + navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); + } + const [selectedFile, setSelectedFile] = useState(null); const [fileAction, setFileAction] = useState(''); const [showError, setShowError] = useState(false); @@ -209,8 +213,7 @@ const ReviewDetailsAssessmentStage = ({ if (reviewConfig.canBeUpdated === false && reviewConfig.canBeDiscarded) { pageTitle = 'Do you want to accept these records?'; } else if (reviewConfig.canBeUpdated && reviewConfig.canBeDiscarded) { - const andExisting = reviewData.existingFiles!.length > 0 ? ' and existing ' : ' '; - pageTitle = `Review the new${andExisting}${reviewTypeLabel.toSentenceCase()}`; + pageTitle = reviewConfig.content.reviewAssessmentPageTitle as string; } else { pageTitle = `Review the ${reviewTypeLabel.toSentenceCase()}`; } @@ -257,15 +260,6 @@ const ReviewDetailsAssessmentStage = ({ > Add all files to the existing {reviewTypeLabel.toSentenceCase()} - { - setFileAction(e.currentTarget.value as FileAction); - }} - > - Choose which files to add to the existing {reviewTypeLabel.toSentenceCase()} - { }); await userEvent.click(confirmButton); - await waitFor(async () => { - const results = await runAxeTest(document.body); - expect(results).toHaveNoViolations(); + await waitFor(() => { + expect(screen.getByText('There is a problem')).toBeInTheDocument(); }); + + const results = await runAxeTest(document.body); + expect(results).toHaveNoViolations(); }); }); }); diff --git a/app/src/config/electronicHealthRecordAttachmentsConfig.json b/app/src/config/electronicHealthRecordAttachmentsConfig.json index 6f6529f12c..d075941934 100644 --- a/app/src/config/electronicHealthRecordAttachmentsConfig.json +++ b/app/src/config/electronicHealthRecordAttachmentsConfig.json @@ -33,6 +33,9 @@ "previewUploadTitle": "Preview electronic health record attachment", "uploadFilesExtraParagraph": "", "reviewDocumentTitle": "EHR Attachments", - "skipDocumentLinkText": "Continue without uploading any EHR attachments" + "skipDocumentLinkText": "Continue without uploading any EHR attachments", + "addMoreFilesRadioNoText": "", + "addMoreFilesRadioYesText": "", + "reviewAssessmentPageTitle": "" } } \ No newline at end of file diff --git a/app/src/config/lettersAndDocumentsConfig.json b/app/src/config/lettersAndDocumentsConfig.json index 0f00538476..84a0d14ea2 100644 --- a/app/src/config/lettersAndDocumentsConfig.json +++ b/app/src/config/lettersAndDocumentsConfig.json @@ -31,6 +31,9 @@ "beforeYouUploadTitle": "Before you upload", "previewUploadTitle": "Preview your PDF files", "uploadFilesExtraParagraph": "", - "reviewDocumentTitle": "Letters and documents" + "reviewDocumentTitle": "Letters and documents", + "addMoreFilesRadioNoText": "", + "addMoreFilesRadioYesText": "", + "reviewAssessmentPageTitle": "" } } \ No newline at end of file diff --git a/app/src/config/lloydGeorgeConfig.json b/app/src/config/lloydGeorgeConfig.json index a35946e31b..da9a1fa5fb 100644 --- a/app/src/config/lloydGeorgeConfig.json +++ b/app/src/config/lloydGeorgeConfig.json @@ -33,6 +33,9 @@ "beforeYouUploadTitle": "Before you upload", "previewUploadTitle": "Preview these scanned paper notes", "uploadFilesExtraParagraph": "You can add a note to the patient's electronic health record to say their Lloyd George record is stored in this service. Use SNOMED code 16521000000101.", - "reviewDocumentTitle": "Scanned paper notes" + "reviewDocumentTitle": "Scanned paper notes", + "addMoreFilesRadioNoText": "No, I don't have anymore scanned paper notes to add for this patient", + "addMoreFilesRadioYesText": "Yes, I have more scanned paper notes to add for this patient", + "reviewAssessmentPageTitle": "Review the new scanned paper notes" } } \ No newline at end of file diff --git a/app/src/helpers/utils/documentType.ts b/app/src/helpers/utils/documentType.ts index d1e60497c0..ab0909d0d1 100644 --- a/app/src/helpers/utils/documentType.ts +++ b/app/src/helpers/utils/documentType.ts @@ -26,7 +26,10 @@ export type ContentKey = | 'uploadFilesBulletPoints' | 'skipDocumentLinkText' | 'confirmFilesTableTitle' - | 'confirmFilesTableParagraph'; + | 'confirmFilesTableParagraph' + | 'addMoreFilesRadioNoText' + | 'addMoreFilesRadioYesText' + | 'reviewAssessmentPageTitle'; export interface IndividualDocumentTypeContent extends Record {} // The individual config for each document type diff --git a/app/src/pages/lloydGeorgeRecordPage/LloydGeorgeRecordPage.test.tsx b/app/src/pages/lloydGeorgeRecordPage/LloydGeorgeRecordPage.test.tsx index 1113e93a5d..d3d37ed678 100644 --- a/app/src/pages/lloydGeorgeRecordPage/LloydGeorgeRecordPage.test.tsx +++ b/app/src/pages/lloydGeorgeRecordPage/LloydGeorgeRecordPage.test.tsx @@ -25,6 +25,10 @@ vi.mock('../../helpers/hooks/useBaseAPIHeaders'); vi.mock('../../helpers/hooks/useBaseAPIUrl'); vi.mock('../../helpers/hooks/useRole'); +vi.mock('../../providers/analyticsProvider/AnalyticsProvider', () => ({ + useAnalyticsContext: (): [null, () => void] => [null, (): void => {}], +})); + const mockAxios = axios as Mocked; const mockPatientDetails = buildPatientDetails(); const mockedUsePatient = usePatient as Mock; diff --git a/app/src/pages/privacyPage/PrivacyPage.test.tsx b/app/src/pages/privacyPage/PrivacyPage.test.tsx index bf92f385f0..fc14cf11e3 100644 --- a/app/src/pages/privacyPage/PrivacyPage.test.tsx +++ b/app/src/pages/privacyPage/PrivacyPage.test.tsx @@ -27,7 +27,7 @@ describe('PrivacyPage', () => { }); describe('Rendering', () => { - it('renders page headers', () => { + it('renders page headers', async () => { render(); const contentHeaders = [ @@ -38,8 +38,11 @@ describe('PrivacyPage', () => { 'Feedback form privacy notice', 'Contact us', ]; - contentHeaders.forEach((str) => { - expect(screen.getByRole('heading', { name: str })).toBeInTheDocument(); + + await waitFor(async () => { + contentHeaders.forEach((str) => { + expect(screen.getByRole('heading', { name: str })).toBeInTheDocument(); + }); }); }); From ceee4db2fcfc5711b4c31eaf3fcbb90f27ec67fa Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Tue, 10 Feb 2026 14:50:22 +0000 Subject: [PATCH 2/8] minor sonar issue --- .../ReviewDetailsAddMoreChoiceStage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx index 96b322f877..28925082b7 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAddMoreChoiceStage/ReviewDetailsAddMoreChoiceStage.tsx @@ -41,7 +41,7 @@ const ReviewDetailsAddMoreChoiceStage: React.FC 1 + reviewData.files!.length > 1 ? routeChildren.ADMIN_REVIEW_UPLOAD_FILE_ORDER : routeChildren.ADMIN_REVIEW_UPLOAD, { reviewId }, From ddbc9998bfa3fb24ff6e7101a8964e8e3cc3c132 Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 11:44:50 +0000 Subject: [PATCH 3/8] minor fix --- .../DocumentUploadLloydGeorgePreview.tsx | 4 ++-- app/src/config/electronicHealthRecordAttachmentsConfig.json | 3 ++- app/src/config/lettersAndDocumentsConfig.json | 3 ++- app/src/config/lloydGeorgeConfig.json | 5 +++-- app/src/helpers/utils/documentType.ts | 3 ++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.tsx b/app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.tsx index 0f476dabc3..bfcfa469a6 100644 --- a/app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.tsx +++ b/app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.tsx @@ -72,8 +72,8 @@ const DocumentUploadLloydGeorgePreview = ({ {documentConfig.stitched ? ( <>

- This shows how these {documentConfig.displayName} will look when - combined into a single document.{' '} + {documentConfig.content.stitchedPreviewFirstParagraph} + {journey === 'update' && `Any files added will appear after the existing ${documentConfig.displayName}.`}

diff --git a/app/src/config/electronicHealthRecordAttachmentsConfig.json b/app/src/config/electronicHealthRecordAttachmentsConfig.json index d075941934..36ffb2e9ee 100644 --- a/app/src/config/electronicHealthRecordAttachmentsConfig.json +++ b/app/src/config/electronicHealthRecordAttachmentsConfig.json @@ -36,6 +36,7 @@ "skipDocumentLinkText": "Continue without uploading any EHR attachments", "addMoreFilesRadioNoText": "", "addMoreFilesRadioYesText": "", - "reviewAssessmentPageTitle": "" + "reviewAssessmentPageTitle": "", + "stitchedPreviewFirstParagraph": "" } } \ No newline at end of file diff --git a/app/src/config/lettersAndDocumentsConfig.json b/app/src/config/lettersAndDocumentsConfig.json index 84a0d14ea2..0833b72eab 100644 --- a/app/src/config/lettersAndDocumentsConfig.json +++ b/app/src/config/lettersAndDocumentsConfig.json @@ -34,6 +34,7 @@ "reviewDocumentTitle": "Letters and documents", "addMoreFilesRadioNoText": "", "addMoreFilesRadioYesText": "", - "reviewAssessmentPageTitle": "" + "reviewAssessmentPageTitle": "", + "stitchedPreviewFirstParagraph": "" } } \ No newline at end of file diff --git a/app/src/config/lloydGeorgeConfig.json b/app/src/config/lloydGeorgeConfig.json index da9a1fa5fb..fcf835621a 100644 --- a/app/src/config/lloydGeorgeConfig.json +++ b/app/src/config/lloydGeorgeConfig.json @@ -31,11 +31,12 @@ "confirmFilesTableTitle": "Scanned paper notes to upload", "confirmFilesTableParagraph": "", "beforeYouUploadTitle": "Before you upload", - "previewUploadTitle": "Preview these scanned paper notes", + "previewUploadTitle": "Preview existing scanned paper notes record", "uploadFilesExtraParagraph": "You can add a note to the patient's electronic health record to say their Lloyd George record is stored in this service. Use SNOMED code 16521000000101.", "reviewDocumentTitle": "Scanned paper notes", "addMoreFilesRadioNoText": "No, I don't have anymore scanned paper notes to add for this patient", "addMoreFilesRadioYesText": "Yes, I have more scanned paper notes to add for this patient", - "reviewAssessmentPageTitle": "Review the new scanned paper notes" + "reviewAssessmentPageTitle": "Review the new scanned paper notes", + "stitchedPreviewFirstParagraph": "This shows how the final notes will look when combined into a single document. " } } \ No newline at end of file diff --git a/app/src/helpers/utils/documentType.ts b/app/src/helpers/utils/documentType.ts index ab0909d0d1..eb9c382f52 100644 --- a/app/src/helpers/utils/documentType.ts +++ b/app/src/helpers/utils/documentType.ts @@ -29,7 +29,8 @@ export type ContentKey = | 'confirmFilesTableParagraph' | 'addMoreFilesRadioNoText' | 'addMoreFilesRadioYesText' - | 'reviewAssessmentPageTitle'; + | 'reviewAssessmentPageTitle' + | 'stitchedPreviewFirstParagraph'; export interface IndividualDocumentTypeContent extends Record {} // The individual config for each document type From e0b0ce53f2eac589e3c98441cdb95e388361c466 Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 14:15:17 +0000 Subject: [PATCH 4/8] minor fix --- .../ReviewDetailsAssessmentStage.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx index 917a17cc15..6c21bb7b05 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx @@ -54,10 +54,6 @@ const ReviewDetailsAssessmentStage = ({ const { reviewId } = useParams<{ reviewId: string }>(); const navigate = useNavigate(); - if (!hasExistingRecordInStorage && reviewId !== undefined) { - navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); - } - const [selectedFile, setSelectedFile] = useState(null); const [fileAction, setFileAction] = useState(''); const [showError, setShowError] = useState(false); @@ -66,10 +62,16 @@ const ReviewDetailsAssessmentStage = ({ const baseUrl = useBaseAPIUrl(); const baseHeaders = useBaseAPIHeaders(); + if (!hasExistingRecordInStorage && reviewId !== undefined) { + navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); + return <>; + } + const handleExistingFileView = async (filename: string, id: string): Promise => { if (!reviewData) { return; } + if (isLocal) { const file = reviewData.existingFiles?.find((f) => f.fileName === filename); if (!file) { From 9e8c0f7730d4cc7f6ea58a364c48c914fc61a284 Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 14:52:52 +0000 Subject: [PATCH 5/8] minor fix --- .../ReviewDetailsAssessmentStage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx index 6c21bb7b05..e128fa2ce0 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx @@ -63,7 +63,9 @@ const ReviewDetailsAssessmentStage = ({ const baseHeaders = useBaseAPIHeaders(); if (!hasExistingRecordInStorage && reviewId !== undefined) { - navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); + setTimeout(() => { + navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); + }, 0); return <>; } From b86c1ca32d3e3912ada290fa16415d7ac17f84ba Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 15:03:01 +0000 Subject: [PATCH 6/8] fix tests --- .../ReviewDetailsAssessmentStage.test.tsx | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx index e4c575102c..32954cc752 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx @@ -252,7 +252,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={createMockUploadDocuments()} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -260,25 +260,6 @@ describe('ReviewDetailsAssessmentStage', () => { expect(screen.getByRole('radio', { name: 'Reject record' })).toBeInTheDocument(); }); - it('renders add-all and choose-files radio buttons when no existing record', () => { - render( - , - ); - - expect(screen.getByLabelText('Add all these files')).toBeInTheDocument(); - expect(screen.getByLabelText('Choose which files to add')).toBeInTheDocument(); - expect( - screen.queryByText(/I don't need these files, they are duplicates/), - ).not.toBeInTheDocument(); - }); - it('renders all radio options when has existing record in storage', () => { render( { uploadDocuments={createMockUploadDocuments()} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -690,7 +671,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={createMockUploadDocuments()} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -715,7 +696,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={createMockUploadDocuments()} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -816,7 +797,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={createMockUploadDocuments()} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -992,7 +973,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={singleUploadDoc} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); @@ -1057,7 +1038,7 @@ describe('ReviewDetailsAssessmentStage', () => { uploadDocuments={multiUploadDocs} downloadStage={DOWNLOAD_STAGE.SUCCEEDED} setDownloadStage={mockSetDownloadStage} - hasExistingRecordInStorage={false} + hasExistingRecordInStorage={true} />, ); From e6e520af470f20b23800534ed5bd57cfe01c2a5e Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 15:20:32 +0000 Subject: [PATCH 7/8] update navigation to replace current entry when adding more choices --- .../ReviewDetailsAssessmentStage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx index e128fa2ce0..b3c885d2f3 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.tsx @@ -64,7 +64,9 @@ const ReviewDetailsAssessmentStage = ({ if (!hasExistingRecordInStorage && reviewId !== undefined) { setTimeout(() => { - navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate); + navigateUrlParam(routeChildren.ADMIN_REVIEW_ADD_MORE_CHOICE, { reviewId }, navigate, { + replace: true, + }); }, 0); return <>; } From 829c608c7d17f74c56c1107e9bb442a1563973cf Mon Sep 17 00:00:00 2001 From: Lillie Dae Date: Thu, 12 Feb 2026 15:42:29 +0000 Subject: [PATCH 8/8] improve coverage --- .../ReviewDetailsAssessmentStage.test.tsx | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx index 32954cc752..9df0f10316 100644 --- a/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx +++ b/app/src/components/blocks/_admin/reviewDetailsAssessmentStage/ReviewDetailsAssessmentStage.test.tsx @@ -1073,4 +1073,47 @@ describe('ReviewDetailsAssessmentStage', () => { expect(screen.getByTestId('back-button')).toBeInTheDocument(); }); }); + + describe('Redirect behavior when no existing record in storage', () => { + it('redirects to add more choice page with replace option when hasExistingRecordInStorage is false', async () => { + vi.useFakeTimers(); + + render( + , + ); + + // Fast-forward timers to trigger the setTimeout + await vi.advanceTimersByTimeAsync(0); + + expect(mockedUseNavigate).toHaveBeenCalledWith( + '/admin/reviews/test-review-id.v1/add-more-choice', + { replace: true }, + ); + + vi.useRealTimers(); + }); + + it('renders empty fragment when redirecting', () => { + const { container } = render( + , + ); + + // Should render empty fragment (no content) + expect(container.firstChild).toBeNull(); + }); + }); });