Skip to content

Commit 6829c6d

Browse files
adamwhitingnhslillie-dae
authored andcommitted
[PRMP-1251] Add letters and docs config
1 parent 7fa2488 commit 6829c6d

File tree

19 files changed

+285
-120
lines changed

19 files changed

+285
-120
lines changed

app/src/components/blocks/_documentUpload/documentUploadCompleteStage/DocumentUploadCompleteStage.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ describe('DocumentUploadCompleteStage', () => {
7171

7272
const expectedDob = getFormattedDate(new Date(patientDetails.birthDate));
7373
expect(screen.getByTestId('dob').textContent).toEqual('Date of birth: ' + expectedDob);
74+
75+
expect(
76+
screen.queryByText(
77+
'You are not the data controller',
78+
{
79+
exact: false,
80+
}
81+
),
82+
).not.toBeInTheDocument();
7483
});
7584

7685
it('should navigate to search when clicking the search link', async () => {
@@ -153,6 +162,25 @@ describe('DocumentUploadCompleteStage', () => {
153162
expect(screen.getByText(documents[1].file.name)).toBeInTheDocument();
154163
});
155164

165+
it('should render non-data controller message when user is not data controller', async () => {
166+
vi.mocked(usePatient).mockReturnValueOnce(
167+
buildPatientDetails({
168+
canManageRecord: false,
169+
}),
170+
);
171+
172+
renderApp(documents);
173+
174+
expect(
175+
screen.getByText(
176+
'You are not the data controller',
177+
{
178+
exact: false,
179+
}
180+
),
181+
).toBeInTheDocument();
182+
});
183+
156184
const renderApp = (documents: UploadDocument[]) => {
157185
render(
158186
<MemoryRouter>

app/src/components/blocks/_documentUpload/documentUploadCompleteStage/DocumentUploadCompleteStage.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ const DocumentUploadCompleteStage = ({ documents, documentConfig }: Props): Reac
126126
</p>
127127
)}
128128

129+
{patientDetails.canManageRecord === false && (
130+
<p>
131+
You are not the data controller for this patient so you cannot view the files
132+
you have uploaded in this service.
133+
</p>
134+
)}
135+
129136
<p>
130137
If you think you've made a mistake, contact the Patient Record Management team at{' '}
131138
<a href="mailto:england.prmteam@nhs.net">england.prmteam@nhs.net</a>.

app/src/components/blocks/_documentUpload/documentUploadConfirmStage/DocumentUploadConfirmStage.test.tsx

Lines changed: 87 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { render, waitFor, screen, RenderResult } from '@testing-library/react';
22
import DocumentUploadConfirmStage from './DocumentUploadConfirmStage';
33
import { formatNhsNumber } from '../../../../helpers/utils/formatNhsNumber';
44
import { getFormattedDate } from '../../../../helpers/utils/formatDate';
5-
import { buildDocumentConfig, buildPatientDetails } from '../../../../helpers/test/testBuilders';
5+
import { buildDocument, buildDocumentConfig, buildPatientDetails } from '../../../../helpers/test/testBuilders';
66
import usePatient from '../../../../helpers/hooks/usePatient';
77
import {
88
DOCUMENT_UPLOAD_STATE,
@@ -11,7 +11,6 @@ import {
1111
import * as ReactRouter from 'react-router-dom';
1212
import { MemoryHistory, createMemoryHistory } from 'history';
1313
import userEvent from '@testing-library/user-event';
14-
import { routeChildren, routes } from '../../../../types/generic/routes';
1514
import { getFormattedPatientFullName } from '../../../../helpers/utils/formatPatientFullName';
1615
import { DOCUMENT_TYPE } from '../../../../helpers/utils/documentType';
1716
import { getJourney } from '../../../../helpers/utils/urlManipulations';
@@ -34,22 +33,6 @@ vi.mock('react-router-dom', async () => {
3433

3534
const mockedUseNavigate = vi.fn();
3635

37-
vi.mock('./components/DocumentList', async () => {
38-
const actual = await vi.importActual('./components/DocumentList');
39-
return {
40-
...actual,
41-
default: ({ documents }: { documents: UploadDocument[] }): React.JSX.Element => {
42-
return (
43-
<div data-testid="document-list">
44-
Document List with
45-
<span data-testid="document-list-count">{documents.length}</span>
46-
documents
47-
</div>
48-
);
49-
},
50-
};
51-
});
52-
5336
vi.mock('../documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview', () => ({
5437
default: ({
5538
documents,
@@ -80,9 +63,10 @@ let history = createMemoryHistory({
8063
initialIndex: 0,
8164
});
8265

83-
let docConfig = buildDocumentConfig();
8466
const mockConfirmFiles = vi.fn();
8567

68+
let mockDocuments: UploadDocument[] = [];
69+
8670
describe('DocumentUploadConfirmStage', () => {
8771
beforeEach(() => {
8872
vi.mocked(usePatient).mockReturnValue(patientDetails);
@@ -92,18 +76,19 @@ describe('DocumentUploadConfirmStage', () => {
9276
});
9377
afterEach(() => {
9478
vi.clearAllMocks();
79+
mockDocuments = [];
9580
});
9681

9782
it('renders', async () => {
98-
renderApp(history, 1);
83+
renderApp(history);
9984

10085
await waitFor(async () => {
10186
expect(screen.getByText('Check files are for the correct patient')).toBeInTheDocument();
10287
});
10388
});
10489

10590
it('should call confirmFiles when confirm button is clicked', async () => {
106-
renderApp(history, 1);
91+
renderApp(history);
10792

10893
await userEvent.click(await screen.findByTestId('confirm-button'));
10994

@@ -113,17 +98,19 @@ describe('DocumentUploadConfirmStage', () => {
11398
});
11499

115100
it.each([
116-
{ fileCount: 3, expectedPreviewCount: 3, stitched: true },
117-
{ fileCount: 1, expectedPreviewCount: 1, stitched: false },
101+
{ fileCount: 3, expectedPreviewCount: 3, docType: DOCUMENT_TYPE.LLOYD_GEORGE },
102+
{ fileCount: 1, expectedPreviewCount: 1, docType: DOCUMENT_TYPE.EHR },
118103
])(
119104
'should render correct number files in the preview %s',
120-
async ({ fileCount, expectedPreviewCount, stitched }) => {
121-
docConfig = buildDocumentConfig({
122-
snomedCode: DOCUMENT_TYPE.EHR,
123-
stitched,
124-
});
125-
126-
renderApp(history, fileCount);
105+
async ({ fileCount, expectedPreviewCount, docType }) => {
106+
for (let i = 1; i <= fileCount; i++) {
107+
mockDocuments.push(buildDocument(
108+
new File(['file'], `file 1.pdf`, { type: 'application/pdf' }),
109+
DOCUMENT_UPLOAD_STATE.SELECTED,
110+
docType,
111+
));
112+
}
113+
renderApp(history);
127114

128115
await waitFor(async () => {
129116
expect(screen.getByTestId('lloyd-george-preview-count').textContent).toBe(
@@ -133,9 +120,68 @@ describe('DocumentUploadConfirmStage', () => {
133120
},
134121
);
135122

123+
it('should hide preview when the previewed document is removed', async () => {
124+
mockDocuments.push(buildDocument(
125+
new File(['file'], `file 1.pdf`, { type: 'application/pdf' }),
126+
DOCUMENT_UPLOAD_STATE.SELECTED,
127+
DOCUMENT_TYPE.EHR_ATTACHMENTS,
128+
));
129+
mockDocuments.push(buildDocument(
130+
new File(['file'], `file 2.pdf`, { type: 'application/pdf' }),
131+
DOCUMENT_UPLOAD_STATE.SELECTED,
132+
DOCUMENT_TYPE.EHR_ATTACHMENTS,
133+
));
134+
renderApp(history);
135+
136+
const firstDocumentViewButton = await screen.findByTestId(`preview-${mockDocuments[0].id}-button`);
137+
expect(firstDocumentViewButton).toBeInTheDocument();
138+
139+
await userEvent.click(firstDocumentViewButton);
140+
141+
await waitFor(() => {
142+
expect(screen.getByTestId('lloyd-george-preview')).toBeInTheDocument();
143+
});
144+
145+
const removeButton = screen.getByTestId(`remove-${mockDocuments[0].id}-button`);
146+
expect(removeButton).toBeInTheDocument();
147+
148+
await userEvent.click(removeButton);
149+
150+
await waitFor(() => {
151+
expect(screen.queryByTestId('lloyd-george-preview')).not.toBeInTheDocument();
152+
});
153+
});
154+
155+
it('should show preview when 1 pdf remains after removing a document', async () => {
156+
mockDocuments.push(buildDocument(
157+
new File(['file'], `file 1.pdf`, { type: 'application/pdf' }),
158+
DOCUMENT_UPLOAD_STATE.SELECTED,
159+
DOCUMENT_TYPE.EHR_ATTACHMENTS,
160+
));
161+
mockDocuments.push(buildDocument(
162+
new File(['file'], `file 2.txt`, { type: 'text/plain' }),
163+
DOCUMENT_UPLOAD_STATE.SELECTED,
164+
DOCUMENT_TYPE.EHR_ATTACHMENTS,
165+
));
166+
renderApp(history);
167+
168+
await waitFor(() => {
169+
expect(screen.queryByTestId('lloyd-george-preview')).not.toBeInTheDocument();
170+
});
171+
172+
const removeButton = screen.getByTestId(`remove-${mockDocuments[0].id}-button`);
173+
expect(removeButton).toBeInTheDocument();
174+
175+
await userEvent.click(removeButton);
176+
177+
await waitFor(() => {
178+
expect(screen.queryByTestId('lloyd-george-preview')).not.toBeInTheDocument();
179+
});
180+
});
181+
136182
describe('Navigation', () => {
137183
it('should navigate to previous screen when go back is clicked', async () => {
138-
renderApp(history, 1);
184+
renderApp(history);
139185

140186
userEvent.click(await screen.findByTestId('go-back-link'));
141187

@@ -145,7 +191,7 @@ describe('DocumentUploadConfirmStage', () => {
145191
});
146192

147193
it('renders patient summary fields is inset', async () => {
148-
renderApp(history, 1);
194+
renderApp(history);
149195

150196
const insetText = screen
151197
.getByText('Make sure that all files uploaded are for this patient only:')
@@ -179,7 +225,7 @@ describe('DocumentUploadConfirmStage', () => {
179225
});
180226

181227
it('should still render all page elements correctly', async () => {
182-
renderApp(history, 1);
228+
renderApp(history);
183229

184230
await waitFor(async () => {
185231
expect(
@@ -191,22 +237,19 @@ describe('DocumentUploadConfirmStage', () => {
191237
});
192238
});
193239

194-
const renderApp = (history: MemoryHistory, docsLength: number): RenderResult => {
195-
const documents: UploadDocument[] = [];
196-
for (let i = 1; i <= docsLength; i++) {
197-
documents.push({
198-
attempts: 0,
199-
id: `${i}`,
200-
docType: DOCUMENT_TYPE.LLOYD_GEORGE,
201-
file: new File(['file'], `file ${i}.pdf`, { type: 'application/pdf' }),
202-
state: DOCUMENT_UPLOAD_STATE.SELECTED,
203-
});
240+
const renderApp = (history: MemoryHistory): RenderResult => {
241+
if (mockDocuments.length === 0) {
242+
mockDocuments.push(buildDocument(
243+
new File(['file'], `file 1.pdf`, { type: 'application/pdf' }),
244+
DOCUMENT_UPLOAD_STATE.SELECTED,
245+
DOCUMENT_TYPE.LLOYD_GEORGE,
246+
));
204247
}
205248

206249
return render(
207250
<ReactRouter.Router navigator={history} location={history.location}>
208251
<DocumentUploadConfirmStage
209-
documents={documents}
252+
documents={mockDocuments}
210253
confirmFiles={mockConfirmFiles}
211254
setDocuments={() => {}}
212255
/>

app/src/components/blocks/_documentUpload/documentUploadConfirmStage/DocumentUploadConfirmStage.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,21 @@ const DocumentUploadConfirmStage = ({
114114
setCurrentPreviewDocument(document);
115115
// timeout to wait for first render before scrolling
116116
setTimeout(() => {
117-
documentPreviewRef.current?.scrollIntoView({ behavior: 'smooth' });
118-
}, 0);
117+
if (typeof documentPreviewRef?.current?.scrollIntoView === 'function') {
118+
documentPreviewRef?.current?.scrollIntoView({ behavior: 'smooth' });
119+
}
120+
}, 2);
119121
};
120122

121123
const removeDocument = (docToRemove: UploadDocument): void => {
122124
const updatedDocs = documents.filter((doc) => doc.id !== docToRemove.id);
123125

124126
groupDocumentsByType(updatedDocs);
125127

126-
if (updatedDocs.length === 1) {
128+
if (currentPreviewDocument?.id === docToRemove.id) {
129+
setCurrentPreviewDocument(undefined);
130+
}
131+
else if (updatedDocs.length === 1 && updatedDocs[0].file.type === 'application/pdf') {
127132
setCurrentPreviewDocument(updatedDocs[0]);
128133
}
129134

@@ -156,7 +161,7 @@ const DocumentUploadConfirmStage = ({
156161

157162
const documentPreview = (): React.JSX.Element => {
158163
if (!currentPreviewDocument) {
159-
return <></>;
164+
return <div ref={documentPreviewRef}></div>;
160165
}
161166

162167
const config = getConfigForDocType(currentPreviewDocument.docType);
@@ -170,8 +175,7 @@ const DocumentUploadConfirmStage = ({
170175
const showCurrentlyViewingText =
171176
hasUnstitchedDocType &&
172177
documents.length > 0 &&
173-
!!groupedDocuments &&
174-
Object.keys(groupedDocuments).length > 1;
178+
!!groupedDocuments;
175179

176180
return (
177181
<div ref={documentPreviewRef}>

app/src/components/generic/patientSummary/PatientSummary.test.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ describe('PatientSummary', () => {
1616
vi.clearAllMocks();
1717
});
1818

19+
it('renders nothing when patient details are null', () => {
20+
mockedUsePatient.mockReturnValue(null);
21+
const { container } = render(<PatientSummary />);
22+
expect(container).toBeEmptyDOMElement();
23+
});
24+
1925
it('renders provided patient information', () => {
2026
const mockDetails = buildPatientDetails({
2127
familyName: 'Jones',
@@ -244,21 +250,6 @@ describe('PatientSummary', () => {
244250
expect(screen.getByText('First name')).toBeInTheDocument();
245251
});
246252

247-
it('handles null patient details gracefully', () => {
248-
mockedUsePatient.mockReturnValue(null);
249-
render(
250-
<PatientSummary>
251-
<PatientSummary.Child item={PatientInfo.FAMILY_NAME} />
252-
<PatientSummary.Child item={PatientInfo.GIVEN_NAME} />
253-
<PatientSummary.Child item={PatientInfo.BIRTH_DATE} />
254-
<PatientSummary.Child item={PatientInfo.POSTAL_CODE} />
255-
</PatientSummary>,
256-
);
257-
258-
expect(screen.getByTestId('patient-summary')).toBeInTheDocument();
259-
// Components should render but with empty/default values
260-
});
261-
262253
it('handles empty NHS number', () => {
263254
const mockDetails = buildPatientDetails({
264255
nhsNumber: '',

app/src/components/generic/patientSummary/PatientSummary.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,13 @@ const PatientSummary = ({
133133
if (reviewPatientDetails) {
134134
patientDetails = reviewPatientDetails;
135135
}
136+
136137
const patientDetailsContextValue = useMemo(() => ({ patientDetails }), [patientDetails]);
137138

139+
if (!patientDetails) {
140+
return <></>;
141+
}
142+
138143
if (oneLine) {
139144
const nameLengthLimit = 30;
140145
const givenName = patientDetails?.givenName.join(' ') || '';
@@ -168,11 +173,11 @@ const PatientSummary = ({
168173
data-testid="patient-summary-small-nhs-number"
169174
className="nhsuk-u-padding-right-9"
170175
>
171-
NHS number: {formatNhsNumber(patientDetails!.nhsNumber)}
176+
NHS number: {formatNhsNumber(patientDetails.nhsNumber)}
172177
</span>
173178
<span data-testid="patient-summary-small-date-of-birth">
174179
Date of birth:{' '}
175-
{getFormattedDate(new Date(patientDetails!.birthDate))}
180+
{getFormattedDate(new Date(patientDetails.birthDate))}
176181
</span>
177182
</p>
178183
</div>

0 commit comments

Comments
 (0)