diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 1cb7934cfb91..d84c6df1a0d3 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -12738,6 +12738,10 @@ function promiseWhile(condition, action) { else { const actionResult = action?.(); console.info('[promiseWhile] promiseWhile() actionResult', actionResult); + if (!actionResult) { + resolve(); + return; + } Promise.resolve(actionResult).then(loop).catch(reject); } }; diff --git a/.github/libs/promiseWhile.ts b/.github/libs/promiseWhile.ts index 2fc53c34fec3..01c061096d64 100644 --- a/.github/libs/promiseWhile.ts +++ b/.github/libs/promiseWhile.ts @@ -13,6 +13,12 @@ function promiseWhile(condition: () => boolean, action: (() => Promise) | } else { const actionResult = action?.(); console.info('[promiseWhile] promiseWhile() actionResult', actionResult); + + if (!actionResult) { + resolve(); + return; + } + Promise.resolve(actionResult).then(loop).catch(reject); } }; diff --git a/android/app/build.gradle b/android/app/build.gradle index 1b651bd29def..4b74d51daec8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001046206 - versionName "1.4.62-6" + versionCode 1001046207 + versionName "1.4.62-7" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/assets/images/simple-illustrations/simple-illustration__lightbulb.svg b/assets/images/simple-illustrations/simple-illustration__lightbulb.svg new file mode 100644 index 000000000000..1dc359764147 --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__lightbulb.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-payments/Deposit-Accounts-USD.md new file mode 100644 index 000000000000..0e195d5e3f1c --- /dev/null +++ b/docs/articles/expensify-classic/bank-accounts-and-payments/Deposit-Accounts-USD.md @@ -0,0 +1,77 @@ +--- +title: Deposit Accounts - USD +description: How to add a deposit account to receive payments for yourself or your business (US) +--- +# Overview + +There are two types of deposit-only accounts: + +1. If you're an employee seeking reimbursement for expenses you’ve incurred, you’ll add a **Personal deposit-only bank account**. +2. If you're a vendor seeking payment for goods or services, you’ll add a **Business deposit-only account**. + +# How to connect a personal deposit-only bank account + +**Connect a personal deposit-only bank account if you are:** + +- An employee based in the US who gets reimbursed by their employer +- An employee based in Australia who gets reimbursed by their company via batch payments +- An international (non-US) employee whose US-based employers send international reimbursements + +**To establish the connection to a personal bank account, follow these steps:** + +1. Navigate to your **Settings > Account > Payments** and click the **Add Deposit-Only Bank Account** button. +2. Click **Log into your bank** button and click **Continue** on the Plaid connection pop-up window. +3. Search for your bank account in the list of banks and follow the prompts to sign-in to your bank account. +4. Enter your bank login credentials when prompted. + - If your bank doesn't appear, click the 'x' in the upper right corner of the Plaid pop-up window and click **Connect Manually**. + - Enter your account information, then click **Save & Continue**. + +You should be all set! You’ll receive reimbursement for your expense reports directly to this bank account. + +# How to connect a business deposit-only bank account + +**Connect a business deposit-only bank account if you are:** + +- A US-based vendor who wants to be paid directly for bills sent to customers/clients +- A US-based vendor who wants to pay invoices directly via Expensify + +**To establish the connection to a business bank account, follow these steps:** + +1. Navigate to your **Settings > Account > Payments and click the Add Deposit-Only Bank Account** button. +2. Click **Log into your bank** button and click **Continue** on the Plaid connection pop-up window. +3. Search for your bank account in the list of banks and follow the prompts to sign-in to your bank account. +4. Enter your bank login credentials when prompted. + - If your bank doesn't appear, click the 'x' in the upper right corner of the Plaid pop-up window and click **Connect Manually**. + - Enter your account information, then click **Save & Continue**. +5. If you see the option to “Switch to Business” after entering the account owner information, click that link. +6. Enter your Company Name and FEIN or TIN information. +7. Enter your company’s website formatted as https://www.domain.com. + +You should be all set! The bank account will display as a deposit-only business account, and you’ll be paid directly for any invoices you submit for payment. + +# How to delete a deposit-only bank account + +**To delete a deposit-only bank account, do the following:** + +1. Navigate to **Settings > Account > Payments > Bank Accounts** +2. Click the **Delete** next to the bank account you want to remove + +{% include faq-begin.md %} + +## **What happens if my bank requires an additional security check before adding it to a third-party?** + +If your bank account has 2FA enabled or another security step, you should be prompted to complete this when adding the account. If not, and you encounter an error, you can always select the option to “Connect Manually”. Either way, please double check that you are entering the correct bank account details to ensure successful payments. + +## **What if I also want to pay employees with my business bank account?** + +If you’ve added a business deposit-only account and also wish to also pay employees, vendors, or utilize the Expensify Card with this bank account, select “Verify” on the listed bank account. This will take you through the additional verification steps to use this account to issue payments. + +## **I connected my deposit-only bank account – Why haven’t I received my reimbursement?** + +There are a few reasons a reimbursement may be unsuccessful. The first step is to review the estimated deposit date on the report. If it’s after that date and you still haven’t seen the funds, it could have been unsuccessful because: + - The incorrect account was added. If you believe you may have entered the wrong account, please reach out to Concierge and provide the Report ID for the missing reimbursement. + - Your account wasn’t set up for Direct Deposit/ACH. You may want to contact your bank to confirm. + +If you aren’t sure, please reach out to Concierge and we can assist! + +{% include faq-end.md %} diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index 9d09b4dc04f2..7f50db5da85a 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -626,9 +626,7 @@ "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipAutomationResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipCoreResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipExtendedActionsResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher_Core_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle", @@ -641,9 +639,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipAutomationResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipCoreResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipExtendedActionsResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipMessageCenterResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipPreferenceCenterResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GTMSessionFetcher_Core_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleDataTransport_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", @@ -793,9 +789,7 @@ "${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipAutomationResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipCoreResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipExtendedActionsResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher/GTMSessionFetcher_Core_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle", @@ -808,9 +802,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipAutomationResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipCoreResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipExtendedActionsResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipMessageCenterResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipPreferenceCenterResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GTMSessionFetcher_Core_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleDataTransport_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index f0bb2ace4f4b..da6ad37ca122 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.62.6 + 1.4.62.7 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b8c2140b8546..c2efa1900aec 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.62.6 + 1.4.62.7 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 0d7c6d12f53c..5bb0aa2aaa40 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.62 CFBundleVersion - 1.4.62.6 + 1.4.62.7 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f9244c515a2c..634aeca6465b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,25 +1,24 @@ PODS: - - Airship (16.12.1): - - Airship/Automation (= 16.12.1) - - Airship/Basement (= 16.12.1) - - Airship/Core (= 16.12.1) - - Airship/ExtendedActions (= 16.12.1) - - Airship/MessageCenter (= 16.12.1) - - Airship/Automation (16.12.1): + - Airship (17.7.3): + - Airship/Automation (= 17.7.3) + - Airship/Basement (= 17.7.3) + - Airship/Core (= 17.7.3) + - Airship/FeatureFlags (= 17.7.3) + - Airship/MessageCenter (= 17.7.3) + - Airship/PreferenceCenter (= 17.7.3) + - Airship/Automation (17.7.3): - Airship/Core - - Airship/Basement (16.12.1) - - Airship/Core (16.12.1): + - Airship/Basement (17.7.3) + - Airship/Core (17.7.3): - Airship/Basement - - Airship/ExtendedActions (16.12.1): + - Airship/FeatureFlags (17.7.3): - Airship/Core - - Airship/MessageCenter (16.12.1): + - Airship/MessageCenter (17.7.3): - Airship/Core - - Airship/PreferenceCenter (16.12.1): + - Airship/PreferenceCenter (17.7.3): - Airship/Core - - AirshipFrameworkProxy (2.1.1): - - Airship (= 16.12.1) - - Airship/MessageCenter (= 16.12.1) - - Airship/PreferenceCenter (= 16.12.1) + - AirshipFrameworkProxy (5.1.1): + - Airship (= 17.7.3) - AirshipServiceExtension (17.8.0) - AppAuth (1.6.2): - AppAuth/Core (= 1.6.2) @@ -1162,8 +1161,8 @@ PODS: - React-Mapbuffer (0.73.4): - glog - React-debug - - react-native-airship (15.3.1): - - AirshipFrameworkProxy (= 2.1.1) + - react-native-airship (17.2.1): + - AirshipFrameworkProxy (= 5.1.1) - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -2438,8 +2437,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Airship: 2f4510b497a8200780752a5e0304a9072bfffb6d - AirshipFrameworkProxy: ea1b6c665c798637b93c465b5e505be3011f1d9d + Airship: 5a6d3f8a982398940b0d48423bb9b8736717c123 + AirshipFrameworkProxy: 7255f4ed9836dc2920f2f1ea5657ced4cee8a35c AirshipServiceExtension: 0a5fb14c3fd1879355ab05a81d10f64512a4f79c AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 boost: d3f49c53809116a5d38da093a8aa78bf551aed09 @@ -2508,7 +2507,7 @@ SPEC CHECKSUMS: React-jsitracing: e8a2dafb9878dbcad02b6b2b88e66267fb427b74 React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad - react-native-airship: 2ed75ff2278f11ff1c1ab08ed68f5bf02727b971 + react-native-airship: 6ab7a7974d53f92b0c46548fc198f797fdbf371f react-native-blob-util: a3ee23cfdde79c769c138d505670055de233b07a react-native-cameraroll: 95ce0d1a7d2d1fe55bf627ab806b64de6c3e69e9 react-native-config: 5ce986133b07fc258828b20b9506de0e683efc1c diff --git a/package-lock.json b/package-lock.json index 289880189422..aeec49ce0a7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.62-6", + "version": "1.4.62-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.62-6", + "version": "1.4.62-7", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -47,7 +47,7 @@ "@storybook/cli": "^8.0.6", "@storybook/react": "^8.0.6", "@storybook/theming": "^8.0.6", - "@ua/react-native-airship": "^15.3.1", + "@ua/react-native-airship": "17.2.1", "@vue/preload-webpack-plugin": "^2.0.0", "awesome-phonenumber": "^5.4.0", "babel-polyfill": "^6.26.0", @@ -13336,8 +13336,9 @@ } }, "node_modules/@ua/react-native-airship": { - "version": "15.3.1", - "license": "Apache-2.0", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-17.2.1.tgz", + "integrity": "sha512-+C5fuPU4MMEpN7I5NbrR8F8awPyaHC732ONxMAZhrjVbfNVuZlpCwptz1xmiRkfiH/nzxhF5uvf+CiOKVYamPQ==", "engines": { "node": ">= 16.0.0" }, diff --git a/package.json b/package.json index 9e2846f469d9..b0c96808ea18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.62-6", + "version": "1.4.62-7", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", @@ -98,7 +98,7 @@ "@storybook/cli": "^8.0.6", "@storybook/react": "^8.0.6", "@storybook/theming": "^8.0.6", - "@ua/react-native-airship": "^15.3.1", + "@ua/react-native-airship": "17.2.1", "@vue/preload-webpack-plugin": "^2.0.0", "awesome-phonenumber": "^5.4.0", "babel-polyfill": "^6.26.0", diff --git a/patches/@ua+react-native-airship+15.3.1.patch b/patches/@ua+react-native-airship+15.3.1.patch deleted file mode 100644 index 1ab11c1f7444..000000000000 --- a/patches/@ua+react-native-airship+15.3.1.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/node_modules/@ua/react-native-airship/react-native-airship.podspec b/node_modules/@ua/react-native-airship/react-native-airship.podspec -index 5e0ce2d..4456f61 100644 ---- a/node_modules/@ua/react-native-airship/react-native-airship.podspec -+++ b/node_modules/@ua/react-native-airship/react-native-airship.podspec -@@ -20,18 +20,7 @@ Pod::Spec.new do |s| - - # Don't install the dependencies when we run `pod install` in the old architecture. - if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then -- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" -- s.pod_target_xcconfig = { -- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", -- "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", -- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" -- } -- s.dependency "React-Codegen" -- s.dependency "React-RCTFabric" -- s.dependency "RCT-Folly" -- s.dependency "RCTRequired" -- s.dependency "RCTTypeSafety" -- s.dependency "ReactCommon/turbomodule/core" -+ install_modules_dependencies(s) - end - - diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index 9271c417ac33..b639b2efdd26 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -55,6 +55,7 @@ import HotDogStand from '@assets/images/simple-illustrations/simple-illustration import Hourglass from '@assets/images/simple-illustrations/simple-illustration__hourglass.svg'; import House from '@assets/images/simple-illustrations/simple-illustration__house.svg'; import InvoiceBlue from '@assets/images/simple-illustrations/simple-illustration__invoice.svg'; +import Lightbulb from '@assets/images/simple-illustrations/simple-illustration__lightbulb.svg'; import LockClosed from '@assets/images/simple-illustrations/simple-illustration__lockclosed.svg'; import LockOpen from '@assets/images/simple-illustrations/simple-illustration__lockopen.svg'; import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg'; @@ -172,4 +173,5 @@ export { Pencil, Tag, CarIce, + Lightbulb, }; diff --git a/src/components/Section/index.tsx b/src/components/Section/index.tsx index 93a2e91639a6..848761c9e982 100644 --- a/src/components/Section/index.tsx +++ b/src/components/Section/index.tsx @@ -70,6 +70,9 @@ type SectionProps = ChildrenProps & { /** Overlay content to display on top of animation */ overlayContent?: () => ReactNode; + + /** The component to display in the title of the section */ + renderSubtitle?: () => ReactNode; }; function Section({ @@ -90,6 +93,7 @@ function Section({ illustrationBackgroundColor, illustrationStyle, overlayContent, + renderSubtitle, }: SectionProps) { const styles = useThemeStyles(); const theme = useTheme(); @@ -139,11 +143,15 @@ function Section({ )} - {!!subtitle && ( - - {subtitle} - - )} + {renderSubtitle + ? renderSubtitle?.() + : !!subtitle && ( + + {subtitle} + + )} {children} diff --git a/src/components/SelectionList/InviteMemberListItem.tsx b/src/components/SelectionList/InviteMemberListItem.tsx index 7b6c70373b9e..69774e24b970 100644 --- a/src/components/SelectionList/InviteMemberListItem.tsx +++ b/src/components/SelectionList/InviteMemberListItem.tsx @@ -13,9 +13,9 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import BaseListItem from './BaseListItem'; -import type {InviteMemberListItemProps} from './types'; +import type {InviteMemberListItemProps, ListItem} from './types'; -function InviteMemberListItem({ +function InviteMemberListItem({ item, isFocused, showTooltip, @@ -28,7 +28,7 @@ function InviteMemberListItem({ rightHandSideComponent, onFocus, shouldSyncFocus, -}: InviteMemberListItemProps) { +}: InviteMemberListItemProps) { const styles = useThemeStyles(); const theme = useTheme(); const StyleUtils = useStyleUtils(); diff --git a/src/components/SelectionList/RadioListItem.tsx b/src/components/SelectionList/RadioListItem.tsx index 088d688fdb2d..7ad4819b9690 100644 --- a/src/components/SelectionList/RadioListItem.tsx +++ b/src/components/SelectionList/RadioListItem.tsx @@ -4,9 +4,9 @@ import TextWithTooltip from '@components/TextWithTooltip'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import BaseListItem from './BaseListItem'; -import type {RadioListItemProps} from './types'; +import type {ListItem, RadioListItemProps} from './types'; -function RadioListItem({ +function RadioListItem({ item, isFocused, showTooltip, @@ -18,7 +18,7 @@ function RadioListItem({ isMultilineSupported = false, onFocus, shouldSyncFocus, -}: RadioListItemProps) { +}: RadioListItemProps) { const styles = useThemeStyles(); const fullTitle = isMultilineSupported ? item.text?.trimStart() : item.text; const indentsLength = (item.text?.length ?? 0) - (fullTitle?.length ?? 0); diff --git a/src/components/SelectionList/TableListItem.tsx b/src/components/SelectionList/TableListItem.tsx index 9720d963b2d9..2fc8a0ebfee6 100644 --- a/src/components/SelectionList/TableListItem.tsx +++ b/src/components/SelectionList/TableListItem.tsx @@ -10,9 +10,9 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import BaseListItem from './BaseListItem'; -import type {TableListItemProps} from './types'; +import type {ListItem, TableListItemProps} from './types'; -function TableListItem({ +function TableListItem({ item, isFocused, showTooltip, @@ -25,7 +25,7 @@ function TableListItem({ rightHandSideComponent, onFocus, shouldSyncFocus, -}: TableListItemProps) { +}: TableListItemProps) { const styles = useThemeStyles(); const theme = useTheme(); const StyleUtils = useStyleUtils(); diff --git a/src/components/SelectionList/UserListItem.tsx b/src/components/SelectionList/UserListItem.tsx index a97ac2f26c9a..68349293e134 100644 --- a/src/components/SelectionList/UserListItem.tsx +++ b/src/components/SelectionList/UserListItem.tsx @@ -14,9 +14,9 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import BaseListItem from './BaseListItem'; -import type {UserListItemProps} from './types'; +import type {ListItem, UserListItemProps} from './types'; -function UserListItem({ +function UserListItem({ item, isFocused, showTooltip, @@ -29,7 +29,7 @@ function UserListItem({ rightHandSideComponent, onFocus, shouldSyncFocus, -}: UserListItemProps) { +}: UserListItemProps) { const styles = useThemeStyles(); const theme = useTheme(); const StyleUtils = useStyleUtils(); diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 12f3110f6052..db9feea756a6 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -12,7 +12,7 @@ import type RadioListItem from './RadioListItem'; import type TableListItem from './TableListItem'; import type UserListItem from './UserListItem'; -type CommonListItemProps = { +type CommonListItemProps = { /** Whether this item is focused (for arrow key controls) */ isFocused?: boolean; @@ -122,9 +122,9 @@ type ListItem = { brickRoadIndicator?: BrickRoad | '' | null; }; -type ListItemProps = CommonListItemProps & { +type ListItemProps = CommonListItemProps & { /** The section list item */ - item: ListItem; + item: TItem; /** Additional styles to apply to text */ style?: StyleProp; @@ -152,11 +152,11 @@ type BaseListItemProps = CommonListItemProps & { errors?: Errors | ReceiptErrors | null; pendingAction?: PendingAction | null; FooterComponent?: ReactElement; - children?: ReactElement | ((hovered: boolean) => ReactElement); + children?: ReactElement> | ((hovered: boolean) => ReactElement>); shouldSyncFocus?: boolean; }; -type UserListItemProps = ListItemProps & { +type UserListItemProps = ListItemProps & { /** Errors that this user may contain */ errors?: Errors | ReceiptErrors | null; @@ -167,11 +167,11 @@ type UserListItemProps = ListItemProps & { FooterComponent?: ReactElement; }; -type InviteMemberListItemProps = UserListItemProps; +type InviteMemberListItemProps = UserListItemProps; -type RadioListItemProps = ListItemProps; +type RadioListItemProps = ListItemProps; -type TableListItemProps = ListItemProps; +type TableListItemProps = ListItemProps; type ValidListItem = typeof RadioListItem | typeof UserListItem | typeof TableListItem | typeof InviteMemberListItem; @@ -301,7 +301,7 @@ type BaseSelectionListProps = Partial & { shouldDelayFocus?: boolean; /** Component to display on the right side of each child */ - rightHandSideComponent?: ((item: ListItem) => ReactElement | null) | ReactElement | null; + rightHandSideComponent?: ((item: TItem) => ReactElement | null) | ReactElement | null; /** Whether to show the loading indicator for new options */ isLoadingNewOptions?: boolean; diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 527b92d4d7dc..5efa9592034f 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -1,6 +1,7 @@ import React from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ApiUtils from '@libs/ApiUtils'; import compose from '@libs/compose'; @@ -32,6 +33,7 @@ const USER_DEFAULT: UserOnyx = {shouldUseStagingServer: undefined, isSubscribedT function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { const shouldUseStagingServer = user?.shouldUseStagingServer ?? ApiUtils.isUsingStagingApi(); const styles = useThemeStyles(); + const {translate} = useLocalize(); return ( <> @@ -39,13 +41,13 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { style={[styles.textLabelSupporting, styles.mb4]} numberOfLines={1} > - Test Preferences + {translate('initialSettingsPage.troubleshoot.testingPreferences')} {/* Option to switch between staging and default api endpoints. This enables QA, internal testers and external devs to take advantage of sandbox environments for 3rd party services like Plaid and Onfido. This toggle is not rendered for internal devs as they make environment changes directly to the .env file. */} {!CONFIG.IS_USING_LOCAL_WEB && ( - + + {/* When toggled all network requests will fail. */} - + {/* Instantly invalidates a user's local authToken. Useful for testing flows related to reauthentication. */} - +