Skip to content

Commit

Permalink
Merge pull request #32678 from tienifr/fix/32232
Browse files Browse the repository at this point in the history
Fix: PDF is not cached
  • Loading branch information
MonilBhavsar authored Feb 28, 2024
2 parents c6dd8ca + abd5347 commit b8e0989
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ const ONYXKEYS = {
/** Indicates whether we should store logs or not */
SHOULD_STORE_LOGS: 'shouldStoreLogs',

// Paths of PDF file that has been cached during one session
CACHED_PDF_PATHS: 'cachedPDFPaths',

/** Collection Keys */
COLLECTION: {
DOWNLOAD: 'download_',
Expand Down Expand Up @@ -564,6 +567,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.PLAID_CURRENT_EVENT]: string;
[ONYXKEYS.LOGS]: Record<number, OnyxTypes.Log>;
[ONYXKEYS.SHOULD_STORE_LOGS]: boolean;
[ONYXKEYS.CACHED_PDF_PATHS]: Record<string, string>;
};

type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function CarouselItem({item, onPress, isFocused, isModalHovered}) {
isAuthTokenRequired={item.isAuthTokenRequired}
onPress={onPress}
transactionID={item.transactionID}
reportActionID={item.reportActionID}
isHovered={isModalHovered}
isFocused={isFocused}
optionalVideoDuration={item.duration}
Expand Down
17 changes: 16 additions & 1 deletion src/components/Attachments/AttachmentView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import useNetwork from '@hooks/useNetwork';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CachedPDFPaths from '@libs/actions/CachedPDFPaths';
import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
import compose from '@libs/compose';
import * as TransactionUtils from '@libs/TransactionUtils';
Expand Down Expand Up @@ -57,6 +58,9 @@ const propTypes = {
// eslint-disable-next-line react/no-unused-prop-types
transactionID: PropTypes.string,

/** The id of the report action related to the attachment */
reportActionID: PropTypes.string,

isHovered: PropTypes.bool,

optionalVideoDuration: PropTypes.number,
Expand All @@ -71,6 +75,7 @@ const defaultProps = {
isWorkspaceAvatar: false,
maybeIcon: false,
transactionID: '',
reportActionID: '',
isHovered: false,
optionalVideoDuration: 0,
};
Expand All @@ -92,6 +97,7 @@ function AttachmentView({
maybeIcon,
fallbackSource,
transaction,
reportActionID,
isHovered,
optionalVideoDuration,
}) {
Expand Down Expand Up @@ -153,6 +159,15 @@ function AttachmentView({
if ((_.isString(source) && Str.isPDF(source)) || (file && Str.isPDF(file.name || translate('attachmentView.unknownFilename')))) {
const encryptedSourceUrl = isAuthTokenRequired ? addEncryptedAuthTokenToURL(source) : source;

const onPDFLoadComplete = (path) => {
if (path && (transaction.transactionID || reportActionID)) {
CachedPDFPaths.add(transaction.transactionID || reportActionID, path);
}
if (!loadComplete) {
setLoadComplete(true);
}
};

// We need the following View component on android native
// So that the event will propagate properly and
// the Password protected preview will be shown for pdf attachement we are about to send.
Expand All @@ -166,7 +181,7 @@ function AttachmentView({
encryptedSourceUrl={encryptedSourceUrl}
onPress={onPress}
onToggleKeyboard={onToggleKeyboard}
onLoadComplete={() => !loadComplete && setLoadComplete(true)}
onLoadComplete={onPDFLoadComplete}
errorLabelStyles={isUsedInAttachmentModal ? [styles.textLabel, styles.textLarge] : [styles.cursorAuto]}
style={isUsedInAttachmentModal ? styles.imageModalPDF : styles.flex1}
isUsedInCarousel={isUsedInCarousel}
Expand Down
8 changes: 5 additions & 3 deletions src/components/PDFView/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ function PDFView({onToggleKeyboard, onLoadComplete, fileName, onPress, isFocused
/**
* After the PDF is successfully loaded hide PDFPasswordForm and the loading
* indicator.
* @param {Number} numberOfPages
* @param {Number} path - Path to cache location
*/
const finishPDFLoad = () => {
const finishPDFLoad = (numberOfPages, path) => {
setShouldRequestPassword(false);
setShouldShowLoadingIndicator(false);
setSuccessToLoadPDF(true);
onLoadComplete();
onLoadComplete(path);
};

function renderPDFView() {
Expand Down Expand Up @@ -137,7 +139,7 @@ function PDFView({onToggleKeyboard, onLoadComplete, fileName, onPress, isFocused
fitPolicy={0}
trustAllCerts={false}
renderActivityIndicator={() => <FullScreenLoadingIndicator />}
source={{uri: sourceURL}}
source={{uri: sourceURL, cache: true, expiration: 864000}}
style={pdfStyles}
onError={handleFailureToLoadPDF}
password={password}
Expand Down
47 changes: 47 additions & 0 deletions src/libs/actions/CachedPDFPaths/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {exists, unlink} from 'react-native-fs';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Add, Clear, ClearAll, ClearByKey} from './types';

/*
* We need to save the paths of PDF files so we can delete them later.
* This is to remove the cached PDFs when an attachment is deleted or the user logs out.
*/
let pdfPaths: Record<string, string> = {};
Onyx.connect({
key: ONYXKEYS.CACHED_PDF_PATHS,
callback: (val) => {
pdfPaths = val ?? {};
},
});

const add: Add = (id: string, path: string) => {
if (pdfPaths[id]) {
return Promise.resolve();
}
return Onyx.merge(ONYXKEYS.CACHED_PDF_PATHS, {[id]: path});
};

const clear: Clear = (path: string) => {
if (!path) {
return Promise.resolve();
}
return new Promise((resolve) => {
exists(path).then((exist) => {
if (!exist) {
resolve();
}
return unlink(path);
});
});
};

const clearByKey: ClearByKey = (id: string) => {
clear(pdfPaths[id] ?? '').then(() => Onyx.merge(ONYXKEYS.CACHED_PDF_PATHS, {[id]: null}));
};

const clearAll: ClearAll = () => {
Promise.all(Object.values(pdfPaths).map(clear)).then(() => Onyx.merge(ONYXKEYS.CACHED_PDF_PATHS, {}));
};

export {add, clearByKey, clearAll};
9 changes: 9 additions & 0 deletions src/libs/actions/CachedPDFPaths/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type {Add, ClearAll, ClearByKey} from './types';

const add: Add = () => Promise.resolve();

const clearByKey: ClearByKey = () => {};

const clearAll: ClearAll = () => {};

export {add, clearByKey, clearAll};
6 changes: 6 additions & 0 deletions src/libs/actions/CachedPDFPaths/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type Add = (id: string, path: string) => Promise<void>;
type Clear = (path: string) => Promise<void>;
type ClearAll = () => void;
type ClearByKey = (id: string) => void;

export type {Add, Clear, ClearAll, ClearByKey};
2 changes: 2 additions & 0 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import type {OnyxData} from '@src/types/onyx/Request';
import type {Comment, Receipt, ReceiptSource, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import * as CachedPDFPaths from './CachedPDFPaths';
import * as Policy from './Policy';
import * as Report from './Report';

Expand Down Expand Up @@ -3162,6 +3163,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor

// STEP 6: Make the API request
API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
CachedPDFPaths.clearByKey(transactionID);

// STEP 7: Navigate the user depending on which page they are on and which resources were deleted
if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
Expand Down
2 changes: 2 additions & 0 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/Rep
import type ReportAction from '@src/types/onyx/ReportAction';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import * as CachedPDFPaths from './CachedPDFPaths';
import * as Modal from './Modal';
import * as Session from './Session';
import * as Welcome from './Welcome';
Expand Down Expand Up @@ -1224,6 +1225,7 @@ function deleteReportComment(reportID: string, reportAction: ReportAction) {
reportActionID,
};

CachedPDFPaths.clearByKey(reportActionID);
API.write(WRITE_COMMANDS.DELETE_COMMENT, parameters, {optimisticData, successData, failureData});
}

Expand Down

0 comments on commit b8e0989

Please sign in to comment.