Skip to content

Commit 0e6467c

Browse files
[PRMP-554] Fix issue with clicking continue before stitch is loaded (#822)
1 parent dd413ee commit 0e6467c

File tree

7 files changed

+72
-38
lines changed

7 files changed

+72
-38
lines changed

app/src/components/blocks/_documentUpload/documentSelectOrderStage/DocumentSelectOrderStage.test.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,23 @@ URL.createObjectURL = vi.fn(() => 'mocked-url');
3131
Element.prototype.scrollIntoView = vi.fn();
3232

3333
vi.mock('../documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview', () => ({
34-
default: ({ documents }: { documents: UploadDocument[] }): React.JSX.Element => (
35-
<div data-testid="lloyd-george-preview">
36-
Lloyd George Preview for {documents.length} documents
37-
</div>
38-
),
34+
default: ({
35+
documents,
36+
stitchedBlobLoaded,
37+
}: {
38+
documents: UploadDocument[];
39+
stitchedBlobLoaded?: (loaded: boolean) => void;
40+
}): React.JSX.Element => {
41+
// Simulate the PDF stitching completion
42+
if (stitchedBlobLoaded) {
43+
setTimeout(() => stitchedBlobLoaded(true), 0);
44+
}
45+
return (
46+
<div data-testid="lloyd-george-preview">
47+
Lloyd George Preview for {documents.length} documents
48+
</div>
49+
);
50+
},
3951
}));
4052

4153
describe('DocumentSelectOrderStage', () => {
@@ -100,10 +112,12 @@ describe('DocumentSelectOrderStage', () => {
100112
expect(screen.getByText('Remove')).toBeInTheDocument();
101113
});
102114

103-
it('renders continue button when documents are present', () => {
115+
it('renders continue button when documents are present', async () => {
104116
renderSut(documents);
105117

106-
expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument();
118+
await waitFor(() => {
119+
expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument();
120+
});
107121
});
108122

109123
it('does not show "Remove all" button when there is only one document', () => {
@@ -411,8 +425,13 @@ describe('DocumentSelectOrderStage', () => {
411425

412426
renderSut(documentsWithDuplicatePositions);
413427

414-
const continueButton = screen.getByRole('button', { name: 'Continue' });
415-
await user.click(continueButton);
428+
let continueButton;
429+
await waitFor(() => {
430+
continueButton = screen.getByRole('button', { name: 'Continue' });
431+
expect(continueButton).toBeInTheDocument();
432+
});
433+
434+
await user.click(continueButton!);
416435

417436
await waitFor(() => {
418437
expect(screen.getByText('There is a problem')).toBeInTheDocument();

app/src/components/blocks/_documentUpload/documentSelectOrderStage/DocumentSelectOrderStage.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Button, Select, Table } from 'nhsuk-react-components';
2-
import { Dispatch, JSX, SetStateAction, useEffect, useRef } from 'react';
2+
import { Dispatch, JSX, SetStateAction, useEffect, useRef, useState } from 'react';
33
import { FieldErrors, FieldValues, useForm } from 'react-hook-form';
44
import { Link, useNavigate } from 'react-router-dom';
55
import useTitle from '../../../../helpers/hooks/useTitle';
@@ -21,6 +21,7 @@ import ErrorBox from '../../../layout/errorBox/ErrorBox';
2121
import DocumentUploadLloydGeorgePreview from '../documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview';
2222
import { ErrorMessageListItem } from '../../../../types/pages/genericPageErrors';
2323
import getMergedPdfBlob from '../../../../helpers/utils/pdfMerger';
24+
import SpinnerButton from '../../../generic/spinnerButton/SpinnerButton';
2425

2526
type Props = {
2627
documents: UploadDocument[];
@@ -38,6 +39,7 @@ const DocumentSelectOrderStage = ({
3839
setMergedPdfBlob,
3940
}: Props): JSX.Element => {
4041
const navigate = useNavigate();
42+
const [stitchedBlobLoaded, setStitchedBlobLoaded] = useState(false);
4143

4244
const documentPositionKey = (documentId: string): string => {
4345
return `${documentId}`;
@@ -341,9 +343,12 @@ const DocumentSelectOrderStage = ({
341343
.filter((doc) => doc.docType === DOCUMENT_TYPE.LLOYD_GEORGE)
342344
.sort((a, b) => a.position! - b.position!)}
343345
setMergedPdfBlob={setMergedPdfBlob}
346+
stitchedBlobLoaded={(loaded: boolean) => {
347+
setStitchedBlobLoaded(loaded);
348+
}}
344349
/>
345350
</div>
346-
{documents.length > 0 && (
351+
{documents.length > 0 && stitchedBlobLoaded && (
347352
<Button
348353
type="submit"
349354
id="form-submit"
@@ -355,6 +360,14 @@ const DocumentSelectOrderStage = ({
355360
Continue
356361
</Button>
357362
)}
363+
{documents.length > 0 && !stitchedBlobLoaded && (
364+
<SpinnerButton
365+
id="continue-spinner"
366+
status="Stitching PDF"
367+
disabled={true}
368+
className="mt-4"
369+
/>
370+
)}
358371
</form>
359372
</>
360373
);

app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ describe('DocumentUploadCompleteStage', () => {
6060
const mockBlob = new Blob(['test pdf content'], { type: 'application/pdf' });
6161
vi.mocked(getMergedPdfBlob).mockResolvedValue(mockBlob);
6262

63+
const stitchedBlobLoaded = vi.fn();
64+
6365
await act(async () => {
6466
render(
6567
<DocumentUploadLloydGeorgePreview
6668
documents={testDocuments}
6769
setMergedPdfBlob={mockSetMergedPdfBlob}
70+
stitchedBlobLoaded={stitchedBlobLoaded}
6871
/>,
6972
);
7073
});
@@ -73,6 +76,7 @@ describe('DocumentUploadCompleteStage', () => {
7376

7477
await waitFor(() => {
7578
expect(mockSetMergedPdfBlob).toHaveBeenCalledWith(mockBlob);
79+
expect(stitchedBlobLoaded).toHaveBeenCalledTimes(2);
7680
});
7781
});
7882
});

app/src/components/blocks/_documentUpload/documentUploadLloydGeorgePreview/DocumentUploadLloydGeorgePreview.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import { UploadDocument } from '../../../../types/pages/UploadDocumentsPage/types';
2-
import { Dispatch, JSX, SetStateAction, useEffect, useRef, useState } from 'react';
2+
import { JSX, useEffect, useRef, useState } from 'react';
33
import PdfViewer from '../../../generic/pdfViewer/PdfViewer';
44
import getMergedPdfBlob from '../../../../helpers/utils/pdfMerger';
55

66
type Props = {
77
documents: UploadDocument[];
8-
setMergedPdfBlob: Dispatch<SetStateAction<Blob | undefined>>;
8+
setMergedPdfBlob: (blob: Blob) => void;
9+
stitchedBlobLoaded?: (value: boolean) => void;
910
};
1011

11-
const DocumentUploadLloydGeorgePreview = ({ documents, setMergedPdfBlob }: Props): JSX.Element => {
12+
const DocumentUploadLloydGeorgePreview = ({
13+
documents,
14+
setMergedPdfBlob,
15+
stitchedBlobLoaded,
16+
}: Props): JSX.Element => {
1217
const [mergedPdfUrl, setMergedPdfUrl] = useState('');
1318

1419
const runningRef = useRef(false);
@@ -20,16 +25,26 @@ const DocumentUploadLloydGeorgePreview = ({ documents, setMergedPdfBlob }: Props
2025
}
2126
return;
2227
}
28+
2329
if (runningRef.current) return;
2430

2531
runningRef.current = true;
2632

2733
const render = async (): Promise<void> => {
34+
if (stitchedBlobLoaded) {
35+
stitchedBlobLoaded(false);
36+
}
37+
2838
const blob = await getMergedPdfBlob(documents.map((doc) => doc.file));
2939
setMergedPdfBlob(blob);
40+
3041
const url = URL.createObjectURL(blob);
3142
runningRef.current = false;
3243
setMergedPdfUrl(url);
44+
45+
if (stitchedBlobLoaded) {
46+
stitchedBlobLoaded(true);
47+
}
3348
};
3449

3550
render().catch((err) => {

app/src/components/generic/pdfViewer/PdfViewer.tsx

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,18 @@
1-
import { useEffect, useRef } from 'react';
2-
31
type Props = {
42
fileUrl: string;
53
customClasses?: string[];
6-
onLoaded?: () => void;
4+
customStyleSheet?: string;
75
};
86

9-
const PdfViewer = ({ fileUrl, customClasses, onLoaded }: Props) => {
10-
const loadedRef = useRef(false);
11-
12-
useEffect(() => {
13-
const test = async () => {
14-
while (!document.querySelector('pdfjs-viewer-element')) {}
15-
16-
if (!loadedRef.current) {
17-
loadedRef.current = true;
18-
19-
if (onLoaded) {
20-
onLoaded();
21-
}
22-
}
23-
};
24-
25-
test();
26-
});
27-
7+
const PdfViewer = ({ fileUrl, customClasses, customStyleSheet }: Props) => {
288
return (
299
<pdfjs-viewer-element
3010
id="pdf-viewer"
3111
data-testid="pdf-viewer"
3212
src={fileUrl}
3313
title="Embedded PDF Viewer"
3414
viewer-path="/pdfjs"
15+
viewer-extra-styles={customStyleSheet}
3516
viewer-extra-styles-urls="['/pdf-viewer.css']"
3617
className={customClasses?.join(' ')}
3718
></pdfjs-viewer-element>

app/src/components/generic/spinnerButton/SpinnerButton.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ export type Props = {
66
status: string;
77
disabled?: boolean;
88
dataTestId?: string;
9+
className?: string;
910
};
1011

11-
const SpinnerButton = ({ id, status, disabled, dataTestId }: Props) => {
12+
const SpinnerButton = ({ id, status, disabled, dataTestId, className }: Props) => {
1213
return (
1314
<Button
1415
id={id}
1516
data-testid={dataTestId}
1617
aria-label={status}
17-
className="spinner_button"
18+
className={`spinner_button ${className}`}
1819
disabled={disabled}
1920
>
2021
<div className="spinner_button-spinner"></div>

app/src/styles/App.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ $hunit: '%';
829829

830830
&.upload-preview {
831831
height: 90vh;
832+
max-height: 1080px;
832833
}
833834
}
834835

0 commit comments

Comments
 (0)