-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Recreate a receipt for native #54358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
neil-marcellini
merged 43 commits into
Expensify:main
from
callstack-internal:fix/51761-recreate-receipt
Jan 29, 2025
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
acdd2e2
Add file handling utilities and enhance form data processing draft
rezkiy37 50c4f59
remove dev prop
rezkiy37 0c2b632
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 2446bb8
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 18d637f
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 04cff7b
Refactor file reading logic to import readFileAsync dynamically and r…
rezkiy37 8dd63c2
remove import
rezkiy37 a9dbba9
Add initiatedOffline parameter to HTTP request handling for offline s…
rezkiy37 02ae8cd
Add initiatedOffline property to persistedRequest in SequentialQueueTest
rezkiy37 754949c
Add initiatedOffline property to persistedRequest in SequentialQueueTest
rezkiy37 0888f6b
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 6f7f4a4
clean processFormData
rezkiy37 c1a5306
integrate prepareRequestPayload
rezkiy37 e12d29c
integrate prepareRequestPayload
rezkiy37 3a389bf
clean
rezkiy37 b899c11
lazy load readFileAsync in prepareRequestPayload
rezkiy37 38b1224
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 713c51f
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 8841ac4
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 87db8e0
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 9d86ba4
use correct value to validate
rezkiy37 4e79434
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 e9f0e86
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 bd16813
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 83f28a3
fix no-restricted-syntax in SequentialQueueTest
rezkiy37 41bbf51
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 ff738b5
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 c21920e
Enhance documentation for initiatedOffline field in RequestData type
rezkiy37 28efbe4
Add initiatedOffline flag to requests in API and SequentialQueue
rezkiy37 faa122a
Add documentation for prepareRequestPayload function in native platforms
rezkiy37 e710d42
Refactor file reading logic in prepareRequestPayload to directly impo…
rezkiy37 cad3e6f
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 0ce0a09
Mock fileDownload utility in tests to isolate file reading functionality
rezkiy37 bc698ea
Refactor imports to use named exports for consistency and clarity
rezkiy37 d2963fc
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 23ac663
Fix expectations for API command calls in Report actions test
rezkiy37 f6304bb
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 c4b9318
Revert "Fix expectations for API command calls in Report actions test"
rezkiy37 65d23a5
Revert "Mock fileDownload utility in tests to isolate file reading fu…
rezkiy37 57f62c8
Mock prepareRequestPayload for tests globally
rezkiy37 4efd175
Refactor prepareRequestPayload mock to handle dynamic data appending
rezkiy37 ff8d096
Revert "Refactor imports to use named exports for consistency and cla…
rezkiy37 6d19d5f
Refactor ValidationUtilsTest to use translateLocal for localization
rezkiy37 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import {readFileAsync} from '@libs/fileDownload/FileUtils'; | ||
| import validateFormDataParameter from '@libs/validateFormDataParameter'; | ||
| import type PrepareRequestPayload from './types'; | ||
|
|
||
| /** | ||
| * Prepares the request payload (body) for a given command and data. | ||
| * This function is specifically designed for native platforms (IOS and Android) to handle the regeneration of blob files. It ensures that files, such as receipts, are properly read and appended to the FormData object before the request is sent. | ||
| */ | ||
| const prepareRequestPayload: PrepareRequestPayload = (command, data, initiatedOffline) => { | ||
| const formData = new FormData(); | ||
| let promiseChain = Promise.resolve(); | ||
|
|
||
| Object.keys(data).forEach((key) => { | ||
| promiseChain = promiseChain.then(() => { | ||
| const value = data[key]; | ||
|
|
||
| if (value === undefined) { | ||
| return Promise.resolve(); | ||
| } | ||
|
|
||
| if (key === 'receipt' && initiatedOffline) { | ||
| const {uri: path = '', source} = value as File; | ||
|
|
||
| return readFileAsync(source, path, () => {}).then((file) => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Coming from #76975, we should use the actual file name if available, otherwise fall back to extracting from path/uri |
||
| if (!file) { | ||
| return; | ||
| } | ||
|
|
||
| validateFormDataParameter(command, key, file); | ||
| formData.append(key, file); | ||
| }); | ||
| } | ||
|
|
||
| validateFormDataParameter(command, key, value); | ||
| formData.append(key, value as string | Blob); | ||
|
|
||
| return Promise.resolve(); | ||
| }); | ||
| }); | ||
|
|
||
| return promiseChain.then(() => formData); | ||
| }; | ||
|
|
||
| export default prepareRequestPayload; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import validateFormDataParameter from '@libs/validateFormDataParameter'; | ||
| import type PrepareRequestPayload from './types'; | ||
|
|
||
| /** | ||
| * Prepares the request payload (body) for a given command and data. | ||
| */ | ||
| const prepareRequestPayload: PrepareRequestPayload = (command, data) => { | ||
| const formData = new FormData(); | ||
|
|
||
| Object.keys(data).forEach((key) => { | ||
| const value = data[key]; | ||
|
|
||
| if (value === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| validateFormDataParameter(command, key, value); | ||
| formData.append(key, value as string | Blob); | ||
| }); | ||
|
|
||
| return Promise.resolve(formData); | ||
| }; | ||
|
|
||
| export default prepareRequestPayload; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| type PrepareRequestPayload = (command: string, data: Record<string, unknown>, initiatedOffline: boolean) => Promise<FormData>; | ||
|
|
||
| export default PrepareRequestPayload; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import CONST from '@src/CONST'; | ||
| import getPlatform from './getPlatform'; | ||
|
|
||
| const platform = getPlatform(); | ||
| const isNativePlatform = platform === CONST.PLATFORM.ANDROID || platform === CONST.PLATFORM.IOS; | ||
|
|
||
| /** | ||
| * Ensures no value of type `object` other than null, Blob, its subclasses, or {uri: string} (native platforms only) is passed to XMLHttpRequest. | ||
| * Otherwise, it will be incorrectly serialized as `[object Object]` and cause an error on Android. | ||
| * See https://github.com/Expensify/App/issues/45086 | ||
| */ | ||
| function validateFormDataParameter(command: string, key: string, value: unknown) { | ||
| // eslint-disable-next-line @typescript-eslint/no-shadow | ||
| const isValid = (value: unknown, isTopLevel: boolean): boolean => { | ||
| if (value === null || typeof value !== 'object') { | ||
| return true; | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.every((element) => isValid(element, false)); | ||
| } | ||
| if (isTopLevel) { | ||
| // Native platforms only require the value to include the `uri` property. | ||
| // Optionally, it can also have a `name` and `type` props. | ||
| // On other platforms, the value must be an instance of `Blob`. | ||
| return isNativePlatform ? 'uri' in value && !!value.uri : value instanceof Blob; | ||
| } | ||
| return false; | ||
| }; | ||
|
|
||
| if (!isValid(value, true)) { | ||
| // eslint-disable-next-line no-console | ||
| console.warn(`An unsupported value was passed to command '${command}' (parameter: '${key}'). Only Blob and primitive types are allowed.`); | ||
| } | ||
| } | ||
|
|
||
| export default validateFormDataParameter; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.