Skip to content

Commit 338777e

Browse files
authored
Merge pull request Expensify#88426 from Expensify/claude-addCorpayPerFileUploadSizeLimit
Add 2MB per-file size limit for Corpay document uploads
2 parents 5ee59ef + fe2f998 commit 338777e

6 files changed

Lines changed: 68 additions & 29 deletions

File tree

src/CONST/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,10 +738,13 @@ const CONST = {
738738
PERSONAL: 'PERSONAL',
739739
},
740740
},
741-
NON_USD_BANK_ACCOUNT: {
741+
CORPAY_DOCUMENT: {
742742
ALLOWED_FILE_TYPES: ['pdf', 'jpg', 'jpeg', 'png'],
743743
FILE_LIMIT: 1,
744+
MAX_FILE_SIZE: 2097152,
744745
TOTAL_FILES_SIZE_LIMIT: 5242880,
746+
},
747+
NON_USD_BANK_ACCOUNT: {
745748
PURPOSE_OF_TRANSACTION_ID: 'Intercompany_Payment',
746749
CURRENT_USER_KEY: 'currentUser',
747750
CORPAY_UNDEFINED_OPTION_VALUE: 'Undefined',

src/components/SubStepForms/DocusignFullStep.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import React, {useCallback, useState} from 'react';
1+
import React, {useCallback, useRef, useState} from 'react';
22
import Button from '@components/Button';
33
import FormProvider from '@components/Form/FormProvider';
44
import InputWrapper from '@components/Form/InputWrapper';
5-
import type {FormInputErrors, FormOnyxKeys, FormOnyxValues} from '@components/Form/types';
5+
import type {FormInputErrors, FormOnyxKeys, FormOnyxValues, FormRef} from '@components/Form/types';
66
import InteractiveStepWrapper from '@components/InteractiveStepWrapper';
77
import Text from '@components/Text';
88
import UploadFile from '@components/UploadFile';
@@ -61,6 +61,8 @@ function DocusignFullStep<TFormID extends keyof OnyxFormValuesMapping>({
6161
const styles = useThemeStyles();
6262
const {environmentURL} = useEnvironment();
6363

64+
const formRef = useRef<FormRef | null>(null);
65+
6466
const [uploadedFiles, setUploadedFiles] = useState<FileObject[]>(defaultValue);
6567

6668
const validate = useCallback(
@@ -87,6 +89,8 @@ function DocusignFullStep<TFormID extends keyof OnyxFormValuesMapping>({
8789
return;
8890
}
8991

92+
formRef.current?.resetFormFieldError(inputID as string);
93+
clearErrors(formID);
9094
setErrorFields(formID, {[inputID]: {onUpload: error}});
9195
};
9296

@@ -106,6 +110,7 @@ function DocusignFullStep<TFormID extends keyof OnyxFormValuesMapping>({
106110
startStepIndex={startStepIndex}
107111
>
108112
<FormProvider
113+
ref={formRef}
109114
formID={formID}
110115
submitButtonText={translate('common.submit')}
111116
onSubmit={onSubmit}
@@ -148,13 +153,14 @@ function DocusignFullStep<TFormID extends keyof OnyxFormValuesMapping>({
148153
onRemove={(fileName) => {
149154
handleRemoveFile(fileName);
150155
}}
151-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
156+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
152157
value={uploadedFiles}
153158
inputID={inputID as string}
154159
setError={(error) => {
155160
setUploadError(error);
156161
}}
157162
fileLimit={1}
163+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
158164
/>
159165
</FormProvider>
160166
</InteractiveStepWrapper>

src/components/UploadFile.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ type UploadFileProps = {
4949

5050
/** The total size limit of the files that can be selected. */
5151
totalFilesSizeLimit?: number;
52+
53+
/** The maximum size of a single file that can be selected. */
54+
maxFileSize?: number;
5255
};
5356

5457
function UploadFile({
@@ -63,6 +66,7 @@ function UploadFile({
6366
onInputChange = () => {},
6467
totalFilesSizeLimit = 0,
6568
fileLimit = 0,
69+
maxFileSize = 0,
6670
}: UploadFileProps) {
6771
const icons = useMemoizedLazyExpensifyIcons(['Close', 'Paperclip']);
6872
const {translate} = useLocalize();
@@ -73,6 +77,14 @@ function UploadFile({
7377

7478
const totalSize = resultedFiles.reduce((sum, file) => sum + (file.size ?? 0), 0);
7579

80+
if (maxFileSize) {
81+
const oversizedFile = files.find((file) => (file.size ?? 0) > maxFileSize);
82+
if (oversizedFile) {
83+
setError(translate('attachmentPicker.sizeExceededWithLimit', maxFileSize / (1024 * 1024)));
84+
return;
85+
}
86+
}
87+
7688
if (totalFilesSizeLimit) {
7789
if (totalSize > totalFilesSizeLimit) {
7890
setError(translate('attachmentPicker.sizeExceededWithValue', totalFilesSizeLimit / (1024 * 1024)));

src/pages/ReimbursementAccount/EnterSignerInfo/subSteps/UploadDocuments.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ function UploadDocuments({onNext, isEditing, policyID}: UploadDocumentsProps) {
140140
onRemove={(fileName) => {
141141
handleRemoveFile(fileName, uploadedIDs, copyOfIDInputID, setUploadedID);
142142
}}
143-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
143+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
144144
value={uploadedIDs}
145145
inputID={copyOfIDInputID}
146146
setError={(error) => {
@@ -168,7 +168,7 @@ function UploadDocuments({onNext, isEditing, policyID}: UploadDocumentsProps) {
168168
onRemove={(fileName) => {
169169
handleRemoveFile(fileName, uploadedProofsOfAddress, addressProofInputID, setUploadedProofOfAddress);
170170
}}
171-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
171+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
172172
value={uploadedProofsOfAddress}
173173
inputID={addressProofInputID}
174174
setError={(error) => {
@@ -195,7 +195,7 @@ function UploadDocuments({onNext, isEditing, policyID}: UploadDocumentsProps) {
195195
onRemove={(fileName) => {
196196
handleRemoveFile(fileName, uploadedProofsOfDirectors, directorsProofInputID, setUploadedProofsOfDirectors);
197197
}}
198-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
198+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
199199
value={uploadedProofsOfDirectors}
200200
inputID={directorsProofInputID}
201201
setError={(error) => {

src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormSubSteps/Documents.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import React, {useCallback, useMemo, useState} from 'react';
1+
import React, {useCallback, useMemo, useRef, useState} from 'react';
22
import {View} from 'react-native';
33
import FormProvider from '@components/Form/FormProvider';
44
import InputWrapper from '@components/Form/InputWrapper';
5-
import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
5+
import type {FormInputErrors, FormOnyxValues, FormRef} from '@components/Form/types';
66
import Text from '@components/Text';
77
import UploadFile from '@components/UploadFile';
88
import useLocalize from '@hooks/useLocalize';
@@ -13,7 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
1313
import {getFieldRequiredErrors} from '@libs/ValidationUtils';
1414
import getCurrencyForNonUSDBankAccount from '@pages/ReimbursementAccount/NonUSD/utils/getCurrencyForNonUSDBankAccount';
1515
import getNeededDocumentsStatusForBeneficialOwner from '@pages/ReimbursementAccount/NonUSD/utils/getNeededDocumentsStatusForBeneficialOwner';
16-
import {clearErrorFields, setDraftValues, setErrorFields} from '@userActions/FormActions';
16+
import {clearErrorFields, clearErrors, setDraftValues, setErrorFields} from '@userActions/FormActions';
1717
import CONST from '@src/CONST';
1818
import ONYXKEYS from '@src/ONYXKEYS';
1919
import type {FileObject} from '@src/types/utils/Attachment';
@@ -45,6 +45,8 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
4545
[codiceFiscaleInputID]: Array.isArray(reimbursementAccountDraft?.[codiceFiscaleInputID]) ? (reimbursementAccountDraft?.[codiceFiscaleInputID] ?? []) : [],
4646
};
4747

48+
const formRef = useRef<FormRef | null>(null);
49+
4850
const [uploadedProofOfOwnership, setUploadedProofOfOwnership] = useState<FileObject[]>(defaultValues[proofOfOwnershipInputID]);
4951
const [uploadedCopyOfID, setUploadedCopyOfID] = useState<FileObject[]>(defaultValues[copyOfIDInputID]);
5052
const [uploadedAddressProof, setUploadedAddressProof] = useState<FileObject[]>(defaultValues[addressProofInputID]);
@@ -78,6 +80,8 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
7880
return;
7981
}
8082

83+
formRef.current?.resetFormFieldError(inputID);
84+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
8185
setErrorFields(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {[inputID]: {onUpload: error}});
8286
};
8387

@@ -97,6 +101,7 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
97101

98102
return (
99103
<FormProvider
104+
ref={formRef}
100105
formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
101106
submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
102107
validate={validate}
@@ -124,8 +129,9 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
124129
setError={(error) => {
125130
setUploadError(error, proofOfOwnershipInputID);
126131
}}
127-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
128-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
132+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
133+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
134+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
129135
value={defaultValues[proofOfOwnershipInputID]}
130136
inputID={proofOfOwnershipInputID}
131137
/>
@@ -152,8 +158,9 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
152158
setError={(error) => {
153159
setUploadError(error, copyOfIDInputID);
154160
}}
155-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
156-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
161+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
162+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
163+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
157164
value={defaultValues[copyOfIDInputID]}
158165
inputID={copyOfIDInputID}
159166
/>
@@ -178,8 +185,9 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
178185
setError={(error) => {
179186
setUploadError(error, addressProofInputID);
180187
}}
181-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
182-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
188+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
189+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
190+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
183191
value={defaultValues[addressProofInputID]}
184192
inputID={addressProofInputID}
185193
/>
@@ -204,8 +212,9 @@ function Documents({onNext, isEditing, ownerBeingModifiedID}: DocumentsProps) {
204212
setError={(error) => {
205213
setUploadError(error, codiceFiscaleInputID);
206214
}}
207-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
208-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
215+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
216+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
217+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
209218
value={defaultValues[codiceFiscaleInputID]}
210219
inputID={codiceFiscaleInputID}
211220
/>

src/pages/ReimbursementAccount/NonUSD/SignerInfo/subSteps/UploadDocuments.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import React, {useEffect, useState} from 'react';
1+
import React, {useEffect, useRef, useState} from 'react';
22
import {View} from 'react-native';
33
import Button from '@components/Button';
44
import DotIndicatorMessage from '@components/DotIndicatorMessage';
55
import FormProvider from '@components/Form/FormProvider';
66
import InputWrapper from '@components/Form/InputWrapper';
7-
import type {FormInputErrors, FormOnyxKeys, FormOnyxValues} from '@components/Form/types';
7+
import type {FormInputErrors, FormOnyxKeys, FormOnyxValues, FormRef} from '@components/Form/types';
88
import Text from '@components/Text';
99
import UploadFile from '@components/UploadFile';
1010
import useLocalize from '@hooks/useLocalize';
@@ -17,7 +17,7 @@ import {getFieldRequiredErrors} from '@libs/ValidationUtils';
1717
import getCurrencyForNonUSDBankAccount from '@pages/ReimbursementAccount/NonUSD/utils/getCurrencyForNonUSDBankAccount';
1818
import getNeededDocumentsStatusForSignerInfo from '@pages/ReimbursementAccount/utils/getNeededDocumentsStatusForSignerInfo';
1919
import WhyLink from '@pages/ReimbursementAccount/WhyLink';
20-
import {clearErrorFields, setDraftValues, setErrorFields} from '@userActions/FormActions';
20+
import {clearErrorFields, clearErrors, setDraftValues, setErrorFields} from '@userActions/FormActions';
2121
import {openExternalLink} from '@userActions/Link';
2222
import CONST from '@src/CONST';
2323
import ONYXKEYS from '@src/ONYXKEYS';
@@ -50,6 +50,8 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
5050
[CODICE_FISCALE]: Array.isArray(reimbursementAccountDraft?.[CODICE_FISCALE]) ? (reimbursementAccountDraft?.[CODICE_FISCALE] ?? []) : [],
5151
};
5252

53+
const formRef = useRef<FormRef | null>(null);
54+
5355
const [uploadedIDs, setUploadedID] = useState<FileObject[]>(defaultValues[COPY_OF_ID]);
5456
const [uploadedProofsOfAddress, setUploadedProofOfAddress] = useState<FileObject[]>(defaultValues[ADDRESS_PROOF]);
5557
const [uploadedProofsOfDirectors, setUploadedProofsOfDirectors] = useState<FileObject[]>(defaultValues[PROOF_OF_DIRECTORS]);
@@ -97,6 +99,8 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
9799
return;
98100
}
99101

102+
formRef.current?.resetFormFieldError(inputID);
103+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
100104
setErrorFields(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {[inputID]: {onUpload: error}});
101105
};
102106

@@ -108,6 +112,7 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
108112

109113
return (
110114
<FormProvider
115+
ref={formRef}
111116
formID={ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM}
112117
submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
113118
onSubmit={handleSubmitWithDownload}
@@ -131,13 +136,14 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
131136
onRemove={(fileName) => {
132137
handleRemoveFile(fileName, uploadedIDs, COPY_OF_ID, setUploadedID);
133138
}}
134-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
139+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
135140
value={uploadedIDs}
136141
inputID={COPY_OF_ID}
137142
setError={(error) => {
138143
setUploadError(error, COPY_OF_ID);
139144
}}
140-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
145+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
146+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
141147
/>
142148
<Text style={[styles.mutedTextLabel, styles.mt6]}>{translate('ownershipInfoStep.copyOfIDDescription')}</Text>
143149
{(isDocumentNeededStatus.isAddressProofNeeded ||
@@ -159,13 +165,14 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
159165
onRemove={(fileName) => {
160166
handleRemoveFile(fileName, uploadedProofsOfAddress, ADDRESS_PROOF, setUploadedProofOfAddress);
161167
}}
162-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
168+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
163169
value={uploadedProofsOfAddress}
164170
inputID={ADDRESS_PROOF}
165171
setError={(error) => {
166172
setUploadError(error, ADDRESS_PROOF);
167173
}}
168-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
174+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
175+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
169176
/>
170177
<Text style={[styles.mutedTextLabel, styles.mt6]}>{translate('ownershipInfoStep.proofOfAddressDescription')}</Text>
171178
{(isDocumentNeededStatus.isProofOfDirectorsNeeded || isDocumentNeededStatus.isCodiceFiscaleNeeded || isDocumentNeededStatus.isPRDAndFSGNeeded) && (
@@ -186,13 +193,14 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
186193
onRemove={(fileName) => {
187194
handleRemoveFile(fileName, uploadedProofsOfDirectors, PROOF_OF_DIRECTORS, setUploadedProofsOfDirectors);
188195
}}
189-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
196+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
190197
value={uploadedProofsOfDirectors}
191198
inputID={PROOF_OF_DIRECTORS}
192199
setError={(error) => {
193200
setUploadError(error, PROOF_OF_DIRECTORS);
194201
}}
195-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
202+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
203+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
196204
/>
197205
<Text style={[styles.mutedTextLabel, styles.mt6]}>{translate('signerInfoStep.proofOfDirectorsDescription')}</Text>
198206
{(isDocumentNeededStatus.isCodiceFiscaleNeeded || isDocumentNeededStatus.isPRDAndFSGNeeded) && <View style={[styles.sectionDividerLine, styles.mt6, styles.mb6]} />}
@@ -211,13 +219,14 @@ function UploadDocuments({onNext, isEditing}: UploadDocumentsProps) {
211219
onRemove={(fileName) => {
212220
handleRemoveFile(fileName, uploadedCodiceFiscale, CODICE_FISCALE, setUploadedCodiceFiscale);
213221
}}
214-
acceptedFileTypes={[...CONST.NON_USD_BANK_ACCOUNT.ALLOWED_FILE_TYPES]}
222+
acceptedFileTypes={[...CONST.CORPAY_DOCUMENT.ALLOWED_FILE_TYPES]}
215223
value={uploadedCodiceFiscale}
216224
inputID={CODICE_FISCALE}
217225
setError={(error) => {
218226
setUploadError(error, CODICE_FISCALE);
219227
}}
220-
fileLimit={CONST.NON_USD_BANK_ACCOUNT.FILE_LIMIT}
228+
fileLimit={CONST.CORPAY_DOCUMENT.FILE_LIMIT}
229+
maxFileSize={CONST.CORPAY_DOCUMENT.MAX_FILE_SIZE}
221230
/>
222231
<Text style={[styles.mutedTextLabel, styles.mt6]}>{translate('signerInfoStep.codiceFiscaleDescription')}</Text>
223232
{isDocumentNeededStatus.isPRDAndFSGNeeded && <View style={[styles.sectionDividerLine, styles.mt6, styles.mb6]} />}

0 commit comments

Comments
 (0)