Skip to content
Open
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
14 changes: 10 additions & 4 deletions src/pages/Share/SubmitDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,13 @@ function SubmitDetailsPage({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [reportOrAccountID, policy, personalPolicy, report, parentReport, currentDate, currentUserPersonalDetails, hasOnlyPersonalPolicies]);

const sharedFileSource = currentAttachment?.content ?? fileUri;
const sharedFileName = getFileName(currentAttachment?.content ?? '') || fileName;
const sharedFileType = currentAttachment?.mimeType ?? fileType;
// Use the branch-aware values computed above: for a share that needs conversion (e.g. HEIC), these resolve to the
// converted JPEG from VALIDATED_FILE_OBJECT; otherwise they fall back to the raw attachment. Re-deriving from
// currentAttachment here would discard the converted file (its content/mimeType are always set), uploading raw
// image/heic which the backend rejects. This mirrors ShareDetailsPage.
const sharedFileSource = fileUri;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ensure the validated file belongs to the current share

For HEIC/image/* shares this now seeds the submit receipt from the global VALIDATED_FILE_OBJECT, but that Onyx value is not tied to the current SHARE_TEMP_FILE. ShareRootPage starts validation asynchronously and clearShareData() only nulls the key; an earlier share's conversion can still finish later and call addValidatedShareFile, leaving a stale JPEG here. In that window, the Submit tab can display/upload the previous share's converted file instead of the newly shared receipt, so please verify the validated file matches the current attachment (for example via its original id/source) before using it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I think we don't need to gate this

const sharedFileName = fileName;
const sharedFileType = fileType;

// Seed the draft so isScanRequest() returns true (enables compact mode + receipt rendering).
useEffect(() => {
Expand Down Expand Up @@ -409,7 +413,9 @@ function SubmitDetailsPage({

// Separate helper so the permission-modal callbacks don't re-enter onConfirm (deadlocked when OS permission was pre-granted).
const performUpload = (locationPermissionGranted: boolean) => {
if (formHasBeenSubmitted.current || !currentAttachment) {
// Block confirm until the async HEIC→JPEG conversion has landed in VALIDATED_FILE_OBJECT, so a fast tap can't
// submit the raw file. Clearing isConfirming keeps the button from getting stuck, so a retry succeeds once ready.
if (formHasBeenSubmitted.current || !currentAttachment || (shouldUsePreValidatedFile && !validFilesToUpload)) {
setIsConfirming(false);
return;
}
Expand Down
29 changes: 29 additions & 0 deletions tests/ui/SubmitDetailsPageTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import {act, fireEvent, render, screen} from '@testing-library/react-native';

import {readFileAsync} from '@libs/fileDownload/FileUtils';
import Log from '@libs/Log';

import SubmitDetailsPage from '@pages/Share/SubmitDetailsPage';
Expand Down Expand Up @@ -214,4 +215,32 @@ describe('SubmitDetailsPage', () => {

logInfoSpy.mockRestore();
});

it('uploads the converted JPEG (not the raw HEIC) when the shared file needed validation', async () => {
// A HEIC share: SHARE_TEMP_FILE holds the raw .heic file, VALIDATED_FILE_OBJECT holds the converted JPEG.
await act(async () => {
await Onyx.merge(ONYXKEYS.SHARE_TEMP_FILE, {content: 'file://shared.heic', mimeType: CONST.SHARE_FILE_MIMETYPE.HEIC});
await Onyx.merge(ONYXKEYS.VALIDATED_FILE_OBJECT, {uri: 'file://converted.jpg', type: CONST.RECEIPT_ALLOWED_FILE_TYPES.JPEG});
});

await renderAndConfirm();

// The upload must read the converted JPEG, never the raw .heic the backend rejects.
const readFileArg = jest.mocked(readFileAsync).mock.calls.at(0);
expect(readFileArg?.[0]).toBe('file://converted.jpg');
expect(readFileArg?.[4]).toBe(CONST.RECEIPT_ALLOWED_FILE_TYPES.JPEG);
});

it('does not upload while a share that needs validation is still awaiting its converted file', async () => {
// A HEIC share whose conversion has not landed yet: VALIDATED_FILE_OBJECT is empty.
await act(async () => {
await Onyx.merge(ONYXKEYS.SHARE_TEMP_FILE, {content: 'file://shared.heic', mimeType: CONST.SHARE_FILE_MIMETYPE.HEIC});
await Onyx.set(ONYXKEYS.VALIDATED_FILE_OBJECT, undefined);
});

await renderAndConfirm();

// Confirm must bail out (no raw HEIC uploaded) until the converted file is ready.
expect(jest.mocked(readFileAsync)).not.toHaveBeenCalled();
});
});
Loading