Skip to content

Commit 0db6a75

Browse files
authored
Merge pull request Expensify#63020 from callstack-internal/feat/50908-GR-Phase-3-Step5-chat-view
feat: Step 5 chat view
2 parents 10f648b + 0000af8 commit 0db6a75

51 files changed

Lines changed: 1417 additions & 51 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/CONST/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,9 @@ const CONST = {
664664
},
665665
ALLOWED_FILE_TYPES: ['pdf', 'jpg', 'jpeg', 'png'],
666666
},
667+
ENTER_SIGNER_INFO: {
668+
ALLOWED_FILE_TYPES: ['pdf', 'jpg', 'jpeg', 'png'],
669+
},
667670
INCORPORATION_TYPES: {
668671
LLC: 'LLC',
669672
CORPORATION: 'Corp',
@@ -1196,6 +1199,7 @@ const CONST = {
11961199
REIMBURSEMENT_REQUESTED: 'REIMBURSEMENTREQUESTED', // Deprecated OldDot Action
11971200
REIMBURSEMENT_SETUP: 'REIMBURSEMENTSETUP', // Deprecated OldDot Action
11981201
REIMBURSEMENT_SETUP_REQUESTED: 'REIMBURSEMENTSETUPREQUESTED', // Deprecated OldDot Action
1202+
REIMBURSEMENT_DIRECTOR_INFORMATION_REQUIRED: 'DIRECTORINFORMATIONREQUIRED',
11991203
REJECTED: 'REJECTED',
12001204
REMOVED_FROM_APPROVAL_CHAIN: 'REMOVEDFROMAPPROVALCHAIN',
12011205
DEMOTED_FROM_WORKSPACE: 'DEMOTEDFROMWORKSPACE',

src/ONYXKEYS.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,8 @@ const ONYXKEYS = {
783783
REPORT_FIELDS_EDIT_FORM_DRAFT: 'reportFieldsEditFormDraft',
784784
REIMBURSEMENT_ACCOUNT_FORM: 'reimbursementAccount',
785785
REIMBURSEMENT_ACCOUNT_FORM_DRAFT: 'reimbursementAccountDraft',
786+
ENTER_SINGER_INFO_FORM: 'enterSignerInfoForm',
787+
ENTER_SINGER_INFO_FORM_DRAFT: 'enterSignerInfoFormDraft',
786788
PERSONAL_BANK_ACCOUNT_FORM: 'personalBankAccount',
787789
PERSONAL_BANK_ACCOUNT_FORM_DRAFT: 'personalBankAccountDraft',
788790
DISABLE_AUTO_RENEW_SURVEY_FORM: 'disableAutoRenewSurveyForm',
@@ -935,6 +937,7 @@ type OnyxFormValuesMapping = {
935937
[ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM]: FormTypes.ReportPhysicalCardForm;
936938
[ONYXKEYS.FORMS.REPORT_FIELDS_EDIT_FORM]: FormTypes.ReportFieldsEditForm;
937939
[ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM]: FormTypes.ReimbursementAccountForm;
940+
[ONYXKEYS.FORMS.ENTER_SINGER_INFO_FORM]: FormTypes.EnterSignerInfoForm;
938941
[ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT_FORM]: FormTypes.PersonalBankAccountForm;
939942
[ONYXKEYS.FORMS.WORKSPACE_DESCRIPTION_FORM]: FormTypes.WorkspaceDescriptionForm;
940943
[ONYXKEYS.FORMS.WORKSPACE_MEMBER_CUSTOM_FIELD_FORM]: FormTypes.WorkspaceMemberCustomFieldsForm;

src/ROUTES.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@ const ROUTES = {
185185
return getUrlWithBackToParam(`bank-account/${stepToOpen}?policyID=${policyID}`, backTo);
186186
},
187187
},
188+
BANK_ACCOUNT_ENTER_SIGNER_INFO: {
189+
route: 'bank-account/enter-signer-info',
190+
getRoute: (policyID: string | undefined, bankAccountID: string | undefined, isCompleted: boolean) => {
191+
if (!policyID) {
192+
Log.warn('Invalid policyID is used to build the BANK_ACCOUNT_ENTER_SIGNER_INFO route');
193+
}
194+
return `bank-account/enter-signer-info?policyID=${policyID}&bankAccountID=${bankAccountID}&isCompleted=${isCompleted}` as const;
195+
},
196+
},
188197
PUBLIC_CONSOLE_DEBUG: {
189198
route: 'troubleshoot/console',
190199
getRoute: (backTo?: string) => getUrlWithBackToParam(`troubleshoot/console`, backTo),

src/SCREENS.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ const SCREENS = {
744744
},
745745
FLAG_COMMENT_ROOT: 'FlagComment_Root',
746746
REIMBURSEMENT_ACCOUNT: 'ReimbursementAccount',
747+
REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO: 'Reimbursement_Account_Signer_Info',
747748
REFERRAL_DETAILS: 'Referral_Details',
748749
KEYBOARD_SHORTCUTS: 'KeyboardShortcuts',
749750
SHARE: {

src/components/SubStepForms/RegistrationNumberStep.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function RegistrationNumberStep<TFormID extends keyof OnyxFormValuesMapping>({
7676
style={[styles.mh5, styles.flexGrow1]}
7777
shouldHideFixErrorsAlert
7878
>
79-
<Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.whatsTheBusinessRegistrationNumber')}</Text>
79+
<Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.whatsTheBusinessRegistrationNumber', {country})}</Text>
8080
<InputWrapper
8181
InputComponent={TextInput}
8282
label={translate('businessInfoStep.registrationNumber')}

src/components/SubStepForms/SingleFieldStep.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import React from 'react';
1+
import React, {forwardRef, useRef} from 'react';
22
import type {InputModeOptions} from 'react-native';
33
import {View} from 'react-native';
44
import FormProvider from '@components/Form/FormProvider';
55
import InputWrapper from '@components/Form/InputWrapper';
66
import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
7+
import type {AnimatedTextInputRef} from '@components/RNTextInput';
78
import Text from '@components/Text';
89
import TextInput from '@components/TextInput';
10+
import useDelayedAutoFocus from '@hooks/useDelayAutoFocus';
911
import useLocalize from '@hooks/useLocalize';
1012
import type {SubStepProps} from '@hooks/useSubStep/types';
1113
import useThemeStyles from '@hooks/useThemeStyles';
@@ -58,6 +60,9 @@ type SingleFieldStepProps<TFormID extends keyof OnyxFormValuesMapping> = SubStep
5860

5961
/** Placeholder displayed inside input */
6062
placeholder?: string;
63+
64+
/** Whether to delay autoFocus to avoid conflicts with navigation animations */
65+
shouldDelayAutoFocus?: boolean;
6166
};
6267

6368
function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
@@ -77,9 +82,12 @@ function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
7782
shouldUseDefaultValue = true,
7883
disabled = false,
7984
placeholder,
85+
shouldDelayAutoFocus = false,
8086
}: SingleFieldStepProps<TFormID>) {
8187
const {translate} = useLocalize();
8288
const styles = useThemeStyles();
89+
const internalInputRef = useRef<AnimatedTextInputRef>(null);
90+
useDelayedAutoFocus(internalInputRef, shouldDelayAutoFocus);
8391

8492
return (
8593
<FormProvider
@@ -110,7 +118,8 @@ function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
110118
shouldUseDefaultValue={shouldUseDefaultValue}
111119
disabled={disabled}
112120
placeholder={placeholder}
113-
autoFocus
121+
autoFocus={!shouldDelayAutoFocus}
122+
ref={internalInputRef}
114123
/>
115124
</View>
116125
{shouldShowHelpLinks && <HelpLinks containerStyles={[styles.mt5]} />}
@@ -121,4 +130,4 @@ function SingleFieldStep<TFormID extends keyof OnyxFormValuesMapping>({
121130

122131
SingleFieldStep.displayName = 'SingleFieldStep';
123132

124-
export default SingleFieldStep;
133+
export default forwardRef(SingleFieldStep);

src/hooks/useDelayAutoFocus.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {useFocusEffect} from '@react-navigation/native';
2+
import type {RefObject} from 'react';
3+
import {useCallback, useRef} from 'react';
4+
import CONST from '@src/CONST';
5+
6+
function useDelayedAutoFocus(ref: RefObject<{focus: () => void} | null>, shouldDelayAutoFocus: boolean) {
7+
const focusTimeoutRef = useRef<NodeJS.Timeout | null>(null);
8+
9+
useFocusEffect(
10+
useCallback(() => {
11+
if (!shouldDelayAutoFocus) {
12+
return undefined;
13+
}
14+
15+
focusTimeoutRef.current = setTimeout(() => {
16+
ref.current?.focus();
17+
}, CONST.ANIMATED_TRANSITION);
18+
19+
return () => {
20+
const timeout = focusTimeoutRef.current;
21+
if (timeout) {
22+
clearTimeout(timeout);
23+
focusTimeoutRef.current = null;
24+
}
25+
};
26+
}, [shouldDelayAutoFocus, ref]),
27+
);
28+
}
29+
30+
export default useDelayedAutoFocus;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type {FormOnyxKeys} from '@components/Form/types';
2+
import type {OnyxFormKey} from '@src/ONYXKEYS';
3+
import ONYXKEYS from '@src/ONYXKEYS';
4+
import useStepFormSubmit from './useStepFormSubmit';
5+
import type {SubStepProps} from './useSubStep/types';
6+
7+
type UseEnterSignerInfoStepFormSubmit = Pick<SubStepProps, 'onNext'> & {
8+
formId?: OnyxFormKey;
9+
fieldIds: Array<FormOnyxKeys<typeof ONYXKEYS.FORMS.ENTER_SINGER_INFO_FORM>>;
10+
shouldSaveDraft: boolean;
11+
};
12+
13+
/**
14+
* Hook for handling submit method in EnterSignerInfo substeps.
15+
* When user is in editing mode, we should save values only when user confirms the change
16+
* @param onNext - callback
17+
* @param fieldIds - field IDs for particular step
18+
* @param shouldSaveDraft - if we should save draft values
19+
*/
20+
export default function useEnterSignerInfoStepFormSubmit({onNext, fieldIds, shouldSaveDraft}: UseEnterSignerInfoStepFormSubmit) {
21+
return useStepFormSubmit<typeof ONYXKEYS.FORMS.ENTER_SINGER_INFO_FORM>({
22+
formId: ONYXKEYS.FORMS.ENTER_SINGER_INFO_FORM,
23+
onNext,
24+
fieldIds,
25+
shouldSaveDraft,
26+
});
27+
}

src/languages/de.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import type {
5252
BillingBannerOwnerAmountOwedOverdueParams,
5353
BillingBannerSubtitleWithDateParams,
5454
BusinessBankAccountParams,
55+
BusinessRegistrationNumberParams,
5556
BusinessTaxIDParams,
5657
CanceledRequestParams,
5758
CardEndingParams,
@@ -203,6 +204,7 @@ import type {
203204
SettlementAccountInfoParams,
204205
SettlementDateParams,
205206
ShareParams,
207+
SignerInfoMessageParams,
206208
SignUpNewFaceCodeParams,
207209
SizeExceededParams,
208210
SplitAmountParams,
@@ -3001,7 +3003,14 @@ const translations = {
30013003
whatsTheBusinessName: 'Wie lautet der Firmenname?',
30023004
whatsTheBusinessAddress: 'Wie lautet die Geschäftsadresse?',
30033005
whatsTheBusinessContactInformation: 'Wie lauten die Geschäftskontaktdaten?',
3004-
whatsTheBusinessRegistrationNumber: 'Wie lautet die Handelsregisternummer?',
3006+
whatsTheBusinessRegistrationNumber: ({country}: BusinessRegistrationNumberParams) => {
3007+
switch (country) {
3008+
case CONST.COUNTRY.GB:
3009+
return 'Wie lautet die Handelsregisternummer (CRN)?';
3010+
default:
3011+
return 'Wie lautet die Handelsregisternummer?';
3012+
}
3013+
},
30053014
whatsTheBusinessTaxIDEIN: ({country}: BusinessTaxIDParams) => {
30063015
switch (country) {
30073016
case CONST.COUNTRY.US:
@@ -3234,6 +3243,10 @@ const translations = {
32343243
PDSandFSGDescription:
32353244
'Unsere Partnerschaft mit Corpay nutzt eine API-Verbindung, um das umfangreiche Netzwerk internationaler Bankpartner zu nutzen und globale Rückerstattungen in Expensify zu ermöglichen. Gemäß der australischen Vorschriften stellen wir Ihnen den Financial Services Guide (FSG) und die Product Disclosure Statement (PDS) von Corpay zur Verfügung.\n\nBitte lesen Sie die FSG- und PDS-Dokumente sorgfältig durch, da sie vollständige Details und wichtige Informationen zu den von Corpay angebotenen Produkten und Dienstleistungen enthalten. Bewahren Sie diese Dokumente für zukünftige Referenz auf.',
32363245
pleaseUpload: 'Bitte laden Sie zusätzliche Unterlagen hoch, um uns bei der Überprüfung Ihrer Identität als Direktor oder leitender Angestellter des Unternehmens zu unterstützen.',
3246+
enterSignerInfo: 'Unterschriftsberechtigte Person eingeben',
3247+
thisStep: 'Dieser Schritt wurde abgeschlossen',
3248+
isConnecting: ({bankAccountLastFour, currency}: SignerInfoMessageParams) =>
3249+
`verbindet ein Geschäftskonto in ${currency} mit der Endung ${bankAccountLastFour} mit Expensify, um Mitarbeitende in ${currency} zu bezahlen. Der nächste Schritt erfordert Informationen einer unterschriftsberechtigten Person wie einem Geschäftsführer oder einer Führungskraft.`,
32373250
},
32383251
agreementsStep: {
32393252
agreements: 'Vereinbarungen',

src/languages/en.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import type {
4141
BillingBannerOwnerAmountOwedOverdueParams,
4242
BillingBannerSubtitleWithDateParams,
4343
BusinessBankAccountParams,
44+
BusinessRegistrationNumberParams,
4445
BusinessTaxIDParams,
4546
CanceledRequestParams,
4647
CardEndingParams,
@@ -192,6 +193,7 @@ import type {
192193
SettlementAccountInfoParams,
193194
SettlementDateParams,
194195
ShareParams,
196+
SignerInfoMessageParams,
195197
SignUpNewFaceCodeParams,
196198
SizeExceededParams,
197199
SplitAmountParams,
@@ -3001,7 +3003,14 @@ const translations = {
30013003
whatsTheBusinessName: "What's the business name?",
30023004
whatsTheBusinessAddress: "What's the business address?",
30033005
whatsTheBusinessContactInformation: "What's the business contact information?",
3004-
whatsTheBusinessRegistrationNumber: "What's the business registration number?",
3006+
whatsTheBusinessRegistrationNumber: ({country}: BusinessRegistrationNumberParams) => {
3007+
switch (country) {
3008+
case CONST.COUNTRY.GB:
3009+
return "What's the Company Registration Number (CRN)?";
3010+
default:
3011+
return "What's the business registration number?";
3012+
}
3013+
},
30053014
whatsTheBusinessTaxIDEIN: ({country}: BusinessTaxIDParams) => {
30063015
switch (country) {
30073016
case CONST.COUNTRY.US:
@@ -3217,7 +3226,7 @@ const translations = {
32173226
legalName: 'Legal name',
32183227
proofOf: 'Proof of personal address',
32193228
enterOneEmail: ({companyName}: CompanyNameParams) => `Enter the email of director or senior officer at ${companyName}`,
3220-
regulationRequiresOneMoreDirector: 'Regulation requires at least more director or senior officer as a signer.',
3229+
regulationRequiresOneMoreDirector: 'Regulation requires at least one more director or senior officer as a signer.',
32213230
hangTight: 'Hang tight...',
32223231
enterTwoEmails: ({companyName}: CompanyNameParams) => `Enter the emails of two directors or senior officers at ${companyName}`,
32233232
sendReminder: 'Send a reminder',
@@ -3232,6 +3241,10 @@ const translations = {
32323241
PDSandFSGDescription:
32333242
"Our partnership with Corpay utilizes an API connection to take advantage of their vast network of international banking partners to power Global Reimbursements in Expensify. As per Australian regulation we are providing you with Corpay's Financial Services Guide (FSG) and Product Disclosure Statement (PDS).\n\nPlease read the FSG and PDS documents carefully as they contain full details and important information on the products and services Corpay offers. Retain these documents for future reference.",
32343243
pleaseUpload: 'Please upload additional documentation below to help us verify your identity as a director or senior officer of the business entity.',
3244+
enterSignerInfo: 'Enter signer info',
3245+
thisStep: 'This step has been completed',
3246+
isConnecting: ({bankAccountLastFour, currency}: SignerInfoMessageParams) =>
3247+
`is connecting a ${currency} business bank account ending in ${bankAccountLastFour} to Expensify to pay employees in ${currency}. The next step requires signer info from a director or senior officer.`,
32353248
},
32363249
agreementsStep: {
32373250
agreements: 'Agreements',

0 commit comments

Comments
 (0)