diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4f78ee6b69bf..e9e4da575b4b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,6 @@ # Every PR gets a review from an internal Expensify engineer * @Expensify/pullerbear + +# Assign the Design team to review changes to our styles & assets +src/styles/ @Expensify/design @Expensify/pullerbear +assets/ @Expensify/design @Expensify/pullerbear diff --git a/.github/workflows/reassurePerformanceTests.yml b/.github/workflows/reassurePerformanceTests.yml index 9887943c77e0..98f876fd60e2 100644 --- a/.github/workflows/reassurePerformanceTests.yml +++ b/.github/workflows/reassurePerformanceTests.yml @@ -1,8 +1,11 @@ name: Reassure Performance Tests on: + push: + branches: [main] + paths-ignore: [docs/**, contributingGuides/**, jest/**, workflow_tests/**] pull_request: - types: [opened, synchronize, closed] + types: [opened, synchronize] branches-ignore: [staging, production] paths-ignore: [docs/**, .github/**, contributingGuides/**, tests/**, workflow_tests/**, '**.md', '**.sh'] diff --git a/android/app/build.gradle b/android/app/build.gradle index 13a6a9d3cc38..c9e5c5a4c15c 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 1001045807 - versionName "1.4.58-7" + versionCode 1001045902 + versionName "1.4.59-2" } flavorDimensions "default" diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.kt b/android/app/src/main/java/com/expensify/chat/MainActivity.kt index 935ba8c8825f..2daebb9b1c00 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.kt +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.kt @@ -14,6 +14,8 @@ import com.facebook.react.ReactActivityDelegate import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate +import com.oblador.performance.RNPerformance + class MainActivity : ReactActivity() { /** * Returns the name of the main component registered from JavaScript. This is used to schedule @@ -82,4 +84,9 @@ class MainActivity : ReactActivity() { KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event) return super.onKeyUp(keyCode, event) } + + override fun onStart() { + super.onStart() + RNPerformance.getInstance().mark("appCreationEnd", false); + } } diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index 2362af009979..e660a871359d 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -15,6 +15,7 @@ import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.modules.i18nmanager.I18nUtil import com.facebook.soloader.SoLoader import com.google.firebase.crashlytics.FirebaseCrashlytics +import com.oblador.performance.RNPerformance import expo.modules.ApplicationLifecycleDispatcher import expo.modules.ReactNativeHostWrapper @@ -42,6 +43,8 @@ class MainApplication : MultiDexApplication(), ReactApplication { override fun onCreate() { super.onCreate() + RNPerformance.getInstance().mark("appCreationStart", false); + if (isOnfidoProcess()) { return } diff --git a/docs/redirects.csv b/docs/redirects.csv index f239d95187c8..9c12c4b0048a 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -67,6 +67,12 @@ https://help.expensify.com/articles/expensify-classic/settings/Merge-Accounts,ht https://help.expensify.com/articles/expensify-classic/settings/Preferences,https://help.expensify.com/expensify-classic/hubs/settings/account-settings https://help.expensify.com/articles/expensify-classic/getting-started/support/Your-Expensify-Account-Manager,https://use.expensify.com/support https://help.expensify.com/articles/expensify-classic/settings/Copilot,https://help.expensify.com/expensify-classic/hubs/copilots-and-delegates/ +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Currency,https://help.expensify.com/articles/expensify-classic/reports/Currency +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Report-Fields-And-Titles,https://help.expensify.com/articles/expensify-classic/workspaces/reports/Report-Fields-And-Titles +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Scheduled-Submit,https://help.expensify.com/articles/expensify-classic/workspaces/reports/Scheduled-Submit +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Categories,https://help.expensify.com/articles/expensify-classic/workspaces/Categori +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Expenses,https://help.expensify.com/expensify-classic/hubs/expenses/ +https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Per-Diem,https://help.expensify.com/articles/expensify-classic/expenses/Per-Diem-Expenses https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Budgets,https://help.expensify.com/articles/expensify-classic/workspaces/Budgets https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Reimbursement,https://help.expensify.com/articles/expensify-classic/send-payments/Reimbursing-Reports https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Tags,https://help.expensify.com/articles/expensify-classic/workspaces/Tags diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 059fe63535b7..1b5bbff8ef99 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.58 + 1.4.59 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.58.7 + 1.4.59.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index c98b0058973d..d19d1c9bd131 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.58 + 1.4.59 CFBundleSignature ???? CFBundleVersion - 1.4.58.7 + 1.4.59.2 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index b8a7167bba64..ac74ce3219a0 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 1.4.58 + 1.4.59 CFBundleVersion - 1.4.58.7 + 1.4.59.2 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b2995c35c9bc..24ef0704be25 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1415,7 +1415,7 @@ PODS: - SDWebImage/Core (~> 5.17) - SocketRocket (0.6.1) - Turf (2.7.0) - - VisionCamera (2.16.8): + - VisionCamera (4.0.0-beta.11): - React - React-callinvoker - React-Core @@ -1920,7 +1920,7 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 - VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a + VisionCamera: b6b6f46949eae83b71429c971162af337ef34fa3 Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 PODFILE CHECKSUM: a431c146e1501391834a2f299a74093bac53b530 diff --git a/package-lock.json b/package-lock.json index eb1d8e0c3aec..095c444cdf91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.59-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.59-2", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -114,7 +114,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "2.16.8", + "react-native-vision-camera": "^4.0.0-beta.11", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", @@ -39769,11 +39769,18 @@ } }, "node_modules/react-native-vision-camera": { - "version": "2.16.8", - "license": "MIT", + "version": "4.0.0-beta.11", + "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.0.0-beta.11.tgz", + "integrity": "sha512-cKg/nwT0q0H1ivEVG+PQt/QxhFgf/dd7SiMm7bCzlSCmt0T2tXyIdLsuY312iKBB2qasQZOYtzRsoQjipHQkDw==", "peerDependencies": { "react": "*", - "react-native": "*" + "react-native": "*", + "react-native-worklets-core": "*" + }, + "peerDependenciesMeta": { + "react-native-worklets-core": { + "optional": true + } } }, "node_modules/react-native-web": { diff --git a/package.json b/package.json index 0b464b3801e0..1b44c77e0a48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.59-2", "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.", @@ -165,7 +165,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "2.16.8", + "react-native-vision-camera": "^4.0.0-beta.11", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", diff --git a/patches/react-native-vision-camera+2.16.8.patch b/patches/react-native-vision-camera+2.16.8.patch deleted file mode 100644 index 3afc4573985d..000000000000 --- a/patches/react-native-vision-camera+2.16.8.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/node_modules/react-native-vision-camera/android/build.gradle b/node_modules/react-native-vision-camera/android/build.gradle -index ddfa243..bafffc3 100644 ---- a/node_modules/react-native-vision-camera/android/build.gradle -+++ b/node_modules/react-native-vision-camera/android/build.gradle -@@ -334,7 +334,7 @@ if (ENABLE_FRAME_PROCESSORS) { - def thirdPartyVersions = new Properties() - thirdPartyVersions.load(new FileInputStream(thirdPartyVersionsFile)) - -- def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] -+ def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] ?: "1.83.0" - def boost_file = new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz") - def DOUBLE_CONVERSION_VERSION = thirdPartyVersions["DOUBLE_CONVERSION_VERSION"] - def double_conversion_file = new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz") -@@ -352,7 +352,7 @@ if (ENABLE_FRAME_PROCESSORS) { - - task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) { - def transformedVersion = BOOST_VERSION.replace("_", ".") -- def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz" -+ def srcUrl = "https://archives.boost.io/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz" - if (REACT_NATIVE_VERSION < 69) { - srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/boost_${BOOST_VERSION}.tar.gz" - } diff --git a/src/CONST.ts b/src/CONST.ts index f4c7ecb5215a..e7358b382f14 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -334,7 +334,6 @@ const CONST = { ALL: 'all', CHRONOS_IN_CASH: 'chronosInCash', DEFAULT_ROOMS: 'defaultRooms', - BETA_COMMENT_LINKING: 'commentLinking', VIOLATIONS: 'violations', REPORT_FIELDS: 'reportFields', TRACK_EXPENSE: 'trackExpense', @@ -1827,6 +1826,8 @@ const CONST = { RECEIPT: 'receipt', DISTANCE: 'distance', TAG: 'tag', + TAX_RATE: 'taxRate', + TAX_AMOUNT: 'taxAmount', }, FOOTER: { EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`, @@ -3335,7 +3336,16 @@ const CONST = { }, /** - * Constants for types of violations. + * Constants for types of violation. + */ + VIOLATION_TYPES: { + VIOLATION: 'violation', + NOTICE: 'notice', + WARNING: 'warning', + }, + + /** + * Constants for types of violation names. * Defined here because they need to be referenced by the type system to generate the * ViolationNames type. */ diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 026025593aef..6a57d6fdcc10 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -26,6 +26,7 @@ import NavigationRoot from './libs/Navigation/NavigationRoot'; import NetworkConnection from './libs/NetworkConnection'; import PushNotification from './libs/Notification/PushNotification'; import './libs/Notification/PushNotification/subscribePushNotification'; +import Performance from './libs/Performance'; import StartupTimer from './libs/StartupTimer'; // This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection import './libs/UnreadIndicatorUpdater'; @@ -130,6 +131,7 @@ function Expensify({ const onSplashHide = useCallback(() => { setIsSplashHidden(true); + Performance.markEnd(CONST.TIMING.SIDEBAR_LOADED); }, []); useLayoutEffect(() => { diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index c134d2a65db2..46b2c5f8055c 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -632,7 +632,7 @@ type OnyxValuesMapping = { [ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields; [ONYXKEYS.UPDATE_REQUIRED]: boolean; [ONYXKEYS.PLAID_CURRENT_EVENT]: string; - [ONYXKEYS.LOGS]: Record; + [ONYXKEYS.LOGS]: OnyxTypes.CapturedLogs; [ONYXKEYS.SHOULD_STORE_LOGS]: boolean; [ONYXKEYS.CACHED_PDF_PATHS]: Record; [ONYXKEYS.POLICY_OWNERSHIP_CHANGE_CHECKS]: Record; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7050360c2e8e..8130c271a2db 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -131,6 +131,16 @@ const ROUTES = { route: 'settings/profile/address/country', getRoute: (country: string, backTo?: string) => getUrlWithBackToParam(`settings/profile/address/country?country=${country}`, backTo), }, + SETTINGS_ADDRESS_STATE: { + route: 'settings/profile/address/state', + + getRoute: (state?: string, backTo?: string, label?: string) => + `${getUrlWithBackToParam(`settings/profile/address/state${state ? `?state=${encodeURIComponent(state)}` : ''}`, backTo)}${ + // the label param can be an empty string so we cannot use a nullish ?? operator + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + label ? `${backTo || state ? '&' : '?'}label=${encodeURIComponent(label)}` : '' + }` as const, + }, SETTINGS_CONTACT_METHODS: { route: 'settings/profile/contact-methods', getRoute: (backTo?: string) => getUrlWithBackToParam('settings/profile/contact-methods', backTo), @@ -401,6 +411,16 @@ const ROUTES = { `create/${iouType}/start/${transactionID}/${reportID}/scan` as const, }, + MONEY_REQUEST_STATE_SELECTOR: { + route: 'request/state', + + getRoute: (state?: string, backTo?: string, label?: string) => + `${getUrlWithBackToParam(`request/state${state ? `?state=${encodeURIComponent(state)}` : ''}`, backTo)}${ + // the label param can be an empty string so we cannot use a nullish ?? operator + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + label ? `${backTo || state ? '&' : '?'}label=${encodeURIComponent(label)}` : '' + }` as const, + }, IOU_REQUEST: 'request/new', IOU_SEND: 'send/new', IOU_SEND_ADD_BANK_ACCOUNT: 'send/new/add-bank-account', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index c732594cdcbe..cf864fd96b3e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -56,6 +56,7 @@ const SCREENS = { DATE_OF_BIRTH: 'Settings_DateOfBirth', ADDRESS: 'Settings_Address', ADDRESS_COUNTRY: 'Settings_Address_Country', + ADDRESS_STATE: 'Settings_Address_State', }, PREFERENCES: { @@ -154,6 +155,7 @@ const SCREENS = { WAYPOINT: 'Money_Request_Waypoint', EDIT_WAYPOINT: 'Money_Request_Edit_Waypoint', RECEIPT: 'Money_Request_Receipt', + STATE_SELECTOR: 'Money_Request_State_Selector', }, IOU_SEND: { diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 626da4cfd5d4..a4d1c2dd6bd6 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -16,7 +16,7 @@ import CountrySelector from './CountrySelector'; import FormProvider from './Form/FormProvider'; import InputWrapper from './Form/InputWrapper'; import type {FormOnyxValues} from './Form/types'; -import StatePicker from './StatePicker'; +import StateSelector from './StateSelector'; import TextInput from './TextInput'; type CountryZipRegex = { @@ -190,7 +190,7 @@ function AddressForm({ {isUSAForm ? ( ; + + /** Whether or not logs should be stored */ + shouldStoreLogs: OnyxEntry; +}; + +type BaseClientSideLoggingToolProps = { + /** Locally created file */ + file?: {path: string; newFileName: string; size: number}; + /** Action to run when pressing Share button */ + onShareLogs?: () => void; + /** Action to run when disabling the switch */ + onDisableLogging: (logs: Log[]) => void; + /** Action to run when enabling logging */ + onEnableLogging?: () => void; +} & BaseClientSideLoggingToolMenuOnyxProps; + +function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onShareLogs, onDisableLogging, onEnableLogging}: BaseClientSideLoggingToolProps) { + const {translate} = useLocalize(); + + const onToggle = () => { + if (!shouldStoreLogs) { + Console.setShouldStoreLogs(true); + + if (onEnableLogging) { + onEnableLogging(); + } + + return; + } + + if (!capturedLogs) { + Alert.alert(translate('initialSettingsPage.troubleshoot.noLogsToShare')); + Console.disableLoggingAndFlushLogs(); + return; + } + + const logs = Object.values(capturedLogs); + const logsWithParsedMessages = parseStringifiedMessages(logs); + + onDisableLogging(logsWithParsedMessages); + Console.disableLoggingAndFlushLogs(); + }; + const styles = useThemeStyles(); + return ( + <> + + + + {!!file && ( + <> + {`path: ${file.path}`} + +