Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,9 @@ function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string,
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants});
}

function setMoneyRequestReceipt(transactionID: string, source: string, filename: string, isDraft: boolean) {
function setMoneyRequestReceipt(transactionID: string, source: string, filename: string, isDraft: boolean, type?: string) {
Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {
receipt: {source},
receipt: {source, type: type ?? ''},
filename,
});
}
Expand Down Expand Up @@ -4066,6 +4066,7 @@ function navigateToStartStepIfScanFileCannotBeRead(
iouType: ValueOf<typeof CONST.IOU.TYPE>,
transactionID: string,
reportID: string,
receiptType: string,
) {
if (!receiptFilename || !receiptPath) {
return;
Expand All @@ -4079,7 +4080,7 @@ function navigateToStartStepIfScanFileCannotBeRead(
}
IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID);
};
FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure);
FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure, receiptType);
}

/** Save the preferred payment method for a policy */
Expand Down
6 changes: 4 additions & 2 deletions src/libs/fileDownload/FileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ function appendTimeToFileName(fileName: string): string {
* @param path - the blob url of the locally uploaded file
* @param fileName - name of the file to read
*/
const readFileAsync: ReadFileAsync = (path, fileName, onSuccess, onFailure = () => {}) =>
const readFileAsync: ReadFileAsync = (path, fileName, onSuccess, onFailure = () => {}, fileType = '') =>
new Promise((resolve) => {
if (!path) {
resolve();
Expand All @@ -176,7 +176,9 @@ const readFileAsync: ReadFileAsync = (path, fileName, onSuccess, onFailure = ()
}
res.blob()
.then((blob) => {
const file = new File([blob], cleanFileName(fileName), {type: blob.type});
// On Android devices, fetching blob for a file with name containing spaces fails to retrieve the type of file.
// In this case, let us fallback on fileType provided by the caller of this function.
const file = new File([blob], cleanFileName(fileName), {type: blob.type || fileType});
file.source = path;
// For some reason, the File object on iOS does not have a uri property
// so images aren't uploaded correctly to the backend
Expand Down
2 changes: 1 addition & 1 deletion src/libs/fileDownload/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type GetImageResolution = (url: File | Asset) => Promise<ImageResolution>;
type ExtensionAndFileName = {fileName: string; fileExtension: string};
type SplitExtensionFromFileName = (fileName: string) => ExtensionAndFileName;

type ReadFileAsync = (path: string, fileName: string, onSuccess: (file: File) => void, onFailure: (error?: unknown) => void) => Promise<File | void>;
type ReadFileAsync = (path: string, fileName: string, onSuccess: (file: File) => void, onFailure: (error?: unknown) => void, fileType?: string) => Promise<File | void>;

type AttachmentDetails = {
previewSourceURL: null | string;
Expand Down
5 changes: 3 additions & 2 deletions src/pages/iou/request/step/IOURequestStepConfirmation.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ function IOURequestStepConfirmation({
const [receiptFile, setReceiptFile] = useState();
const receiptFilename = lodashGet(transaction, 'filename');
const receiptPath = lodashGet(transaction, 'receipt.source');
const receiptType = lodashGet(transaction, 'receipt.type');
const transactionTaxCode = transaction.taxRate && transaction.taxRate.keyForList;
const transactionTaxAmount = transaction.taxAmount;
const requestType = TransactionUtils.getRequestType(transaction);
Expand Down Expand Up @@ -179,8 +180,8 @@ function IOURequestStepConfirmation({
setReceiptFile(receipt);
};

IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID);
}, [receiptPath, receiptFilename, requestType, iouType, transactionID, reportID]);
IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID, receiptType);
}, [receiptType, receiptPath, receiptFilename, requestType, iouType, transactionID, reportID]);

useEffect(() => {
const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat);
Expand Down
5 changes: 3 additions & 2 deletions src/pages/iou/request/step/IOURequestStepParticipants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ function IOURequestStepParticipants({
const headerTitle = translate(TransactionUtils.getHeaderTitleTranslationKey(transaction));
const receiptFilename = lodashGet(transaction, 'filename');
const receiptPath = lodashGet(transaction, 'receipt.source');
const receiptType = lodashGet(transaction, 'receipt.type');

// When the component mounts, if there is a receipt, see if the image can be read from the disk. If not, redirect the user to the starting step of the flow.
// This is because until the request is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then
// the image ceases to exist. The best way for the user to recover from this is to start over from the start of the request process.
useEffect(() => {
IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, () => {}, iouRequestType, iouType, transactionID, reportID);
}, [receiptPath, receiptFilename, iouRequestType, iouType, transactionID, reportID]);
IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, () => {}, iouRequestType, iouType, transactionID, reportID, receiptType);
}, [receiptType, receiptPath, receiptFilename, iouRequestType, iouType, transactionID, reportID]);

const addParticipant = useCallback(
(val) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,9 @@ function IOURequestStepScan({
}

// Store the receipt on the transaction object in Onyx
IOU.setMoneyRequestReceipt(transactionID, file.uri, file.name, action !== CONST.IOU.ACTION.EDIT);
// On Android devices, fetching blob for a file with name containing spaces fails to retrieve the type of file.
// So, let us also save the file type in receipt for later use during blob fetch
IOU.setMoneyRequestReceipt(transactionID, file.uri, file.name, action !== CONST.IOU.ACTION.EDIT, file.type);

if (action === CONST.IOU.ACTION.EDIT) {
updateScanAndNavigate(file, file.uri);
Expand Down
1 change: 1 addition & 0 deletions src/types/onyx/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Receipt = {
source?: ReceiptSource;
filename?: string;
state?: ValueOf<typeof CONST.IOU.RECEIPT_STATE>;
type?: string;
};

type Route = {
Expand Down