diff --git a/assets/images/attachment-not-found.svg b/assets/images/attachment-not-found.svg index 25da973ce9cb..87231be3741b 100644 --- a/assets/images/attachment-not-found.svg +++ b/assets/images/attachment-not-found.svg @@ -1,18 +1 @@ - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/binoculars.svg b/assets/images/binoculars.svg index 64977dee38b5..1739abff408c 100644 --- a/assets/images/binoculars.svg +++ b/assets/images/binoculars.svg @@ -1,25 +1 @@ - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/bolt.svg b/assets/images/bolt.svg index 76334459107b..d2311261b5ec 100644 --- a/assets/images/bolt.svg +++ b/assets/images/bolt.svg @@ -1,4 +1 @@ - - - - + \ No newline at end of file diff --git a/assets/images/buildings.svg b/assets/images/buildings.svg index 42171d499f26..4acce6e971be 100644 --- a/assets/images/buildings.svg +++ b/assets/images/buildings.svg @@ -1,12 +1 @@ - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/card-bofa.svg b/assets/images/companyCards/card-bofa.svg index c58229f1b242..5b210bbe2a93 100644 --- a/assets/images/companyCards/card-bofa.svg +++ b/assets/images/companyCards/card-bofa.svg @@ -1,27 +1 @@ - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/card-capitalone.svg b/assets/images/companyCards/card-capitalone.svg index 9f1402298683..650fe5cb53d8 100644 --- a/assets/images/companyCards/card-capitalone.svg +++ b/assets/images/companyCards/card-capitalone.svg @@ -1,23 +1 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-amex-large.svg b/assets/images/companyCards/large/card-amex-large.svg index 06f0f57e16d2..2de2e018911a 100644 --- a/assets/images/companyCards/large/card-amex-large.svg +++ b/assets/images/companyCards/large/card-amex-large.svg @@ -1,32 +1 @@ - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-bofa-large.svg b/assets/images/companyCards/large/card-bofa-large.svg index c83e06ffb65d..5babf9a7b611 100644 --- a/assets/images/companyCards/large/card-bofa-large.svg +++ b/assets/images/companyCards/large/card-bofa-large.svg @@ -1,27 +1 @@ - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-brex-large.svg b/assets/images/companyCards/large/card-brex-large.svg index e1a48c3dbe39..2a3d09ee6240 100644 --- a/assets/images/companyCards/large/card-brex-large.svg +++ b/assets/images/companyCards/large/card-brex-large.svg @@ -1,23 +1 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-capital_one-large.svg b/assets/images/companyCards/large/card-capital_one-large.svg index 20f3bd442d9e..01ea419f6a39 100644 --- a/assets/images/companyCards/large/card-capital_one-large.svg +++ b/assets/images/companyCards/large/card-capital_one-large.svg @@ -1,23 +1 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-chase-large.svg b/assets/images/companyCards/large/card-chase-large.svg index 2b0904ae225d..2be1eb205c28 100644 --- a/assets/images/companyCards/large/card-chase-large.svg +++ b/assets/images/companyCards/large/card-chase-large.svg @@ -1,26 +1 @@ - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-citi-large.svg b/assets/images/companyCards/large/card-citi-large.svg index 14e3ecd36850..2a7b8e55105b 100644 --- a/assets/images/companyCards/large/card-citi-large.svg +++ b/assets/images/companyCards/large/card-citi-large.svg @@ -1,31 +1 @@ - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-expensify-large.svg b/assets/images/companyCards/large/card-expensify-large.svg index 2cef4a59ca20..3948b4718031 100644 --- a/assets/images/companyCards/large/card-expensify-large.svg +++ b/assets/images/companyCards/large/card-expensify-large.svg @@ -1,61 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-generic-large.svg b/assets/images/companyCards/large/card-generic-large.svg index 542d34fada88..0979107526e6 100644 --- a/assets/images/companyCards/large/card-generic-large.svg +++ b/assets/images/companyCards/large/card-generic-large.svg @@ -1,26 +1 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-mastercard-large.svg b/assets/images/companyCards/large/card-mastercard-large.svg index efc27960ef73..3d21c4b7bcdc 100644 --- a/assets/images/companyCards/large/card-mastercard-large.svg +++ b/assets/images/companyCards/large/card-mastercard-large.svg @@ -1,33 +1 @@ - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-stripe-large.svg b/assets/images/companyCards/large/card-stripe-large.svg index cd084457f5b7..61d852342b90 100644 --- a/assets/images/companyCards/large/card-stripe-large.svg +++ b/assets/images/companyCards/large/card-stripe-large.svg @@ -1,32 +1 @@ - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-visa-large.svg b/assets/images/companyCards/large/card-visa-large.svg index 0f000c5652df..63289094956b 100644 --- a/assets/images/companyCards/large/card-visa-large.svg +++ b/assets/images/companyCards/large/card-visa-large.svg @@ -1,48 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/companyCards/large/card-wellsfargo-large.svg b/assets/images/companyCards/large/card-wellsfargo-large.svg index ef9eb84a890d..588cff40115e 100644 --- a/assets/images/companyCards/large/card-wellsfargo-large.svg +++ b/assets/images/companyCards/large/card-wellsfargo-large.svg @@ -1,23 +1 @@ - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/product-illustrations/emptystate__holdexpense.svg b/assets/images/product-illustrations/emptystate__holdexpense.svg index d00738964047..2684926c768a 100644 --- a/assets/images/product-illustrations/emptystate__holdexpense.svg +++ b/assets/images/product-illustrations/emptystate__holdexpense.svg @@ -1,1207 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/receipt-placeholder-plus.svg b/assets/images/receipt-placeholder-plus.svg index 3ebc08b40b06..477f1f8585eb 100644 --- a/assets/images/receipt-placeholder-plus.svg +++ b/assets/images/receipt-placeholder-plus.svg @@ -1,17 +1 @@ - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/emptystate__puzzlepieces.svg b/assets/images/simple-illustrations/emptystate__puzzlepieces.svg index d137ce5dcff2..ad678e0ecd85 100644 --- a/assets/images/simple-illustrations/emptystate__puzzlepieces.svg +++ b/assets/images/simple-illustrations/emptystate__puzzlepieces.svg @@ -1,93 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__building.svg b/assets/images/simple-illustrations/simple-illustration__building.svg index 94a7320d8471..4ba71bba9c82 100644 --- a/assets/images/simple-illustrations/simple-illustration__building.svg +++ b/assets/images/simple-illustrations/simple-illustration__building.svg @@ -1,47 +1 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__buildings.svg b/assets/images/simple-illustrations/simple-illustration__buildings.svg index cb22c3a29ce4..d560a14b0d4d 100644 --- a/assets/images/simple-illustrations/simple-illustration__buildings.svg +++ b/assets/images/simple-illustrations/simple-illustration__buildings.svg @@ -1,55 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__flash.svg b/assets/images/simple-illustrations/simple-illustration__flash.svg index be8daf296aa1..4f30e2ecdb63 100644 --- a/assets/images/simple-illustrations/simple-illustration__flash.svg +++ b/assets/images/simple-illustrations/simple-illustration__flash.svg @@ -1,52 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__mobileapp.svg b/assets/images/simple-illustrations/simple-illustration__mobileapp.svg index 80682c942f81..5522bfc198a0 100644 --- a/assets/images/simple-illustrations/simple-illustration__mobileapp.svg +++ b/assets/images/simple-illustrations/simple-illustration__mobileapp.svg @@ -1,54 +1 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__perdiem.svg b/assets/images/simple-illustrations/simple-illustration__perdiem.svg index ea5a865a2694..05d9ea4254be 100644 --- a/assets/images/simple-illustrations/simple-illustration__perdiem.svg +++ b/assets/images/simple-illustrations/simple-illustration__perdiem.svg @@ -1,82 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__pillow.svg b/assets/images/simple-illustrations/simple-illustration__pillow.svg index 97a0811266ae..3ff85c19f1f0 100644 --- a/assets/images/simple-illustrations/simple-illustration__pillow.svg +++ b/assets/images/simple-illustrations/simple-illustration__pillow.svg @@ -1,28 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__realtimereports.svg b/assets/images/simple-illustrations/simple-illustration__realtimereports.svg index 40fc3082a028..95a6009c5670 100644 --- a/assets/images/simple-illustrations/simple-illustration__realtimereports.svg +++ b/assets/images/simple-illustrations/simple-illustration__realtimereports.svg @@ -1,88 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__stopwatch.svg b/assets/images/simple-illustrations/simple-illustration__stopwatch.svg index c348fd73337b..3c7f329daf52 100644 --- a/assets/images/simple-illustrations/simple-illustration__stopwatch.svg +++ b/assets/images/simple-illustrations/simple-illustration__stopwatch.svg @@ -1,41 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/train.svg b/assets/images/train.svg index 40d8c9d1af8a..ef04e95016ac 100644 --- a/assets/images/train.svg +++ b/assets/images/train.svg @@ -1,3 +1 @@ - - - + \ No newline at end of file diff --git a/patches/react-native+0.76.3+030+disable-suggestion-pop-up.patch b/patches/react-native+0.76.3+030+disable-suggestion-pop-up.patch new file mode 100644 index 000000000000..790c283edc8b --- /dev/null +++ b/patches/react-native+0.76.3+030+disable-suggestion-pop-up.patch @@ -0,0 +1,325 @@ +diff --git a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +index 0973ae8..d5e6cee 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js ++++ b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +@@ -169,6 +169,7 @@ const RCTTextInputViewConfig = { + onChangeSync: true, + onKeyPressSync: true, + }), ++ disableKeyboardShortcuts: true, + }, + }; + +diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts +index 47cdcfc..22c42ae 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts ++++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts +@@ -136,6 +136,11 @@ export interface DocumentSelectionState extends EventEmitter { + * @see https://reactnative.dev/docs/textinput#props + */ + export interface TextInputIOSProps { ++ /** ++ * If true, the keyboard shortcuts (undo/redo and copy buttons) are disabled. The default value is false. ++ */ ++ disableKeyboardShortcuts?: boolean | undefined; ++ + /** + * enum('never', 'while-editing', 'unless-editing', 'always') + * When the clear button should appear on the right side of the text view +diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js +index 2f35731..a1455e7 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js ++++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js +@@ -224,6 +224,12 @@ export type enterKeyHintType = + type PasswordRules = string; + + type IOSProps = $ReadOnly<{| ++ /** ++ * If true, the keyboard shortcuts (undo/redo and copy buttons) are disabled. The default value is false. ++ * @platform ios ++ */ ++ disableKeyboardShortcuts?: ?boolean, ++ + /** + * When the clear button should appear on the right side of the text view. + * This property is supported only for single-line TextInput component. +diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js +index 2ffb38b..40e732f 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js ++++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js +@@ -267,6 +267,12 @@ export type enterKeyHintType = + type PasswordRules = string; + + type IOSProps = $ReadOnly<{| ++ /** ++ * If true, the keyboard shortcuts (undo/redo and copy buttons) are disabled. The default value is false. ++ * @platform ios ++ */ ++ disableKeyboardShortcuts?: ?boolean, ++ + /** + * When the clear button should appear on the right side of the text view. + * This property is supported only for single-line TextInput component. +diff --git a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h +index 205f994..3b528d2 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h ++++ b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.h +@@ -38,6 +38,8 @@ NS_ASSUME_NONNULL_BEGIN + + @property (nonatomic, strong, nullable) NSString *inputAccessoryViewID; + ++@property (nonatomic, assign) BOOL disableKeyboardShortcuts; ++ + @end + + NS_ASSUME_NONNULL_END +diff --git a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +index 065a819..b521dd9 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm ++++ b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +@@ -22,6 +22,8 @@ @implementation RCTUITextView { + UITextView *_detachedTextView; + RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter; + NSDictionary *_defaultTextAttributes; ++ NSArray *_initialValueLeadingBarButtonGroups; ++ NSArray *_initialValueTrailingBarButtonGroups; + } + + static UIFont *defaultPlaceholderFont(void) +@@ -56,6 +58,8 @@ - (instancetype)initWithFrame:(CGRect)frame + self.textContainer.lineFragmentPadding = 0; + self.scrollsToTop = NO; + self.scrollEnabled = YES; ++ _initialValueLeadingBarButtonGroups = nil; ++ _initialValueTrailingBarButtonGroups = nil; + } + + return self; +@@ -136,6 +140,25 @@ - (void)textDidChange + [self _invalidatePlaceholderVisibility]; + } + ++- (void)setDisableKeyboardShortcuts:(BOOL)disableKeyboardShortcuts ++{ ++ // Initialize the initial values only once ++ if (_initialValueLeadingBarButtonGroups == nil) { ++ // Capture initial values of leading and trailing button groups ++ _initialValueLeadingBarButtonGroups = self.inputAssistantItem.leadingBarButtonGroups; ++ _initialValueTrailingBarButtonGroups = self.inputAssistantItem.trailingBarButtonGroups; ++ } ++ ++ if (disableKeyboardShortcuts) { ++ self.inputAssistantItem.leadingBarButtonGroups = @[]; ++ self.inputAssistantItem.trailingBarButtonGroups = @[]; ++ } else { ++ // Restore the initial values ++ self.inputAssistantItem.leadingBarButtonGroups = _initialValueLeadingBarButtonGroups; ++ self.inputAssistantItem.trailingBarButtonGroups = _initialValueTrailingBarButtonGroups; ++ } ++} ++ + #pragma mark - Overrides + + - (void)setFont:(UIFont *)font +diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +index cc51013..26a112f 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h ++++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +@@ -51,6 +51,8 @@ NS_ASSUME_NONNULL_BEGIN + // Use `attributedText.string` instead. + @property (nonatomic, copy, nullable) NSString *text NS_UNAVAILABLE; + ++@property (nonatomic, assign) BOOL disableKeyboardShortcuts; ++ + @end + + NS_ASSUME_NONNULL_END +diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm +index 6047486..5d1e97b 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm ++++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm +@@ -30,6 +30,8 @@ @implementation RCTBaseTextInputView { + BOOL _hasInputAccessoryView; + NSString *_Nullable _predictedText; + BOOL _didMoveToWindow; ++ NSArray *_initialValueLeadingBarButtonGroups; ++ NSArray *_initialValueTrailingBarButtonGroups; + } + + - (void)reactUpdateResponderOffsetForScrollView:(RCTScrollView *)scrollView +@@ -64,6 +66,8 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge + _bridge = bridge; + _eventDispatcher = bridge.eventDispatcher; + [self initializeReturnKeyType]; ++ _initialValueLeadingBarButtonGroups = nil; ++ _initialValueTrailingBarButtonGroups = nil; + } + + return self; +@@ -374,6 +378,25 @@ - (void)setShowSoftInputOnFocus:(BOOL)showSoftInputOnFocus + } + } + ++- (void)setDisableKeyboardShortcuts:(BOOL)disableKeyboardShortcuts ++{ ++ // Initialize the initial values only once ++ if (_initialValueLeadingBarButtonGroups == nil) { ++ // Capture initial values of leading and trailing button groups ++ _initialValueLeadingBarButtonGroups = self.backedTextInputView.inputAssistantItem.leadingBarButtonGroups; ++ _initialValueTrailingBarButtonGroups = self.backedTextInputView.inputAssistantItem.trailingBarButtonGroups; ++ } ++ ++ if (disableKeyboardShortcuts) { ++ self.backedTextInputView.inputAssistantItem.leadingBarButtonGroups = @[]; ++ self.backedTextInputView.inputAssistantItem.trailingBarButtonGroups = @[]; ++ } else { ++ // Restore the initial values ++ self.backedTextInputView.inputAssistantItem.leadingBarButtonGroups = _initialValueLeadingBarButtonGroups; ++ self.backedTextInputView.inputAssistantItem.trailingBarButtonGroups = _initialValueTrailingBarButtonGroups; ++ } ++} ++ + #pragma mark - RCTBackedTextInputDelegate + + - (BOOL)textInputShouldBeginEditing +diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm +index e367394..08ec761 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm ++++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm +@@ -70,6 +70,8 @@ @implementation RCTBaseTextInputViewManager { + + RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger) + ++RCT_EXPORT_VIEW_PROPERTY(disableKeyboardShortcuts, BOOL) ++ + RCT_EXPORT_SHADOW_PROPERTY(text, NSString) + RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString) + RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTDirectEventBlock) +diff --git a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h +index 91f8eb0..fbf9f32 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h ++++ b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.h +@@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN + @property (nonatomic, assign, readonly) CGFloat zoomScale; + @property (nonatomic, assign, readonly) CGPoint contentOffset; + @property (nonatomic, assign, readonly) UIEdgeInsets contentInset; ++@property (nonatomic, assign) BOOL disableKeyboardShortcuts; + + @end + +diff --git a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +index 667e646..617f05f 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm ++++ b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +@@ -19,6 +19,8 @@ + @implementation RCTUITextField { + RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter; + NSDictionary *_defaultTextAttributes; ++ NSArray *_initialValueLeadingBarButtonGroups; ++ NSArray *_initialValueTrailingBarButtonGroups; + } + + - (instancetype)initWithFrame:(CGRect)frame +@@ -31,6 +33,8 @@ - (instancetype)initWithFrame:(CGRect)frame + + _textInputDelegateAdapter = [[RCTBackedTextFieldDelegateAdapter alloc] initWithTextField:self]; + _scrollEnabled = YES; ++ _initialValueLeadingBarButtonGroups = nil; ++ _initialValueTrailingBarButtonGroups = nil; + } + + return self; +@@ -119,6 +123,25 @@ - (void)setSecureTextEntry:(BOOL)secureTextEntry + self.attributedText = originalText; + } + ++- (void)setDisableKeyboardShortcuts:(BOOL)disableKeyboardShortcuts ++{ ++ // Initialize the initial values only once ++ if (_initialValueLeadingBarButtonGroups == nil) { ++ // Capture initial values of leading and trailing button groups ++ _initialValueLeadingBarButtonGroups = self.inputAssistantItem.leadingBarButtonGroups; ++ _initialValueTrailingBarButtonGroups = self.inputAssistantItem.trailingBarButtonGroups; ++ } ++ ++ if (disableKeyboardShortcuts) { ++ self.inputAssistantItem.leadingBarButtonGroups = @[]; ++ self.inputAssistantItem.trailingBarButtonGroups = @[]; ++ } else { ++ // Restore the initial values ++ self.inputAssistantItem.leadingBarButtonGroups = _initialValueLeadingBarButtonGroups; ++ self.inputAssistantItem.trailingBarButtonGroups = _initialValueTrailingBarButtonGroups; ++ } ++} ++ + #pragma mark - Placeholder + + - (NSDictionary *)_placeholderTextAttributes +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +index 2e7b1a1..abd91ef 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +@@ -278,6 +278,11 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & + if (newTextInputProps.inputAccessoryViewID != oldTextInputProps.inputAccessoryViewID) { + _backedTextInputView.inputAccessoryViewID = RCTNSStringFromString(newTextInputProps.inputAccessoryViewID); + } ++ ++ if (newTextInputProps.disableKeyboardShortcuts != oldTextInputProps.disableKeyboardShortcuts) { ++ _backedTextInputView.disableKeyboardShortcuts = newTextInputProps.disableKeyboardShortcuts; ++ } ++ + [super updateProps:props oldProps:oldProps]; + + [self setDefaultInputAccessoryView]; +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +index 6345758..92c56b4 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +@@ -45,6 +45,7 @@ void RCTCopyBackedTextInput( + toTextInput.textContentType = fromTextInput.textContentType; + toTextInput.smartInsertDeleteType = fromTextInput.smartInsertDeleteType; + toTextInput.passwordRules = fromTextInput.passwordRules; ++ toTextInput.disableKeyboardShortcuts = fromTextInput.disableKeyboardShortcuts; + + [toTextInput setSelectedTextRange:fromTextInput.selectedTextRange notifyDelegate:NO]; + } +diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.cpp b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.cpp +index ec0f350..56c3b4f 100644 +--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.cpp ++++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.cpp +@@ -102,7 +102,13 @@ BaseTextInputProps::BaseTextInputProps( + rawProps, + "autoCapitalize", + sourceProps.autoCapitalize, +- {})) {} ++ {})), ++ disableKeyboardShortcuts(convertRawProp( ++ context, ++ rawProps, ++ "disableKeyboardShortcuts", ++ sourceProps.disableKeyboardShortcuts, ++ {false})) {} + + void BaseTextInputProps::setProp( + const PropsParserContext& context, +@@ -180,6 +186,7 @@ void BaseTextInputProps::setProp( + RAW_SET_PROP_SWITCH_CASE_BASIC(text); + RAW_SET_PROP_SWITCH_CASE_BASIC(mostRecentEventCount); + RAW_SET_PROP_SWITCH_CASE_BASIC(autoCapitalize); ++ RAW_SET_PROP_SWITCH_CASE_BASIC(disableKeyboardShortcuts); + } + } + +diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.h +index bff69fe..27782a1 100644 +--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.h ++++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputProps.h +@@ -63,6 +63,8 @@ class BaseTextInputProps : public ViewProps, public BaseTextProps { + bool autoFocus{false}; + + std::string autoCapitalize{}; ++ ++ bool disableKeyboardShortcuts{false}; + }; + + } // namespace facebook::react diff --git a/src/CONST.ts b/src/CONST.ts index 12e92c26479f..e4f782be13d6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -177,9 +177,9 @@ const onboardingPersonalSpendMessage: OnboardingMessage = { 'Here’s how to track an expense:\n' + '\n' + '1. Click the green *+* button.\n' + - '2. Choose *Track expense*.\n' + + '2. Choose *Create expense*.\n' + '3. Enter an amount or scan a receipt.\n' + - '4. Click *Track*.\n' + + '4. Click *Create*.\n' + '\n' + 'And you’re done! Yep, it’s that easy.', }, diff --git a/src/components/AmountTextInput.tsx b/src/components/AmountTextInput.tsx index 12189d22dba0..256d95ba8419 100644 --- a/src/components/AmountTextInput.tsx +++ b/src/components/AmountTextInput.tsx @@ -84,6 +84,7 @@ function AmountTextInput( // Setting both autoCorrect and spellCheck to false will hide the suggestion. autoCorrect={false} spellCheck={false} + disableKeyboardShortcuts // eslint-disable-next-line react/jsx-props-no-spreading {...rest} /> diff --git a/src/components/BrokenConnectionDescription.tsx b/src/components/BrokenConnectionDescription.tsx index a1b9bd62ffa2..078cbed25631 100644 --- a/src/components/BrokenConnectionDescription.tsx +++ b/src/components/BrokenConnectionDescription.tsx @@ -3,8 +3,8 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {isInstantSubmitEnabled, isPolicyAdmin as isPolicyAdminPolicyUtils} from '@libs/PolicyUtils'; +import {isCurrentUserSubmitter, isProcessingReport, isReportApproved, isReportManuallyReimbursed} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -26,11 +26,11 @@ type BrokenConnectionDescriptionProps = { function BrokenConnectionDescription({transactionID, policy, report}: BrokenConnectionDescriptionProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`); + const [transactionViolations] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID ?? CONST.DEFAULT_NUMBER_ID}`); const brokenConnection530Error = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530); const brokenConnectionError = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION); - const isPolicyAdmin = PolicyUtils.isPolicyAdmin(policy); + const isPolicyAdmin = isPolicyAdminPolicyUtils(policy); if (!brokenConnection530Error && !brokenConnectionError) { return ''; @@ -40,7 +40,7 @@ function BrokenConnectionDescription({transactionID, policy, report}: BrokenConn return translate('violations.brokenConnection530Error'); } - if (isPolicyAdmin && !ReportUtils.isCurrentUserSubmitter(report?.reportID)) { + if (isPolicyAdmin && !isCurrentUserSubmitter(report?.reportID)) { return ( <> {`${translate('violations.adminBrokenConnectionError')}`} @@ -53,7 +53,7 @@ function BrokenConnectionDescription({transactionID, policy, report}: BrokenConn ); } - if (ReportUtils.isReportApproved(report) || ReportUtils.isReportManuallyReimbursed(report) || (ReportUtils.isProcessingReport(report) && !PolicyUtils.isInstantSubmitEnabled(policy))) { + if (isReportApproved(report) || isReportManuallyReimbursed(report) || (isProcessingReport(report) && !isInstantSubmitEnabled(policy))) { return translate('violations.memberBrokenConnectionError'); } diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 1654314e576d..38d859def1f7 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -8,7 +8,6 @@ import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getCurrentUserAccountID} from '@libs/actions/Report'; import {convertToDisplayString} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import {getConnectedIntegration, isPolicyAdmin} from '@libs/PolicyUtils'; @@ -30,7 +29,6 @@ import { isClosedExpenseReportWithNoExpenses, isCurrentUserSubmitter, isInvoiceReport, - isOpenExpenseReport, navigateBackOnDeleteTransaction, } from '@libs/ReportUtils'; import { @@ -45,7 +43,17 @@ import { shouldShowBrokenConnectionViolation as shouldShowBrokenConnectionViolationTransactionUtils, } from '@libs/TransactionUtils'; import variables from '@styles/variables'; -import {approveMoneyRequest, canApproveIOU, canIOUBePaid as canIOUBePaidAction, deleteMoneyRequest, deleteTrackExpense, payInvoice, payMoneyRequest, submitReport} from '@userActions/IOU'; +import { + approveMoneyRequest, + canApproveIOU, + canIOUBePaid as canIOUBePaidAction, + canSubmitReport, + deleteMoneyRequest, + deleteTrackExpense, + payInvoice, + payMoneyRequest, + submitReport, +} from '@userActions/IOU'; import {markAsCash as markAsCashAction} from '@userActions/Transaction'; import CONST from '@src/CONST'; import useDelegateUserDetails from '@src/hooks/useDelegateUserDetails'; @@ -134,15 +142,14 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const allTransactions = useMemo(() => getAllReportTransactions(moneyRequestReport?.reportID, transactions), [moneyRequestReport?.reportID, transactions]); const canAllowSettlement = hasUpdatedTotal(moneyRequestReport, policy); const policyType = policy?.type; - const isDraft = isOpenExpenseReport(moneyRequestReport); const connectedIntegration = getConnectedIntegration(policy); const navigateBackToAfterDelete = useRef(); const hasHeldExpenses = hasHeldExpensesReportUtils(moneyRequestReport?.reportID); const hasScanningReceipt = getTransactionsWithReceipts(moneyRequestReport?.reportID).some((t) => isReceiptBeingScanned(t)); const hasOnlyPendingTransactions = allTransactions.length > 0 && allTransactions.every((t) => isExpensifyCardTransaction(t) && isPending(t)); - const transactionIDs = allTransactions.map((t) => t.transactionID); - const hasAllPendingRTERViolations = allHavePendingRTERViolation([transaction?.transactionID]); - const shouldShowBrokenConnectionViolation = shouldShowBrokenConnectionViolationTransactionUtils(transaction?.transactionID, moneyRequestReport, policy); + const transactionIDs = allTransactions.map((t) => t.transactionID) ?? []; + const hasAllPendingRTERViolations = allHavePendingRTERViolation(transactionIDs); + const shouldShowBrokenConnectionViolation = shouldShowBrokenConnectionViolationTransactionUtils(transactionIDs, moneyRequestReport, policy); const hasOnlyHeldExpenses = hasOnlyHeldExpensesReportUtils(moneyRequestReport?.reportID); const isPayAtEndExpense = isPayAtEndExpenseTransactionUtils(transaction); const isArchivedReport = isArchivedReportUtils(moneyRequestReport); @@ -165,22 +172,18 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const shouldDisableApproveButton = shouldShowApproveButton && !isAllowedToApproveExpenseReport(moneyRequestReport); - const currentUserAccountID = getCurrentUserAccountID(); const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN; - const shouldShowSubmitButton = - !!moneyRequestReport && - !isArchivedReport && - isDraft && - reimbursableSpend !== 0 && - !hasAllPendingRTERViolations && - !shouldShowBrokenConnectionViolation && - (moneyRequestReport?.ownerAccountID === currentUserAccountID || isAdmin || moneyRequestReport?.managerID === currentUserAccountID); + const shouldShowSubmitButton = canSubmitReport(moneyRequestReport, policy, transactionIDs); const shouldShowExportIntegrationButton = !shouldShowPayButton && !shouldShowSubmitButton && connectedIntegration && isAdmin && canBeExported(moneyRequestReport); const shouldShowSettlementButton = - (shouldShowPayButton || shouldShowApproveButton) && !hasAllPendingRTERViolations && !shouldShowExportIntegrationButton && !shouldShowBrokenConnectionViolation; + !shouldShowSubmitButton && + (shouldShowPayButton || shouldShowApproveButton) && + !hasAllPendingRTERViolations && + !shouldShowExportIntegrationButton && + !shouldShowBrokenConnectionViolation; const shouldDisableSubmitButton = shouldShowSubmitButton && !isAllowedToSubmitDraftExpenseReport(moneyRequestReport); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; @@ -399,7 +402,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea /> )} - {shouldShowSubmitButton && !shouldUseNarrowLayout && ( + {!!moneyRequestReport && shouldShowSubmitButton && !shouldUseNarrowLayout && (