react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

Downloading PDF larger than 30 pages - browser freeze?

Open daredevil1302 opened this issue 1 year ago • 0 comments

Is your feature request related to a problem? Please describe. There is a suggestion on the react-pdf main website for this specific problem. The suggestion is to implement service workers. However, this implementation makes sense only for static PDF components that are consisted of plain text, some images. For PDF components that use advanced logic (global state, functions, hooks) it's not possible to implement worker logic (as far as I know)

Describe the solution you'd like I would like to find a solution that will allow me to offload the main browser thread in instances where PDF's might have more than 30 pages (even 100)

Describe alternatives you've considered Don't know of any alternatives to service workers.

Additional context Rewriting my current PDF generating logic is too costly and would last too long to consider

Current Code Responsible for the Download

export const useQuoteReport = (shareQuoteConfig: TShareQuote) => {
	const { t } = useTranslation();
	const { cropsToQuoteFilteredP14s } = useCropsToQuoteFilter();
	const { p14s } = useGetQuoteCrops();
	const { quote } = useQuoterContext();
	const { tableOptions, checkedFilters } = useTableOptionsContext();
	const [loading, setLoading] = useState(false);
	const { username, fullName, logoURL, phoneNumber } = useAuthContext();
	const { getUnitOfMeasure } = useGetUnitOfMeasure();
	const { resolveAppendix } = usePdfAppendix();
	const { sortedAndFilteredData: sortedAndFilteredCrops } = useSortAndFilter({
		data: mappedData(cropsToQuoteFilteredP14s),
		type: 'P14'
	});
	const { userPreferencesData: userPreferences } = useUserPreferencesContext();
	const { logEvent, userFullName } = useEventLogging();

	const handleDownload = useCallback(() => {
		setLoading(true);
		const headerData: TPDFHeaderData = {
			userData: { email: username, fullName, logoURL, phoneNumber },
			policyData: {
				producerName: quote?.producerName,
				producerType: quote?.producerType,
				policyNumber: quote?.p10Data && quote?.p10Data[0]?.policyNumber,
				cropYear: quote?.reinsuranceYear
			},
			quoteNumber: `${t('common.quote')}: ${quote?.reinsuranceYear}-${
				quote?.quoteId
			}`
		};
		const quoterActiveFilters: TQuoterActiveFilters = {
			CLUs: checkedFilters.P11,
			units: checkedFilters.P15
		};
		const configFilters: TConfigFilters = {
			filterCLUs: shareQuoteConfig.filterCLUs,
			filterUnits: shareQuoteConfig.filterCLUs
				? true
				: shareQuoteConfig.filterLocations
		};
		pdf(
			<QuoteOutputDocument
				quote={quote}
				p14s={p14s}
				orderedP14s={sortedAndFilteredCrops as TInsuranceInForce[]}
				tableOptions={tableOptions}
				summary={shareQuoteConfig.summary}
				headerData={headerData}
				getUnitOfMeasure={getUnitOfMeasure}
				userPreferences={userPreferences}
				quoterActiveFilters={quoterActiveFilters}
				configFilters={configFilters}
			/>
		)
			.toBlob()
			.then(async initialBlob => {
				if (shareQuoteConfig.includePamphlets) {
					const appendixBlobs = await resolveAppendix();
					return [initialBlob, ...appendixBlobs];
				}
				return initialBlob;
			})
			.then(async data => {
				if (shareQuoteConfig.includePamphlets && Array.isArray(data)) {
					const merger = new PDFMerger();
					for (const blob of data) {
						const arrayBuffer = await blob?.arrayBuffer();
						if (arrayBuffer) {
							await merger.add(arrayBuffer, null);
						}
					}
					// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- type definition wrong, will change once library updates
					// @ts-ignore
					const mergedPdf = await merger.saveAsBlob();
					return mergedPdf;
				}
				return data;
			})
			.then(instance => {
				const url = URL.createObjectURL(instance);
				const link = document.createElement('a');
				link.href = url;
				link.download = `Quote-${quote?.reinsuranceYear}-${quote?.quoteId}.pdf`;
				link.click();
				setLoading(false);
				logEvent({ event: 'ShareQuote', section: 'Quoter', userFullName });
			})
			.catch(error => {
				console.error(error);
				toast.error(t('shareQuote.downloadPDFError'));
				setLoading(false);
			});
	}, [quote, tableOptions, sortedAndFilteredCrops, shareQuoteConfig, t]);

	return { loading, handleDownload };
};

daredevil1302 avatar Jul 08 '24 07:07 daredevil1302